agentworkshop 0.2.2 → 0.3.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.
- package/package.json +16 -1
- package/scripts/dev-guard.mjs +13 -0
- package/sdk/api.mjs +101 -0
- package/sdk/client.mjs +52 -8
- package/sdk/context.mjs +56 -15
- package/sdk/index.d.mts +135 -0
- package/sdk/index.mjs +5 -18
- package/sdk/lifecycle.mjs +25 -0
- package/server/api/plugins/[name]/[...path].ts +5 -2
- package/server/data/daqs.json +237 -61
- package/server/data/dcw-lines.json +56 -0
- package/server/data/dcw-products.json +42 -0
- package/server/data/dcw-recipes.json +120 -0
- package/server/data/dcw-rollback.json +1 -1
- package/server/data/dcw-runs.json +150 -108
- package/server/data/dcws.json +126 -0
- package/server/data/line-runs.json +75 -15
- package/server/plugins/aw-plugins.ts +7 -1
- package/server/services/workshop/plugins/host.mjs +69 -3
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"productId": "pd-3ad54846",
|
|
8
8
|
"productName": "光学膜 BOPP",
|
|
9
9
|
"startedAt": "2026-08-31T16:20:13.707Z",
|
|
10
|
-
"taggedSamples":
|
|
10
|
+
"taggedSamples": 29764
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
13
|
"lineId": "ln-c377a6bf",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"productId": "pd-7e69e0ee",
|
|
18
18
|
"productName": "警告验证产品-k2xh",
|
|
19
19
|
"startedAt": "2026-09-01T03:23:18.233Z",
|
|
20
|
-
"taggedSamples":
|
|
20
|
+
"taggedSamples": 11692
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"lineId": "ln-9224d3d7",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"productId": "pd-910c0fa8",
|
|
28
28
|
"productName": "新协议产品-9xhn",
|
|
29
29
|
"startedAt": "2026-09-01T05:59:24.062Z",
|
|
30
|
-
"taggedSamples":
|
|
30
|
+
"taggedSamples": 14665
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"lineId": "ln-386c53ed",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"productId": "pd-2d4f9357",
|
|
38
38
|
"productName": "新协议产品-6ofk",
|
|
39
39
|
"startedAt": "2026-09-01T06:05:53.063Z",
|
|
40
|
-
"taggedSamples":
|
|
40
|
+
"taggedSamples": 14955
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"lineId": "ln-5957f6db",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"productId": "pd-a3ed5047",
|
|
48
48
|
"productName": "新协议产品-x4hd",
|
|
49
49
|
"startedAt": "2026-09-01T06:09:02.148Z",
|
|
50
|
-
"taggedSamples":
|
|
50
|
+
"taggedSamples": 14541
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
"lineId": "ln-9ec42f08",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"productId": "pd-5de729c0",
|
|
58
58
|
"productName": "新协议产品-teti",
|
|
59
59
|
"startedAt": "2026-09-01T06:13:44.315Z",
|
|
60
|
-
"taggedSamples":
|
|
60
|
+
"taggedSamples": 14520
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
"lineId": "ln-69e37924",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"productId": "pd-45eb8d43",
|
|
68
68
|
"productName": "新协议产品-fg8t",
|
|
69
69
|
"startedAt": "2026-09-01T06:16:47.469Z",
|
|
70
|
-
"taggedSamples":
|
|
70
|
+
"taggedSamples": 14553
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
73
|
"lineId": "ln-c269e692",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"productId": "pd-b3bd0191",
|
|
78
78
|
"productName": "新协议产品-w2sp",
|
|
79
79
|
"startedAt": "2026-09-01T06:56:05.893Z",
|
|
80
|
-
"taggedSamples":
|
|
80
|
+
"taggedSamples": 14604
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
"lineId": "ln-229d1637",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"productId": "pd-06b896f9",
|
|
88
88
|
"productName": "新协议产品-lp4h",
|
|
89
89
|
"startedAt": "2026-09-01T06:57:29.288Z",
|
|
90
|
-
"taggedSamples":
|
|
90
|
+
"taggedSamples": 14476
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"lineId": "ln-9546f91f",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"productId": "pd-53e55078",
|
|
98
98
|
"productName": "新协议产品-jri6",
|
|
99
99
|
"startedAt": "2026-09-01T07:00:25.059Z",
|
|
100
|
-
"taggedSamples":
|
|
100
|
+
"taggedSamples": 13899
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
"lineId": "ln-087aad5b",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"productId": "pd-e7e969af",
|
|
108
108
|
"productName": "新协议产品-4c2d",
|
|
109
109
|
"startedAt": "2026-09-01T07:09:07.307Z",
|
|
110
|
-
"taggedSamples":
|
|
110
|
+
"taggedSamples": 12890
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
113
|
"lineId": "ln-97d44f8a",
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"productId": "pd-28a3ab2c",
|
|
118
118
|
"productName": "新协议产品-b2ni",
|
|
119
119
|
"startedAt": "2026-09-01T07:13:44.912Z",
|
|
120
|
-
"taggedSamples":
|
|
120
|
+
"taggedSamples": 12739
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"lineId": "ln-a9551770",
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
"productId": "pd-0c6a64c8",
|
|
128
128
|
"productName": "新协议产品-uwkf",
|
|
129
129
|
"startedAt": "2026-09-01T07:15:40.113Z",
|
|
130
|
-
"taggedSamples":
|
|
130
|
+
"taggedSamples": 12384
|
|
131
131
|
},
|
|
132
132
|
{
|
|
133
133
|
"lineId": "ln-844ad82f",
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"productId": "pd-6932b24f",
|
|
138
138
|
"productName": "新协议产品-kk6l",
|
|
139
139
|
"startedAt": "2026-09-01T09:06:55.728Z",
|
|
140
|
-
"taggedSamples":
|
|
140
|
+
"taggedSamples": 10539
|
|
141
141
|
},
|
|
142
142
|
{
|
|
143
143
|
"lineId": "ln-af002514",
|
|
@@ -147,6 +147,66 @@
|
|
|
147
147
|
"productId": "pd-6348a595",
|
|
148
148
|
"productName": "0.8mm 光学膜",
|
|
149
149
|
"startedAt": "2026-09-01T14:06:28.766Z",
|
|
150
|
-
"taggedSamples":
|
|
150
|
+
"taggedSamples": 952
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"lineId": "ln-0eccf6ba",
|
|
154
|
+
"runId": "rr-4e0a115f",
|
|
155
|
+
"recipeId": "rc-8a60518e",
|
|
156
|
+
"recipeName": "哨兵配方-mtjku36w",
|
|
157
|
+
"productId": "pd-4b71be77",
|
|
158
|
+
"productName": "哨兵产品-mtjku36w",
|
|
159
|
+
"startedAt": "2026-09-02T04:09:11.482Z",
|
|
160
|
+
"taggedSamples": 5
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"lineId": "ln-e984246e",
|
|
164
|
+
"runId": "rr-39b3edda",
|
|
165
|
+
"recipeId": "rc-70f39a03",
|
|
166
|
+
"recipeName": "配方C-mtjkwyhu",
|
|
167
|
+
"productId": "pd-bb1e0bed",
|
|
168
|
+
"productName": "产品C-mtjkwyhu",
|
|
169
|
+
"startedAt": "2026-09-02T04:11:26.583Z",
|
|
170
|
+
"taggedSamples": 4
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"lineId": "ln-1fe0b5bc",
|
|
174
|
+
"runId": "rr-2baf5f34",
|
|
175
|
+
"recipeId": "rc-25081a45",
|
|
176
|
+
"recipeName": "配方D-mtjkzcfr",
|
|
177
|
+
"productId": "pd-9f2d9507",
|
|
178
|
+
"productName": "产品D-mtjkzcfr",
|
|
179
|
+
"startedAt": "2026-09-02T04:13:17.902Z",
|
|
180
|
+
"taggedSamples": 3
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"lineId": "ln-d826473e",
|
|
184
|
+
"runId": "rr-7585cef0",
|
|
185
|
+
"recipeId": "rc-3ebd1a97",
|
|
186
|
+
"recipeName": "配方E-mtjl43pv",
|
|
187
|
+
"productId": "pd-d230255e",
|
|
188
|
+
"productName": "产品E-mtjl43pv",
|
|
189
|
+
"startedAt": "2026-09-02T04:16:59.891Z",
|
|
190
|
+
"taggedSamples": 2
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"lineId": "ln-156abb71",
|
|
194
|
+
"runId": "rr-d8002452",
|
|
195
|
+
"recipeId": "rc-fce9474f",
|
|
196
|
+
"recipeName": "配方F-mtjl60qf",
|
|
197
|
+
"productId": "pd-6065b4ba",
|
|
198
|
+
"productName": "产品F-mtjl60qf",
|
|
199
|
+
"startedAt": "2026-09-02T04:18:29.340Z",
|
|
200
|
+
"taggedSamples": 1
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"lineId": "ln-bac43927",
|
|
204
|
+
"runId": "rr-7f4a6ac0",
|
|
205
|
+
"recipeId": "rc-e27a0673",
|
|
206
|
+
"recipeName": "配方G-mtjl98nl",
|
|
207
|
+
"productId": "pd-52f54e33",
|
|
208
|
+
"productName": "产品G-mtjl98nl",
|
|
209
|
+
"startedAt": "2026-09-02T04:20:59.682Z",
|
|
210
|
+
"taggedSamples": 0
|
|
151
211
|
}
|
|
152
212
|
]
|
|
@@ -11,7 +11,13 @@ import { dirname, resolve } from 'node:path'
|
|
|
11
11
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
12
12
|
|
|
13
13
|
export default defineNitroPlugin((nitroApp) => {
|
|
14
|
-
void initPluginHost({ cwd: process.cwd(), packageRoot })
|
|
14
|
+
void initPluginHost({ cwd: process.cwd(), packageRoot }).then((host) => {
|
|
15
|
+
// 实际监听端口回填(nitro listen 后 ctx.api 自环 origin 才准确)
|
|
16
|
+
nitroApp.hooks.hookOnce('listen', (listener: { port?: number }) => {
|
|
17
|
+
if (listener?.port)
|
|
18
|
+
host.setSelfOrigin(listener.port)
|
|
19
|
+
})
|
|
20
|
+
})
|
|
15
21
|
nitroApp.hooks.hookOnce('close', () => {
|
|
16
22
|
void shutdownPluginHost()
|
|
17
23
|
})
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// —— ctx 由宿主注入,插件运行时零导入依赖(sdk/ 供类型与显式糖)。
|
|
10
10
|
// 错误隔离:单插件装载/执行失败记入 failures,绝不拖垮主服务。
|
|
11
11
|
// ============================================================
|
|
12
|
-
import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
12
|
+
import { existsSync, readdirSync, readFileSync, watch } from 'node:fs'
|
|
13
13
|
import { join, resolve } from 'node:path'
|
|
14
14
|
import { pathToFileURL } from 'node:url'
|
|
15
15
|
import { HookBus, createPluginContext, createRouteTable, validatePluginModule } from '@/sdk/index.mjs'
|
|
@@ -75,6 +75,7 @@ export async function initPluginHost({ cwd = process.cwd(), packageRoot } = {})
|
|
|
75
75
|
}),
|
|
76
76
|
routes: createRouteTable(),
|
|
77
77
|
plugins: new Map(),
|
|
78
|
+
disposables: new Map(), // name → fn[](setup 内 ctx.onDispose 登记;server:close 时回收)
|
|
78
79
|
failures: [],
|
|
79
80
|
initedAt: null,
|
|
80
81
|
logger,
|
|
@@ -83,6 +84,7 @@ export async function initPluginHost({ cwd = process.cwd(), packageRoot } = {})
|
|
|
83
84
|
|
|
84
85
|
// 有效配置(只读面;引擎/模式解析从运行根动态加载,js-yaml 由对应 node_modules 解析)
|
|
85
86
|
let config = null
|
|
87
|
+
let settingsPath = null
|
|
86
88
|
let paths = { home: defaultHome(), configRoot: join(cwd, '.AgentWorkShop'), dataDir: join(cwd, '.AgentWorkShop', 'data') }
|
|
87
89
|
try {
|
|
88
90
|
const homeMod = await import(pathToUrl(join(cwd, 'shared', 'config', 'home.mjs')))
|
|
@@ -91,6 +93,7 @@ export async function initPluginHost({ cwd = process.cwd(), packageRoot } = {})
|
|
|
91
93
|
if (engineRoot && existsSync(join(engineRoot, 'shared', 'config', 'engine.mjs'))) {
|
|
92
94
|
const engine = await import(pathToUrl(join(engineRoot, 'shared', 'config', 'engine.mjs')))
|
|
93
95
|
config = engine.loadEffective({ configPath: rm.configPath, settingsPath: rm.settingsPath, env: process.env })
|
|
96
|
+
settingsPath = rm.settingsPath
|
|
94
97
|
}
|
|
95
98
|
paths = { home: rm.home, configRoot: rm.configRoot, dataDir: rm.dataDir }
|
|
96
99
|
host.logger.info(`配置根: ${rm.configRoot} (${rm.mode} 模式)`)
|
|
@@ -98,6 +101,51 @@ export async function initPluginHost({ cwd = process.cwd(), packageRoot } = {})
|
|
|
98
101
|
catch (err) {
|
|
99
102
|
host.logger.warn('配置引擎加载降级(插件 ctx.config 将为空):', err?.message)
|
|
100
103
|
}
|
|
104
|
+
host.config = config
|
|
105
|
+
// 自环 origin:PORT env(prod) > argv --port(dev:dev-guard 转发链天然携带) > 配置 dev 端口;
|
|
106
|
+
// nitro listen 钩子(setSelfOrigin)仍保留为最终兜底
|
|
107
|
+
const argPort = (() => {
|
|
108
|
+
const argv = process.argv
|
|
109
|
+
const i = argv.indexOf('--port')
|
|
110
|
+
if (i >= 0 && argv[i + 1]) return argv[i + 1]
|
|
111
|
+
const eq = argv.find(a => a.startsWith('--port='))
|
|
112
|
+
return eq ? eq.slice(7) : null
|
|
113
|
+
})()
|
|
114
|
+
let selfOrigin = `http://127.0.0.1:${process.env.PORT ?? process.env.NITRO_PORT ?? argPort ?? config?.effective?.['server.dev.port'] ?? 3000}`
|
|
115
|
+
host.setSelfOrigin = (port) => {
|
|
116
|
+
selfOrigin = `http://127.0.0.1:${port}`
|
|
117
|
+
host.logger.info(`自环 origin 就绪: ${selfOrigin}`)
|
|
118
|
+
}
|
|
119
|
+
host.selfOrigin = () => selfOrigin
|
|
120
|
+
host.logger.info(`自环 origin: ${selfOrigin} (PORT=${process.env.PORT ?? '∅'} NITRO_PORT=${process.env.NITRO_PORT ?? '∅'} argPort=${argPort ?? '∅'})`)
|
|
121
|
+
|
|
122
|
+
// 配置变更监听:runtime-settings.json 变化 → 原地刷新 effective + config:changed 钩子
|
|
123
|
+
if (settingsPath && existsSync(settingsPath)) {
|
|
124
|
+
try {
|
|
125
|
+
let debounce = null
|
|
126
|
+
watch(settingsPath, () => {
|
|
127
|
+
clearTimeout(debounce)
|
|
128
|
+
debounce = setTimeout(async () => {
|
|
129
|
+
try {
|
|
130
|
+
if (host.config && existsSync(settingsPath)) {
|
|
131
|
+
const homeMod = await import(pathToUrl(join(cwd, 'shared', 'config', 'home.mjs')))
|
|
132
|
+
const rm = homeMod.resolveRunMode({ cwd, packageRoot, env: process.env })
|
|
133
|
+
const engine = await import(pathToUrl(join((rm.mode === 'repo' ? rm.root : packageRoot ?? rm.root) ?? cwd, 'shared', 'config', 'engine.mjs')))
|
|
134
|
+
const fresh = engine.loadEffective({ configPath: rm.configPath, settingsPath: rm.settingsPath, env: process.env })
|
|
135
|
+
Object.assign(host.config.effective, fresh.effective)
|
|
136
|
+
host.config.sources = fresh.sources
|
|
137
|
+
}
|
|
138
|
+
await host.bus.emit('config:changed', { at: new Date().toISOString() })
|
|
139
|
+
host.logger.info('配置变更已广播(config:changed)')
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
host.logger.warn('config:changed 处理失败:', err?.message)
|
|
143
|
+
}
|
|
144
|
+
}, 300)
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
catch { /* fs.watch 不可用时插件可经轮询自行感知 */ }
|
|
148
|
+
}
|
|
101
149
|
|
|
102
150
|
const entries = discoverPluginDirs(cwd)
|
|
103
151
|
if (entries.length) host.logger.info(`发现 ${entries.length} 个插件,开始装载 ...`)
|
|
@@ -129,12 +177,15 @@ export async function initPluginHost({ cwd = process.cwd(), packageRoot } = {})
|
|
|
129
177
|
rec.routes.push({ method: String(m).toUpperCase(), path: p })
|
|
130
178
|
},
|
|
131
179
|
}
|
|
180
|
+
const perPluginDisposables = []
|
|
181
|
+
host.disposables.set(def.name, perPluginDisposables)
|
|
132
182
|
const ctx = createPluginContext({
|
|
133
183
|
name: def.name,
|
|
134
184
|
scope,
|
|
135
185
|
dir,
|
|
136
186
|
hooks: host.bus,
|
|
137
187
|
logger: {
|
|
188
|
+
debug: (...a) => logger.info(`[${def.name}][debug]`, ...a),
|
|
138
189
|
info: (...a) => logger.info(`[${def.name}]`, ...a),
|
|
139
190
|
warn: (...a) => logger.warn(`[${def.name}]`, ...a),
|
|
140
191
|
error: (...a) => logger.error(`[${def.name}]`, ...a),
|
|
@@ -142,6 +193,11 @@ export async function initPluginHost({ cwd = process.cwd(), packageRoot } = {})
|
|
|
142
193
|
config,
|
|
143
194
|
paths,
|
|
144
195
|
emitter,
|
|
196
|
+
onDispose: (fn) => {
|
|
197
|
+
perPluginDisposables.push(fn)
|
|
198
|
+
return fn
|
|
199
|
+
},
|
|
200
|
+
selfOrigin: host.selfOrigin,
|
|
145
201
|
})
|
|
146
202
|
|
|
147
203
|
// 声明式 routes + setup 内 ctx.route() 两种形态都支持
|
|
@@ -214,10 +270,20 @@ export function pluginManifest() {
|
|
|
214
270
|
}))
|
|
215
271
|
}
|
|
216
272
|
|
|
217
|
-
/** 关机钩子(nitro close 时调用) */
|
|
273
|
+
/** 关机钩子(nitro close 时调用):先逐插件回收订阅/定时器,再广播 server:close */
|
|
218
274
|
export async function shutdownPluginHost() {
|
|
219
275
|
const host = getPluginHost()
|
|
220
276
|
if (!host) return
|
|
277
|
+
for (const [name, list] of host.disposables ?? []) {
|
|
278
|
+
for (const fn of list.splice(0)) {
|
|
279
|
+
try {
|
|
280
|
+
await fn()
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
host.logger.warn(`[${name}] onDispose 失败:`, err?.message)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
221
287
|
await host.bus.emit('server:close', { at: new Date().toISOString() })
|
|
222
|
-
host.logger.info('
|
|
288
|
+
host.logger.info('插件清理完成,已发出 server:close')
|
|
223
289
|
}
|