agentworkshop 0.2.2 → 0.4.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.
Files changed (40) hide show
  1. package/LICENSE +91 -0
  2. package/README-zh.md +431 -424
  3. package/README.md +10 -3
  4. package/app/components/AppSidebar.vue +1 -0
  5. package/app/pages/plugins/index.vue +258 -0
  6. package/app/plugins/aw-plugins.client.ts +81 -48
  7. package/cli/commands/plugin.mjs +57 -7
  8. package/docs/plugins.md +133 -63
  9. package/docs/sdk.md +265 -0
  10. package/i18n/locales/en.ts +17 -0
  11. package/i18n/locales/zh-CN.ts +17 -0
  12. package/package.json +19 -2
  13. package/scripts/_dbg-docs-site-shot.mjs +33 -0
  14. package/scripts/dev-guard.mjs +13 -0
  15. package/scripts/home-bootstrap.mjs +26 -1
  16. package/sdk/api.mjs +101 -0
  17. package/sdk/client.mjs +56 -8
  18. package/sdk/context.mjs +56 -15
  19. package/sdk/examples/line-sentinel/client.mjs +31 -0
  20. package/sdk/examples/line-sentinel/index.mjs +102 -0
  21. package/sdk/examples/ops-notifier/client.mjs +23 -0
  22. package/sdk/examples/ops-notifier/index.mjs +34 -0
  23. package/sdk/index.d.mts +135 -0
  24. package/sdk/index.mjs +5 -18
  25. package/sdk/lifecycle.mjs +25 -0
  26. package/server/api/plugins/[name]/[...path].ts +5 -2
  27. package/server/api/workshop/plugins/[name]/disable.post.ts +19 -0
  28. package/server/api/workshop/plugins/[name]/enable.post.ts +19 -0
  29. package/server/api/workshop/plugins/[name]/index.get.ts +14 -0
  30. package/server/api/workshop/plugins/index.get.ts +17 -0
  31. package/server/data/daqs.json +260 -62
  32. package/server/data/dcw-lines.json +63 -0
  33. package/server/data/dcw-products.json +49 -0
  34. package/server/data/dcw-recipes.json +140 -0
  35. package/server/data/dcw-rollback.json +1 -1
  36. package/server/data/dcw-runs.json +175 -126
  37. package/server/data/dcws.json +147 -0
  38. package/server/data/line-runs.json +85 -15
  39. package/server/plugins/aw-plugins.ts +7 -1
  40. package/server/services/workshop/plugins/host.mjs +212 -18
