@zhama/tego-plugin-sdk 0.0.0-stage → 1.36.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.
Files changed (98) hide show
  1. package/LICENSE +172 -0
  2. package/README.md +846 -2
  3. package/access-catalog.schema.json +304 -0
  4. package/access-fixtures/resolve.json +1359 -0
  5. package/bin/tego-plugin-pack.mjs +2 -0
  6. package/bin/tego-plugin.mjs +3 -0
  7. package/dist/access-drizzle.cjs +1 -0
  8. package/dist/access-drizzle.d.cts +726 -0
  9. package/dist/access-drizzle.d.ts +726 -0
  10. package/dist/access-drizzle.js +1 -0
  11. package/dist/access-hono.cjs +3 -0
  12. package/dist/access-hono.d.cts +108 -0
  13. package/dist/access-hono.d.ts +108 -0
  14. package/dist/access-hono.js +3 -0
  15. package/dist/access-implications.cjs +1 -0
  16. package/dist/access-implications.d.cts +25 -0
  17. package/dist/access-implications.d.ts +25 -0
  18. package/dist/access-implications.js +1 -0
  19. package/dist/access.cjs +26 -0
  20. package/dist/access.d.cts +884 -0
  21. package/dist/access.d.ts +884 -0
  22. package/dist/access.js +26 -0
  23. package/dist/catalog-CSSbrfEf.d.cts +361 -0
  24. package/dist/catalog-CSSbrfEf.d.ts +361 -0
  25. package/dist/chunk-3KUOBGJN.js +19 -0
  26. package/dist/chunk-3WA3M347.cjs +1 -0
  27. package/dist/chunk-5CU33JVY.js +1 -0
  28. package/dist/chunk-7K37PVGV.js +5 -0
  29. package/dist/chunk-7XHF3YSK.js +1 -0
  30. package/dist/chunk-AJY7ZHXK.cjs +3 -0
  31. package/dist/chunk-BN6TGHSB.cjs +1 -0
  32. package/dist/chunk-BTHXQWHT.js +1 -0
  33. package/dist/chunk-C2OCOPZQ.cjs +1 -0
  34. package/dist/chunk-IMAVYQ4U.cjs +4 -0
  35. package/dist/chunk-OP64Y4IN.cjs +1 -0
  36. package/dist/chunk-QKSPPMVN.js +1 -0
  37. package/dist/chunk-ROFUQLOZ.cjs +1 -0
  38. package/dist/chunk-SNUCO2MK.js +1 -0
  39. package/dist/chunk-THMWRUAT.cjs +19 -0
  40. package/dist/chunk-VMCGDDGP.js +3 -0
  41. package/dist/chunk-W7C357A6.cjs +5 -0
  42. package/dist/chunk-WLTASJF6.js +4 -0
  43. package/dist/egress.cjs +7 -0
  44. package/dist/egress.d.cts +9 -0
  45. package/dist/egress.d.ts +9 -0
  46. package/dist/egress.js +7 -0
  47. package/dist/frontend.cjs +2 -0
  48. package/dist/frontend.d.cts +353 -0
  49. package/dist/frontend.d.ts +353 -0
  50. package/dist/frontend.js +2 -0
  51. package/dist/gateway-signature.cjs +1 -0
  52. package/dist/gateway-signature.d.cts +112 -0
  53. package/dist/gateway-signature.d.ts +112 -0
  54. package/dist/gateway-signature.js +1 -0
  55. package/dist/index.cjs +1 -0
  56. package/dist/index.d.cts +528 -0
  57. package/dist/index.d.ts +528 -0
  58. package/dist/index.js +1 -0
  59. package/dist/manifest-types-DQARCQJt.d.cts +627 -0
  60. package/dist/manifest-types-DQARCQJt.d.ts +627 -0
  61. package/dist/manifest.cjs +1 -0
  62. package/dist/manifest.d.cts +2824 -0
  63. package/dist/manifest.d.ts +2824 -0
  64. package/dist/manifest.js +1 -0
  65. package/dist/mcp-identity.cjs +2 -0
  66. package/dist/mcp-identity.d.cts +106 -0
  67. package/dist/mcp-identity.d.ts +106 -0
  68. package/dist/mcp-identity.js +2 -0
  69. package/dist/pack.cjs +1 -0
  70. package/dist/pack.d.cts +169 -0
  71. package/dist/pack.d.ts +169 -0
  72. package/dist/pack.js +1 -0
  73. package/dist/publish.cjs +1 -0
  74. package/dist/publish.d.cts +96 -0
  75. package/dist/publish.d.ts +96 -0
  76. package/dist/publish.js +1 -0
  77. package/dist/scaffold.cjs +523 -0
  78. package/dist/scaffold.d.cts +182 -0
  79. package/dist/scaffold.d.ts +182 -0
  80. package/dist/scaffold.js +523 -0
  81. package/dist/server-runtime.cjs +1 -0
  82. package/dist/server-runtime.d.cts +63 -0
  83. package/dist/server-runtime.d.ts +63 -0
  84. package/dist/server-runtime.js +1 -0
  85. package/dist/server.cjs +1 -0
  86. package/dist/server.d.cts +1808 -0
  87. package/dist/server.d.ts +1808 -0
  88. package/dist/server.js +1 -0
  89. package/dist/testing.cjs +2 -0
  90. package/dist/testing.d.cts +92 -0
  91. package/dist/testing.d.ts +92 -0
  92. package/dist/testing.js +2 -0
  93. package/dist/vite.cjs +1 -0
  94. package/dist/vite.d.cts +133 -0
  95. package/dist/vite.d.ts +133 -0
  96. package/dist/vite.js +1 -0
  97. package/package.json +160 -4
  98. package/sql/access.sql +73 -0