@@ -0,0 +1,135 @@
1
+ // AgentWorkShop SDK 类型声明(agentworkshop/sdk)
2
+ import type { HookBus } from './hooks.mjs'
3
+
4
+ export declare const SDK_VERSION: string
5
+
6
+ /** 生命周期钩子总线:异步串行、错误隔离、'*' 通配、连续失败自动熔断 */
7
+ export declare class HookBus {
8
+ constructor(opts?: { name?: string, onError?: (err: Error, meta?: { bus?: string, type?: string, fails?: number }) => void })
9
+ on(type: string, fn: (payload: any) => any): () => void
10
+ once(type: string, fn: (payload: any) => any): () => void
11
+ off(type: string, fn: (payload: any) => any): void
12
+ emit(type: string, payload?: any): Promise<any>
13
+ readonly size: number
14
+ }
15
+
16
+ export interface PluginLogger {
17
+ debug(...args: unknown[]): void
18
+ info(...args: unknown[]): void
19
+ warn(...args: unknown[]): void
20
+ error(...args: unknown[]): void
21
+ }
22
+
23
+ export interface PluginKv {
24
+ get(key: string): any
25
+ set(key: string, value: any): any
26
+ all(): Record<string, any>
27
+ bump(key: string, by?: number): number
28
+ }
29
+
30
+ export interface PluginHttp {
31
+ get(url: string, opts?: { timeoutMs?: number, headers?: Record<string, string> }): Promise<Response>
32
+ post(url: string, body?: unknown, opts?: { timeoutMs?: number, headers?: Record<string, string> }): Promise<Response>
33
+ }
34
+
35
+ /** 平台 REST 客户端(SDK 作为项目服务 client 的门面) */
36
+ export interface PlatformClient {
37
+ call<T = any>(method: string, path: string, body?: unknown): Promise<T>
38
+ get<T = any>(path: string, query?: Record<string, unknown>): Promise<T>
39
+ post<T = any>(path: string, body?: unknown): Promise<T>
40
+ patch<T = any>(path: string, body?: unknown): Promise<T>
41
+ delete<T = any>(path: string): Promise<T>
42
+ setToken(token: string | null): PlatformClient
43
+ ping(): Promise<any>
44
+ users: { list(q?: any): Promise<any>, get(id: string): Promise<any>, create(b: any): Promise<any>, login(email: string, password: string): Promise<any>, me(): Promise<any> }
45
+ lines: { list(q?: any): Promise<any>, get(id: string): Promise<any>, create(b: any): Promise<any>, update(id: string, p: any): Promise<any>, remove(id: string): Promise<any>, start(id: string, recipeId?: string): Promise<any>, stop(id: string): Promise<any> }
46
+ products: { list(q?: any): Promise<any>, create(b: any): Promise<any> }
47
+ recipes: { list(q?: any): Promise<any>, create(b: any): Promise<any> }
48
+ dcwNodes: { list(q?: any): Promise<any>, create(b: any): Promise<any> }
49
+ daqNodes: { list(q?: any): Promise<any>, create(b: any): Promise<any>, alarms(): Promise<any> }
50
+ templates: { daq(): Promise<any[]>, dcw(): Promise<any[]> }
51
+ twins: { list(q?: any): Promise<any>, create(b: any): Promise<any> }
52
+ teams: { list(q?: any): Promise<any>, create(b: any): Promise<any> }
53
+ agents: { list(q?: any): Promise<any>, create(b: any): Promise<any> }
54
+ channels: { list(q?: any): Promise<any> }
55
+ plugins: { manifest(): Promise<any> }
56
+ }
57
+
58
+ export interface PluginContext {
59
+ name: string
60
+ scope: 'project' | 'user'
61
+ dir: string
62
+ sdkVersion: string
63
+ hooks: HookBus
64
+ logger: PluginLogger
65
+ config: {
66
+ get(key: string): any
67
+ all(): Record<string, any>
68
+ onChange(fn: (payload?: { at: string }) => any): () => void
69
+ }
70
+ paths: { home: string, configRoot: string, dataDir: string }
71
+ dataDir: string
72
+ kv: PluginKv
73
+ timer: {
74
+ setInterval(fn: (...args: any[]) => void, ms: number, ...rest: any[]): NodeJS.Timeout
75
+ setTimeout(fn: (...args: any[]) => void, ms: number, ...rest: any[]): NodeJS.Timeout
76
+ }
77
+ onDispose(fn: () => any): () => void
78
+ subscriptions: { add(d: { dispose(): any } | (() => any)): any }
79
+ route(method: string, path: string, handler: (event: any) => any): boolean
80
+ api: PlatformClient
81
+ http: PluginHttp
82
+ events: { on(type: string, fn: (payload: any) => any): () => void, off(type: string, fn: (payload: any) => any): void }
83
+ }
84
+
85
+ export interface PluginRouteDef {
86
+ method?: string
87
+ path: string
88
+ handler: (event: any) => any
89
+ }
90
+
91
+ export interface PluginDef {
92
+ name: string
93
+ version?: string
94
+ description?: string
95
+ setup?(ctx: PluginContext): void | Promise<void>
96
+ client?: string
97
+ routes?: PluginRouteDef[]
98
+ }
99
+
100
+ /** 显式糖:类型化定义插件(宿主同样接受裸对象导出) */
101
+ export declare function definePlugin(def: PluginDef): PluginDef
102
+
103
+ export declare function createPluginContext(opts: Record<string, any>): PluginContext
104
+ export declare function createRouteTable(): {
105
+ register(name: string, method: string, path: string, handler: (event: any) => any): boolean
106
+ resolve(name: string, method: string, path: string): ((event: any) => any) | null
107
+ byPlugin(name: string): Array<{ method: string, path: string }>
108
+ readonly size: number
109
+ }
110
+ export declare function validatePluginModule(mod: any, source: string): { ok: boolean, def?: PluginDef, error?: string }
111
+ export declare function pluginKvExists(dataDir: string, name: string): boolean
112
+
113
+ export declare function createPlatformClient(opts?: { baseUrl?: string, token?: string, logger?: PluginLogger, timeoutMs?: number }): PlatformClient
114
+
115
+ export declare const LIFECYCLE_EVENTS: readonly ['plugin:host:init', 'config:changed', 'event:*', 'daq:sample', 'dcw:write', 'line:start', 'line:stop', 'server:close']
116
+ export declare const CLIENT_EVENTS: readonly ['client:init', 'event:*', 'page:change', 'client:destroy']
117
+
118
+ /** 客户端插件上下文(sdk/client.mjs) */
119
+ export declare const CLIENT_SDK_VERSION: string
120
+ export interface ClientContext {
121
+ name: string
122
+ sdkVersion: string
123
+ hooks: HookBus
124
+ on(type: string, fn: (payload: any) => any): () => void
125
+ fetch<T = any>(path: string, opt?: { method?: string, body?: unknown, headers?: Record<string, string> }): Promise<T>
126
+ el(tag: string, attrs?: Record<string, unknown>, children?: Array<Node | string>): HTMLElement
127
+ mount(target: string | Element, node: Node): Node
128
+ root(): HTMLElement
129
+ log: PluginLogger
130
+ dispose(): void
131
+ }
132
+ export declare function createClientContext(opts: { name: string, eventBridge?: (fn: (type: string, payload: any) => void) => (() => void), baseUrl?: string }): ClientContext
133
+
134
+ declare const _default: Record<string, unknown>
135
+ export default _default
package/sdk/index.mjs CHANGED
@@ -15,29 +15,15 @@
15
15
  // ============================================================