@@ -0,0 +1,627 @@
1
+ /**
2
+ * Operator-supplied configuration, declared per part.
3
+ *
4
+ * Three sections, never one. A plugin's browser code, its backend process and
5
+ * its claw extension are three different audiences, and folding their settings
6
+ * into a single object makes "does the frontend get to see this API key" a
7
+ * question answered by remembering to strip a field before responding. Split,
8
+ * the frontend simply has no path to the other two.
9
+ *
10
+ * The frontend and backend sections are declared here, in `tego.plugin.json`.
11
+ * The claw section is not: `claw/openclaw.plugin.json` already carries a
12
+ * `configSchema`, claw itself validates against it, and a second declaration
13
+ * would be a second truth about the same fields.
14
+ *
15
+ * ## Why the schema subset is this narrow
16
+ *
17
+ * A flat object of scalars, string enums and string arrays. Two reasons, and
18
+ * the second is the load-bearing one:
19
+ *
20
+ * - The form has to render without an author previewing it. Anything the
21
+ * renderer would fall back to a JSON textarea for is a field the operator
22
+ * fills by typing JSON, which is not a form.
23
+ * - Per-avatar claw overrides merge at top-level key granularity, on purpose:
24
+ * deep-merging nested objects and arrays has no single obvious semantics.
25
+ * A nested object would therefore be replaced wholesale by an override,
26
+ * which is not what its shape suggests. Refusing nesting keeps the storage
27
+ * model and the declaration honest with each other.
28
+ */
29
+
30
+ /** The three audiences a plugin's settings can belong to. */
31
+ declare const PLUGIN_CONFIG_SECTIONS: readonly ["frontend", "backend", "claw"];
32
+ type PluginConfigSection = (typeof PLUGIN_CONFIG_SECTIONS)[number];
33
+ /**
34
+ * Stands in for a stored secret whenever a value leaves the server towards a
35
+ * human.
36
+ *
37
+ * The same string claw uses, deliberately: a secret that survived a round trip
38
+ * through one console and got clobbered by the other would be the worst
39
+ * possible outcome of having two sentinels. Writing it back means "leave the
40
+ * stored value alone".
41
+ */
42
+ declare const PLUGIN_CONFIG_SECRET_SENTINEL = "__OPENCLAW_REDACTED__";
43
+ type PluginConfigFieldType = 'string' | 'number' | 'integer' | 'boolean' | 'array';
44
+ /** One field. Flat by construction — no `properties`, no `$ref`, no unions. */
45
+ interface PluginConfigFieldSchema {
46
+ type: PluginConfigFieldType;
47
+ title?: string;
48
+ description?: string;
49
+ default?: unknown;
50
+ /** Closed set of allowed values. Strings and numbers only. */
51
+ enum?: (string | number)[];
52
+ minLength?: number;
53
+ maxLength?: number;
54
+ pattern?: string;
55
+ format?: 'uri' | 'email';
56
+ minimum?: number;
57
+ maximum?: number;
58
+ /** Required for `type: "array"`, and only a string element is supported. */
59
+ items?: {
60
+ type: 'string';
61
+ enum?: string[];
62
+ };
63
+ maxItems?: number;
64
+ }
65
+ interface PluginConfigSchema {
66
+ type: 'object';
67
+ properties: Record<string, PluginConfigFieldSchema>;
68
+ required?: string[];
69
+ /** Always false: an operator cannot invent a key the plugin never reads. */
70
+ additionalProperties?: false;
71
+ }
72
+ /**
73
+ * How one field is presented.
74
+ *
75
+ * `label` and `help` are {@link LocalizedText} because the platform ships ten
76
+ * languages and a plugin's settings screen has no reason to be the one part of
77
+ * it that is English-only. A plain string still works and means "the same in
78
+ * every language", which is right for a field named after a protocol.
79
+ */
80
+ interface PluginConfigUiHint {
81
+ label?: LocalizedText;
82
+ help?: LocalizedText;
83
+ placeholder?: LocalizedText;
84
+ order?: number;
85
+ /** Collapsed by default. For knobs with a sane default nobody should touch. */
86
+ advanced?: boolean;
87
+ /**
88
+ * Stored encrypted, never returned in plaintext, never placed in the
89
+ * container environment.
90
+ *
91
+ * Illegal in the frontend section: that section is delivered to the browser
92
+ * in full, so a secret there is public by construction. Validation rejects
93
+ * it rather than quietly stripping the flag.
94
+ */
95
+ sensitive?: boolean;
96
+ }
97
+ interface PluginConfigDeclaration {
98
+ schema: PluginConfigSchema;
99
+ uiHints?: Record<string, PluginConfigUiHint>;
100
+ }
101
+ /** What the install screen says about one section, without opening a schema. */
102
+ interface PluginConfigSectionSummary {
103
+ fieldCount: number;
104
+ /** Property names the section cannot run without. */
105
+ required: string[];
106
+ /** Property names stored encrypted. */
107
+ sensitive: string[];
108
+ }
109
+ declare const EMPTY_CONFIG_SECTION_SUMMARY: PluginConfigSectionSummary;
110
+ declare function summarizeConfigDeclaration(declaration: PluginConfigDeclaration | undefined): PluginConfigSectionSummary;
111
+ /**
112
+ * The same summary for the claw section, read out of an OpenClaw manifest.
113
+ *
114
+ * Separate because that schema is not held to the subset above — claw owns it,
115
+ * and holding an already-valid OpenClaw extension to a Tego-only restriction
116
+ * would refuse packages claw itself runs. Anything nested is counted at the
117
+ * top level and rendered by the form's own fallback.
118
+ */
119
+ declare function summarizeClawConfig(clawManifest: Record<string, unknown> | null): PluginConfigSectionSummary;
120
+ /**
121
+ * Replace every stored secret with the sentinel.
122
+ *
123
+ * Applied on the way out to any human-facing surface. Keys absent from the
124
+ * stored value stay absent — writing a sentinel for a secret nobody has set
125
+ * would make the form show a filled field the operator cannot clear.
126
+ */
127
+ declare function redactSecrets(value: Record<string, unknown>, sensitive: readonly string[]): Record<string, unknown>;
128
+ /**
129
+ * Put the stored secret back wherever the submitted value is the sentinel.
130
+ *
131
+ * The inverse of {@link redactSecrets}, and the reason a form can be saved
132
+ * without the operator retyping every key it never showed them.
133
+ *
134
+ * A sentinel with no stored counterpart is dropped rather than saved
135
+ * literally: it means the form rendered a value that has since been deleted,
136
+ * and persisting the marker itself would give the plugin a password of
137
+ * `__OPENCLAW_REDACTED__`.
138
+ */
139
+ declare function restoreSecrets(submitted: Record<string, unknown>, stored: Record<string, unknown>, sensitive: readonly string[]): Record<string, unknown>;
140
+ /**
141
+ * Fill in declared defaults for keys the operator left unset.
142
+ *
143
+ * `properties` is defaulted although the type requires it: the claw section's
144
+ * schema is whatever an OpenClaw manifest declares, which this type describes
145
+ * but does not enforce, and a schema of `{"type":"object"}` would otherwise
146
+ * throw here rather than simply having no defaults to apply.
147
+ */
148
+ declare function applyConfigDefaults(schema: PluginConfigSchema, value: Record<string, unknown>): Record<string, unknown>;
149
+ /** A hint's label in one language, falling back to the property name. */
150
+ declare function configFieldLabel(name: string, hint: PluginConfigUiHint | undefined, field: PluginConfigFieldSchema | undefined, locale: string): string;
151
+
152
+ /**
153
+ * `tego.plugin.json` — the one manifest every Tego plugin ships.
154
+ *
155
+ * A plugin is a single archive containing up to three parts: a frontend module
156
+ * loaded into the host shell, a backend process the platform runs, and an
157
+ * OpenClaw extension loaded by claw containers. At least one part is required;
158
+ * a plugin with only `claw` is exactly what the ecosystem uploads today.
159
+ *
160
+ * The claw part keeps its own upstream `openclaw.plugin.json` untouched inside
161
+ * its subdirectory. This manifest wraps it rather than replacing it, so claw's
162
+ * loader and this platform never have to agree on a schema.
163
+ */
164
+
165
+ /** A display string, either a single value or one per locale tag. */
166
+ type LocalizedText = string | Record<string, string>;
167
+ /**
168
+ * Icon names a nav entry may choose from.
169
+ *
170
+ * A closed list rather than "any `lucide-react` name", because resolving an
171
+ * arbitrary string to a component means importing the whole icon set into the
172
+ * shell — which is why every plugin entry used to render the same generic
173
+ * puzzle piece. A fixed list is a static map the bundler can shake.
174
+ *
175
+ * Adding a name is a minor host API bump: older shells would render the
176
+ * fallback for an icon they have no entry for.
177
+ */
178
+ declare const PLUGIN_NAV_ICONS: readonly ["bar-chart", "bell", "bookmark", "book-open", "bot", "briefcase", "building", "calendar", "chart-pie", "clipboard-list", "clock", "contact", "credit-card", "database", "file-text", "folder", "globe", "handshake", "inbox", "key", "layers", "layout-dashboard", "library", "link", "list-todo", "mail", "map-pin", "message-square", "mic", "package", "phone", "puzzle", "receipt", "search", "settings", "shield", "shopping-cart", "sliders", "sparkles", "star", "table", "tag", "target", "trending-up", "truck", "users", "wallet", "workflow", "wrench", "zap"];
179
+ type PluginNavIcon = (typeof PLUGIN_NAV_ICONS)[number];
180
+ /** Rendered for an entry that names no icon. */
181
+ declare const PLUGIN_NAV_ICON_FALLBACK: PluginNavIcon;
182
+ /**
183
+ * One page a frontend part registers.
184
+ *
185
+ * These are not sidebar rows. The shell gives a plugin exactly one row —
186
+ * itself — which opens the plugin at its root; the plugin routes its pages
187
+ * from there. A plugin with at least one entry gets that row.
188
+ *
189
+ * Entries do not gate access. Who may open a plugin follows the AI employees
190
+ * it is installed on (tenant-scoped plugins are open to the whole tenant),
191
+ * and the host writes no role menu or permission for them.
192
+ */
193
+ interface PluginNavEntry {
194
+ /** Stable identifier within the plugin; what `ctx.can(key)` checks. */
195
+ key: string;
196
+ /** i18n key resolved against the plugin's own bundle, not the host's. */
197
+ labelKey: string;
198
+ /**
199
+ * Kept for manifest compatibility; the host does not read it. The sidebar
200
+ * row's icon is the frontend part's own `icon`.
201
+ */
202
+ icon?: PluginNavIcon;
203
+ /** Kept for manifest compatibility; the host does not read it. */
204
+ order?: number;
205
+ /** Subpath under `/p/<pluginId>`. Defaults to the plugin root. */
206
+ path?: string;
207
+ }
208
+ interface PluginFrontendPart {
209
+ /** Directory inside the archive. Defaults to `frontend`. */
210
+ dir?: string;
211
+ /** SystemJS entry relative to `dir`. Defaults to `index.js`. */
212
+ entry?: string;
213
+ /** Locale JSON directory relative to `dir`. Defaults to `i18n`. */
214
+ i18nDir?: string;
215
+ /**
216
+ * The plugin's icon in the shell's sidebar. Defaults to the generic plugin
217
+ * icon.
218
+ *
219
+ * Declared here and not taken from `nav`, because the row stands for the
220
+ * plugin rather than for any one of its pages: borrowing the first page's
221
+ * icon would put a dashboard glyph next to "CRM" only because the author
222
+ * happened to list the dashboard first.
223
+ */
224
+ icon?: PluginNavIcon;
225
+ nav?: PluginNavEntry[];
226
+ /**
227
+ * Settings delivered to the browser alongside discovery.
228
+ *
229
+ * Public by construction — anything here reaches the page — so a
230
+ * `sensitive` hint in this section is a validation error rather than a
231
+ * field that gets quietly stripped.
232
+ */
233
+ config?: PluginConfigDeclaration;
234
+ }
235
+ /**
236
+ * Resource caps for the backend process.
237
+ *
238
+ * Only what the orchestrator actually applies. Egress controls used to be
239
+ * declarable here and were enforced nowhere — a field that reads as a network
240
+ * policy while every host stays reachable is worse than no field, because it
241
+ * is the one an operator would rely on.
242
+ */
243
+ interface PluginBackendLimits {
244
+ memoryMb?: number;
245
+ cpuMs?: number;
246
+ requestTimeoutMs?: number;
247
+ }
248
+ /**
249
+ * Language runtime of the backend process.
250
+ *
251
+ * Each value maps to one platform-owned runner image; a package never ships
252
+ * its own. See `docs/architecture/plugin-backend-protocol.md`.
253
+ */
254
+ type PluginBackendRuntime = 'node' | 'python';
255
+ declare const PLUGIN_BACKEND_RUNTIMES: readonly PluginBackendRuntime[];
256
+ type PluginBackendPlatform = 'linux/amd64' | 'linux/arm64';
257
+ declare const PLUGIN_BACKEND_PLATFORMS: readonly PluginBackendPlatform[];
258
+ type PluginPublicRouteMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
259
+ /**
260
+ * One anonymous entry point into the backend.
261
+ *
262
+ * `path` is literal segments and `:name` parameters, e.g.
263
+ * `/public/inspections/:token`. The gateway forwards only requests that match
264
+ * a declaration; everything else under the public prefix is a 404 that never
265
+ * reaches the plugin.
266
+ */
267
+ interface PluginPublicRoute {
268
+ method: PluginPublicRouteMethod;
269
+ path: string;
270
+ }
271
+ interface PluginSchemaRepair {
272
+ id: string;
273
+ /** SQL generated from an isolated legacy schema, relative to backend dir. */
274
+ sqlFile: string;
275
+ table: string;
276
+ column: string;
277
+ postgresType: 'integer' | 'text' | 'boolean' | 'bigint' | 'jsonb';
278
+ }
279
+ interface PluginBackendPart {
280
+ /** Directory inside the archive. Defaults to `backend`. */
281
+ dir?: string;
282
+ /** Defaults to `node`. */
283
+ runtime?: PluginBackendRuntime;
284
+ /**
285
+ * Entry relative to `dir`. Defaults to `index.js` for node and `app.py` for
286
+ * python.
287
+ */
288
+ entry?: string;
289
+ /**
290
+ * CPU architectures the package's vendored wheels cover. Python only, and
291
+ * defaults to both: a release that installs on one node pool and not the
292
+ * other fails at the worst possible moment.
293
+ */
294
+ platforms?: PluginBackendPlatform[];
295
+ /**
296
+ * Exact outbound targets. A bare hostname means HTTPS 443; hostname:port
297
+ * and IP:port permit that specific port through the platform egress proxy.
298
+ * A lone `*` permits every routable target and port, including private IPs.
299
+ */
300
+ egress?: string[];
301
+ /**
302
+ * Append-only SQL directory relative to `dir`, applied by the host into the
303
+ * plugin's dedicated schema. Defaults to `migrations`.
304
+ */
305
+ migrationsDir?: string;
306
+ compatibilityRepairs?: PluginSchemaRepair[];
307
+ /** Readiness path the runtime polls. Defaults to `/healthz`. */
308
+ healthPath?: string;
309
+ limits?: PluginBackendLimits;
310
+ /**
311
+ * Routes anyone may call without signing in — a QR code scanned on a
312
+ * phone, a link sent to a contractor. Avatar plugins require a bound and
313
+ * enabled employee in the public URL (or an existing legacy target).
314
+ * Each request carries a signed anonymous context; the plugin verifies its token.
315
+ */
316
+ publicRoutes?: PluginPublicRoute[];
317
+ /**
318
+ * Settings the backend process reads at startup.
319
+ *
320
+ * Fetched over the host API rather than injected as environment variables:
321
+ * env is visible to `docker inspect`, to the orchestrator's API and to crash
322
+ * dumps, and it is fixed at container creation, so rotating a key would mean
323
+ * recreating the container.
324
+ *
325
+ * A required field with no value leaves the install in `awaiting_config` —
326
+ * installed, no container, and an explanation instead of a 502.
327
+ */
328
+ config?: PluginConfigDeclaration;
329
+ }
330
+ interface PluginClawHooks {
331
+ allowPromptInjection?: boolean;
332
+ allowConversationAccess?: boolean;
333
+ }
334
+ interface PluginClawPart {
335
+ /** Runtime hook access disclosed by the installed package. */
336
+ hooks?: PluginClawHooks;
337
+ /** Directory inside the archive holding an intact OpenClaw extension. */
338
+ dir?: string;
339
+ }
340
+ /**
341
+ * A static site served to anonymous visitors — the pages behind
342
+ * `publicRoutes`. Built with its own dependencies, not against the host's
343
+ * shared modules: nobody signed in means no shell to load into.
344
+ */
345
+ interface PluginPublicFrontendPart {
346
+ /** Directory inside the archive holding `index.html`. Defaults to `public-frontend`. */
347
+ dir?: string;
348
+ }
349
+ interface PluginParts {
350
+ frontend?: PluginFrontendPart;
351
+ backend?: PluginBackendPart;
352
+ claw?: PluginClawPart;
353
+ publicFrontend?: PluginPublicFrontendPart;
354
+ }
355
+ interface PluginPermissions {
356
+ required?: string[];
357
+ }
358
+ /**
359
+ * The plugin's own roles and permissions, enforced by its backend through
360
+ * `@tego/plugin-sdk/access`.
361
+ *
362
+ * `catalog` is a path inside the package, so the same file the backend is
363
+ * built from is the one upload validates and discloses. Accounts still come
364
+ * from the host; the catalog only says what they may do inside this plugin.
365
+ */
366
+ interface PluginAccess {
367
+ catalog: string;
368
+ }
369
+ /**
370
+ * Who a plugin belongs to once installed.
371
+ *
372
+ * `avatar` — the plugin is a capability of a digital avatar. Install picks
373
+ * which avatars get it, and its pages are visible while one of those is
374
+ * active.
375
+ *
376
+ * `tenant` — a workspace-wide application with no per-avatar meaning. Visible
377
+ * to everyone in the tenant who holds the menu permission. A claw part on a
378
+ * tenant-scoped plugin goes to every avatar in the tenant, including avatars
379
+ * created later: nobody picks avatars, so nobody can forget the new ones.
380
+ *
381
+ * Declared, never inferred. "Has a claw part" happens to correlate today, but
382
+ * a frontend-only reporting page over the same backend is tenant-scoped, and
383
+ * guessing wrong means the plugin is either invisible or visible to everyone.
384
+ */
385
+ type PluginScope = 'avatar' | 'tenant';
386
+ /**
387
+ * What installing this plugin will bring, shown to the operator before they
388
+ * confirm.
389
+ *
390
+ * These are **disclosures**, not grants. Plugins are first-party and the
391
+ * frontend runs with the shell's own privileges, so calling them permissions
392
+ * would promise an isolation boundary that does not exist. `database` is the
393
+ * exception that also changes behaviour, because provisioning a schema is a
394
+ * thing the host does or does not do.
395
+ */
396
+ interface PluginDeclares {
397
+ /**
398
+ * The backend gets a dedicated Postgres schema and a role scoped to it, and
399
+ * the host applies the package's migrations into it.
400
+ *
401
+ * Defaults to true when a backend part exists, which is what the platform
402
+ * has always done. A backend that only proxies or computes sets it false and
403
+ * then finds `host.db` unavailable.
404
+ */
405
+ database?: boolean;
406
+ /**
407
+ * The backend stores objects through the host storage API, under a prefix
408
+ * derived from the install.
409
+ *
410
+ * A byte budget is deliberately not declarable: nothing accounts total usage
411
+ * yet, and a number no one enforces reads as a cap. The per-object ceiling
412
+ * the host does enforce is a platform constant, not a plugin's choice.
413
+ */
414
+ storage?: boolean;
415
+ /**
416
+ * The backend publishes `plugin.<id>.*` events to the tenant's subscribers.
417
+ *
418
+ * Publish-only. Plugin backends cannot subscribe to platform events.
419
+ */
420
+ events?: boolean;
421
+ /** The backend may send durable, recipient-scoped messages to the host inbox. */
422
+ notifications?: boolean;
423
+ }
424
+ /**
425
+ * Business wording for a plugin tool in the audit trail. Without it an auditor
426
+ * sees `crm_query_customer {"id":"C123"}`; with it, "查询客户 C123 的持仓".
427
+ */
428
+ interface PluginAuditToolDeclaration {
429
+ category?: 'read' | 'write' | 'search' | 'browse' | 'exec' | 'knowledge' | 'memory' | 'message' | 'schedule' | 'delegate' | 'document' | 'plugin';
430
+ /** Template with `{param}` placeholders filled from the call parameters. */
431
+ title?: LocalizedText;
432
+ /** Parameter naming the business object, e.g. `customerId`. */
433
+ target?: string;
434
+ /** `high` raises a risk flag on every call. */
435
+ risk?: 'low' | 'medium' | 'high';
436
+ /** Data classes touched, e.g. `pii`, `account`, `trade`. */
437
+ dataClasses?: string[];
438
+ }
439
+ interface PluginAuditDeclarations {
440
+ /** Keyed by the tool name the claw part registers. */
441
+ tools?: Record<string, PluginAuditToolDeclaration>;
442
+ }
443
+ interface PluginAgentReadinessDeclaration {
444
+ /** Backend route path (relative to plugin root) returning PluginAgentReadinessResponse. */
445
+ path: string;
446
+ }
447
+ /**
448
+ * Text fields are `LocalizedText`: the host picks the viewer's locale, then
449
+ * `en`. `action.route` is relative to the plugin's own pages (`/deals`), never
450
+ * an absolute URL.
451
+ */
452
+ interface PluginAgentReadinessItem {
453
+ id: string;
454
+ title: LocalizedText;
455
+ why?: LocalizedText | undefined;
456
+ status: 'ready' | 'action_needed' | 'not_applicable' | 'unknown';
457
+ owner: 'self' | 'other';
458
+ ownerHint?: LocalizedText | undefined;
459
+ optional?: boolean | undefined;
460
+ action?: {
461
+ label: LocalizedText;
462
+ route: string;
463
+ } | undefined;
464
+ }
465
+ interface PluginAgentReadinessResponse {
466
+ items: PluginAgentReadinessItem[];
467
+ }
468
+ interface PluginWorkDelegationDeclaration {
469
+ allowedAvatarRoles: string[];
470
+ /**
471
+ * @deprecated Host API 1.33 grants and revokes in its own dialog. Still
472
+ * accepted so older manifests validate; the host no longer links to it.
473
+ */
474
+ settingsRoute?: string;
475
+ /** Host API 1.33: one sentence in the consent dialog, at most 120 characters. */
476
+ summary?: LocalizedText;
477
+ /** Host API 1.33: https link shown in the consent dialog. */
478
+ privacyPolicyUrl?: string;
479
+ /**
480
+ * Host API 1.33: the consent dialog offers, unchecked, to also record the
481
+ * person's new conversations with the employee for this plugin.
482
+ */
483
+ conversationCapture?: boolean;
484
+ }
485
+ interface TegoPluginManifest {
486
+ /** Bumped only when this manifest's own shape breaks. */
487
+ manifestVersion: 1;
488
+ /**
489
+ * Flat identifier. Doubles as a directory name under claw's `extensions/`
490
+ * and as an `openclaw.json` object key, so scoped npm-style ids are refused.
491
+ */
492
+ id: string;
493
+ version: string;
494
+ displayName: LocalizedText;
495
+ description?: LocalizedText;
496
+ author?: string;
497
+ homepage?: string;
498
+ /** Icon path inside the archive. */
499
+ icon?: string;
500
+ category?: string;
501
+ tags?: string[];
502
+ /**
503
+ * Caret range of the host API this plugin was built against, e.g. `^1.2.0`.
504
+ * Required once a frontend or backend part exists, because both bind to host
505
+ * modules; a claw-only plugin is governed by claw's own `minHostVersion`.
506
+ */
507
+ hostApiRange?: string;
508
+ scope: PluginScope;
509
+ declares?: PluginDeclares;
510
+ parts: PluginParts;
511
+ permissions?: PluginPermissions;
512
+ /** Host API 1.22: plugin-owned roles and permissions. */
513
+ access?: PluginAccess;
514
+ /** How this plugin's tools read in the audit trail. */
515
+ audit?: PluginAuditDeclarations;
516
+ /** Employee templates shipped as immutable assets in this plugin release. */
517
+ agentTemplates?: {
518
+ key: string;
519
+ entry: string;
520
+ icon?: string;
521
+ }[];
522
+ /**
523
+ * Host-enforced eligibility for work delegation. Omit to disable; `*` allows any role.
524
+ * Requires a backend part. The host owns the consent dialog and the grant
525
+ * and revoke entries, so a plugin builds no delegation UI of its own.
526
+ */
527
+ workDelegation?: PluginWorkDelegationDeclaration;
528
+ /** Read-only record routes used by the generic conversation binding API. */
529
+ conversationRecordRoutes?: {
530
+ entity: string;
531
+ path: string;
532
+ contextQuery?: string;
533
+ labelFields?: string[];
534
+ }[];
535
+ /** Per-user business readiness endpoint for digital employees using this plugin. */
536
+ agentReadiness?: PluginAgentReadinessDeclaration;
537
+ }
538
+ declare const PLUGIN_MANIFEST_FILENAME = "tego.plugin.json";
539
+ /** Mirrors OpenClaw's own manifest filename, found inside the claw part. */
540
+ declare const CLAW_MANIFEST_FILENAME = "openclaw.plugin.json";
541
+ declare const PLUGIN_PART_DEFAULTS: {
542
+ readonly frontend: {
543
+ readonly dir: "frontend";
544
+ readonly entry: "index.js";
545
+ readonly i18nDir: "i18n";
546
+ };
547
+ readonly backend: {
548
+ readonly dir: "backend";
549
+ readonly runtime: "node";
550
+ readonly entry: {
551
+ readonly node: "index.js";
552
+ readonly python: "app.py";
553
+ };
554
+ readonly migrationsDir: "migrations";
555
+ readonly healthPath: "/healthz";
556
+ };
557
+ readonly claw: {
558
+ readonly dir: "claw";
559
+ };
560
+ readonly publicFrontend: {
561
+ readonly dir: "public-frontend";
562
+ readonly entry: "index.html";
563
+ };
564
+ };
565
+ /**
566
+ * Scope of a manifest, tolerating one written before the field existed.
567
+ *
568
+ * Validation requires `scope` on every upload, so the fallback only ever fires
569
+ * for a manifest already stored on a release row. It reproduces what those
570
+ * releases got in practice — a claw part made the plugin an avatar capability,
571
+ * and nothing else was avatar-scoped.
572
+ */
573
+ declare function resolvePluginScope(manifest: Pick<TegoPluginManifest, 'parts'> & {
574
+ scope?: PluginScope;
575
+ }): PluginScope;
576
+ /** Every disclosure with its default applied, so callers never see undefined. */
577
+ declare function resolvePluginDeclares(manifest: Pick<TegoPluginManifest, 'parts' | 'declares'>): Required<PluginDeclares>;
578
+ type PluginPartName = keyof PluginParts;
579
+ declare const PLUGIN_PART_NAMES: readonly PluginPartName[];
580
+ /** Part names this manifest actually declares, in stable order. */
581
+ declare function declaredPartNames(manifest: TegoPluginManifest): PluginPartName[];
582
+ interface ResolvedFrontendPart {
583
+ dir: string;
584
+ entryPath: string;
585
+ i18nDirPath: string;
586
+ nav: PluginNavEntry[];
587
+ config?: PluginConfigDeclaration;
588
+ }
589
+ interface ResolvedBackendPart {
590
+ dir: string;
591
+ runtime: PluginBackendRuntime;
592
+ entryPath: string;
593
+ /** Empty for node, which ships no native dependencies. */
594
+ platforms: PluginBackendPlatform[];
595
+ egress: string[];
596
+ migrationsDirPath: string;
597
+ compatibilityRepairs?: PluginSchemaRepair[];
598
+ healthPath: string;
599
+ limits: PluginBackendLimits;
600
+ publicRoutes: PluginPublicRoute[];
601
+ config?: PluginConfigDeclaration;
602
+ }
603
+ interface ResolvedClawPart {
604
+ hooks?: PluginClawHooks;
605
+ dir: string;
606
+ manifestPath: string;
607
+ }
608
+ interface ResolvedPublicFrontendPart {
609
+ dir: string;
610
+ entryPath: string;
611
+ }
612
+ interface ResolvedPluginParts {
613
+ frontend?: ResolvedFrontendPart;
614
+ backend?: ResolvedBackendPart;
615
+ claw?: ResolvedClawPart;
616
+ publicFrontend?: ResolvedPublicFrontendPart;
617
+ }
618
+ /**
619
+ * Apply every part default once, producing archive-relative paths.
620
+ *
621
+ * The only place defaults live. Validation, install and the runtimes all read
622
+ * this, so a plugin that omits `entry` cannot be resolved differently by two
623
+ * callers.
624
+ */
625
+ declare function resolvePluginParts(manifest: TegoPluginManifest): ResolvedPluginParts;
626
+
627
+ export { resolvePluginParts as $, type PluginConfigDeclaration as A, type PluginConfigFieldSchema as B, CLAW_MANIFEST_FILENAME as C, type PluginConfigFieldType as D, EMPTY_CONFIG_SECTION_SUMMARY as E, type PluginConfigSchema as F, type PluginConfigUiHint as G, type PluginFrontendPart as H, type PluginParts as I, type PluginPermissions as J, type PluginPublicFrontendPart as K, type LocalizedText as L, type PluginPublicRouteMethod as M, type PluginSchemaRepair as N, type PluginWorkDelegationDeclaration as O, type PluginPublicRoute as P, type ResolvedClawPart as Q, type ResolvedBackendPart as R, type ResolvedFrontendPart as S, type TegoPluginManifest as T, type ResolvedPluginParts as U, type ResolvedPublicFrontendPart as V, applyConfigDefaults as W, configFieldLabel as X, declaredPartNames as Y, redactSecrets as Z, resolvePluginDeclares as _, type PluginBackendRuntime as a, resolvePluginScope as a0, restoreSecrets as a1, summarizeClawConfig as a2, summarizeConfigDeclaration as a3, type PluginScope as b, type PluginPartName as c, type PluginDeclares as d, type PluginConfigSection as e, type PluginConfigSectionSummary as f, type PluginNavIcon as g, type PluginNavEntry as h, type PluginAgentReadinessDeclaration as i, PLUGIN_BACKEND_PLATFORMS as j, PLUGIN_BACKEND_RUNTIMES as k, PLUGIN_CONFIG_SECRET_SENTINEL as l, PLUGIN_CONFIG_SECTIONS as m, PLUGIN_MANIFEST_FILENAME as n, PLUGIN_NAV_ICONS as o, PLUGIN_NAV_ICON_FALLBACK as p, PLUGIN_PART_DEFAULTS as q, PLUGIN_PART_NAMES as r, type PluginAgentReadinessItem as s, type PluginAgentReadinessResponse as t, type PluginAuditDeclarations as u, type PluginAuditToolDeclaration as v, type PluginBackendLimits as w, type PluginBackendPart as x, type PluginBackendPlatform as y, type PluginClawPart as z };
@@ -0,0 +1 @@
1
+ "use strict";var n=Object.defineProperty;var e=(r,t)=>n(r,"name",{value:t,configurable:!0});var chunk3WA3M347_cjs=require("./chunk-3WA3M347.cjs");require("./chunk-ROFUQLOZ.cjs"),require("./chunk-C2OCOPZQ.cjs"),require("./chunk-AJY7ZHXK.cjs"),require("./chunk-OP64Y4IN.cjs"),Object.defineProperty(exports,"PYTHON_LOCK_FILENAME",{enumerable:!0,get:e(function(){return chunk3WA3M347_cjs.PYTHON_LOCK_FILENAME},"get")}),Object.defineProperty(exports,"PYTHON_RUNNER_VERSION",{enumerable:!0,get:e(function(){return chunk3WA3M347_cjs.PYTHON_RUNNER_VERSION},"get")}),Object.defineProperty(exports,"PYTHON_WHEELS_DIR",{enumerable:!0,get:e(function(){return chunk3WA3M347_cjs.PYTHON_WHEELS_DIR},"get")}),Object.defineProperty(exports,"checkPluginAccessCatalog",{enumerable:!0,get:e(function(){return chunk3WA3M347_cjs.checkPluginAccessCatalog},"get")}),Object.defineProperty(exports,"checkPythonVendoring",{enumerable:!0,get:e(function(){return chunk3WA3M347_cjs.checkPythonVendoring},"get")}),Object.defineProperty(exports,"normalizePackageName",{enumerable:!0,get:e(function(){return chunk3WA3M347_cjs.normalizePackageName},"get")}),Object.defineProperty(exports,"parseRequirementsLock",{enumerable:!0,get:e(function(){return chunk3WA3M347_cjs.parseRequirementsLock},"get")}),Object.defineProperty(exports,"parseTegoPluginManifest",{enumerable:!0,get:e(function(){return chunk3WA3M347_cjs.parseTegoPluginManifest},"get")}),Object.defineProperty(exports,"parseWheelFilename",{enumerable:!0,get:e(function(){return chunk3WA3M347_cjs.parseWheelFilename},"get")}),Object.defineProperty(exports,"tegoPluginManifestSchema",{enumerable:!0,get:e(function(){return chunk3WA3M347_cjs.tegoPluginManifestSchema},"get")});