16
16
  import { SDK_VERSION, definePlugin, createPluginContext, createRouteTable, validatePluginModule, pluginKvExists } from './context.mjs'
17
17
  import { HookBus } from './hooks.mjs'
18
+ import { createPlatformClient } from './api.mjs'
18
19
  import { CLIENT_SDK_VERSION, createClientContext } from './client.mjs'
20
+ import { LIFECYCLE_EVENTS, CLIENT_EVENTS } from './lifecycle.mjs'
19
21
 
20
22
  export { SDK_VERSION, definePlugin, createPluginContext, createRouteTable, validatePluginModule, pluginKvExists } from './context.mjs'
21
23
  export { HookBus } from './hooks.mjs'
24
+ export { createPlatformClient } from './api.mjs'
22
25
  export { CLIENT_SDK_VERSION, createClientContext } from './client.mjs'
23
-
24
- /** 服务端生命周期事件清单(宿主触发;文档见 docs/plugins.md) */
25
- export const LIFECYCLE_EVENTS = Object.freeze([
26
- 'plugin:host:init',
27
- 'event:*',
28
- 'daq:sample',
29
- 'dcw:write',
30
- 'line:start',
31
- 'line:stop',
32
- 'server:close',
33
- ])
34
-
35
- /** 客户端生命周期事件清单 */
36
- export const CLIENT_EVENTS = Object.freeze([
37
- 'client:init',
38
- 'event:*',
39
- 'page:change',
40
- ])
26
+ export { LIFECYCLE_EVENTS, CLIENT_EVENTS } from './lifecycle.mjs'
41
27
 
42
28
  export default {
43
29
  SDK_VERSION,
@@ -47,6 +33,7 @@ export default {
47
33
  createRouteTable,
48
34
  validatePluginModule,
49
35
  pluginKvExists,
36
+ createPlatformClient,
50
37
  CLIENT_SDK_VERSION,
51
38
  createClientContext,
52
39
  LIFECYCLE_EVENTS,
@@ -0,0 +1,25 @@
1
+ // ============================================================
2
+ // AgentWorkShop SDK — 生命周期事件清单(宿主触发;单一事实源)
3
+ // ============================================================
4
+
5
+ /** 服务端生命周期事件清单(宿主触发;文档见 docs/plugins.md) */
6
+ export const LIFECYCLE_EVENTS = Object.freeze([
7
+ 'plugin:host:init',
8
+ 'config:changed',
9
+ 'event:*',
10
+ 'daq:sample',
11
+ 'dcw:write',
12
+ 'line:start',
13
+ 'line:stop',
14
+ 'server:close',
15
+ ])
16
+
17
+ /** 客户端生命周期事件清单 */
18
+ export const CLIENT_EVENTS = Object.freeze([
19
+ 'client:init',
20
+ 'event:*',
21
+ 'page:change',
22
+ 'client:destroy',
23
+ ])
24
+
25
+ export default { LIFECYCLE_EVENTS, CLIENT_EVENTS }
@@ -3,10 +3,10 @@
3
3
  * 插件经 ctx.route(method, path, handler) 注册;handler(event) 返回值由 nitro 序列化。
4
4
  * 鉴权由插件自行处理(v1 不强制;可经 resolveUser 复用业务鉴权)。
5
5
  */
6
- import { defineEventHandler, createError } from 'h3'
6
+ import { defineEventHandler, createError, readBody } from 'h3'
7
7
  import { getPluginHost } from '@/server/services/workshop/plugins/host.mjs'
8
8
 
9
- export default defineEventHandler((event) => {
9
+ export default defineEventHandler(async (event) => {
10
10
  const host = getPluginHost()
11
11
  if (!host) throw createError({ statusCode: 503, statusMessage: 'plugin host not ready' })
12
12
  const name = String(event.context.params?.name ?? '')
@@ -15,5 +15,8 @@ export default defineEventHandler((event) => {
15
15
  if (!handler) {
16
16
  throw createError({ statusCode: 404, statusMessage: `plugin route not found: ${event.method} /api/plugins/${name}${path}` })
17
17
  }
18
+ // 预读 body 挂到 event(插件 handler 无 h3 导入能力,经 event.awBody 消费)
19
+ const awBody = await readBody(event).catch(() => undefined)
20
+ ;(event as Record<string, unknown>).awBody = awBody
18
21
  return handler(event)
19
22
  })
@@ -0,0 +1,19 @@
1
+ /**
2
+ * POST /api/workshop/plugins/:name/disable —— 停用插件(admin;热重载生效)。
3
+ */
4
+ import { defineEventHandler, createError } from 'h3'
5
+ import { resolveUser, requireAdmin } from '@/server/api/workshop/caller'
6
+ import { pluginManifest, reloadPluginHost, setPluginEnabled } from '@/server/services/workshop/plugins/host.mjs'
7
+
8
+ export default defineEventHandler(async (event) => {
9
+ const user = resolveUser(event)
10
+ requireAdmin(event)
11
+ const name = String(event.context.params?.name ?? '')
12
+ if (!pluginManifest().some(p => p.name === name)) {
13
+ throw createError({ statusCode: 404, statusMessage: `plugin not found: ${name}` })
14
+ }
15
+ setPluginEnabled(name, false)
16
+ await reloadPluginHost()
17
+ const p = pluginManifest().find(x => x.name === name)
18
+ return { ok: true, enabled: p?.enabled ?? false, by: user.name }
19
+ })
@@ -0,0 +1,19 @@
1
+ /**
2
+ * POST /api/workshop/plugins/:name/enable —— 启用插件(admin;热重载生效)。
3
+ */
4
+ import { defineEventHandler, createError } from 'h3'
5
+ import { resolveUser, requireAdmin } from '@/server/api/workshop/caller'
6
+ import { pluginManifest, reloadPluginHost, setPluginEnabled } from '@/server/services/workshop/plugins/host.mjs'
7
+
8
+ export default defineEventHandler(async (event) => {
9
+ const user = resolveUser(event)
10
+ requireAdmin(event)
11
+ const name = String(event.context.params?.name ?? '')
12
+ if (!pluginManifest().some(p => p.name === name)) {
13
+ throw createError({ statusCode: 404, statusMessage: `plugin not found: ${name}` })
14
+ }
15
+ setPluginEnabled(name, true)
16
+ await reloadPluginHost()
17
+ const p = pluginManifest().find(x => x.name === name)
18
+ return { ok: true, enabled: p?.enabled ?? true, by: user.name }
19
+ })
@@ -0,0 +1,14 @@
1
+ /**
2
+ * GET /api/workshop/plugins/:name —— 单插件详情(鉴权)。
3
+ */
4
+ import { defineEventHandler, createError } from 'h3'
5
+ import { resolveUser } from '@/server/api/workshop/caller'
6
+ import { pluginManifest } from '@/server/services/workshop/plugins/host.mjs'
7
+
8
+ export default defineEventHandler((event) => {
9
+ resolveUser(event)
10
+ const name = String(event.context.params?.name ?? '')
11
+ const p = pluginManifest().find(x => x.name === name)
12
+ if (!p) throw createError({ statusCode: 404, statusMessage: `plugin not found: ${name}` })
13
+ return p
14
+ })
@@ -0,0 +1,17 @@
1
+ /**
2
+ * GET /api/workshop/plugins —— 插件管理清单(鉴权;含启停状态/路由/装载失败)。
3
+ * 网页「插件管理」页数据源。
4
+ */
5
+ import { defineEventHandler } from 'h3'
6
+ import { resolveUser } from '@/server/api/workshop/caller'
7
+ import { getPluginHost, pluginManifest } from '@/server/services/workshop/plugins/host.mjs'
8
+
9
+ export default defineEventHandler((event) => {
10
+ resolveUser(event)
11
+ const host = getPluginHost()
12
+ return {
13
+ plugins: pluginManifest(),
14
+ failures: host?.failures ?? [],
15
+ initedAt: host?.initedAt ?? null,
16
+ }
17
+ })