agentworkshop 0.7.13 → 0.7.15

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 (83) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/{CXutoGrn.js → CD1SlCoI.js} +3 -3
  3. package/.output/public/_nuxt/CYBq3kS7.js +1 -0
  4. package/.output/public/_nuxt/Cr9DkD1d.js +1 -0
  5. package/.output/public/_nuxt/DMdVWIGz.js +19 -0
  6. package/.output/public/_nuxt/agents.CB9Ck7VQ.css +1 -0
  7. package/.output/public/_nuxt/builds/latest.json +1 -1
  8. package/.output/public/_nuxt/builds/meta/65f6bed9-b794-44a4-805a-e22700c10817.json +1 -0
  9. package/.output/public/_nuxt/channel-templates.C-M5nKcC.css +1 -0
  10. package/.output/public/_nuxt/{Ds8JbqGB.js → ed5qX-x5.js} +1 -1
  11. package/.output/public/_nuxt/{entry.Bv_GCmPP.css → entry.BNApuuEW.css} +1 -1
  12. package/.output/public/_nuxt/pages.CG8UJ2TK.css +1 -0
  13. package/.output/public/_nuxt/teams.DN0pAGGu.css +1 -0
  14. package/.output/server/chunks/_/nitro.mjs +760 -664
  15. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  16. package/.output/server/chunks/build/TownView-CunmEMzS.mjs +1 -1
  17. package/.output/server/chunks/build/_id_-CVnMdSeG.mjs +1 -1
  18. package/.output/server/chunks/build/_id_-D265Wh_k.mjs +1 -1
  19. package/.output/server/chunks/build/{agents-B10wmFri.mjs → agents--6bzGtES.mjs} +156 -80
  20. package/.output/server/chunks/build/agents--6bzGtES.mjs.map +1 -0
  21. package/.output/server/chunks/build/{channel-templates-CpWxVk5A.mjs → channel-templates-C1Bb-U75.mjs} +19 -20
  22. package/.output/server/chunks/build/channel-templates-C1Bb-U75.mjs.map +1 -0
  23. package/.output/server/chunks/build/daq-DxaXk_8N.mjs +1 -1
  24. package/.output/server/chunks/build/dcw-B0dtiHFG.mjs +1 -1
  25. package/.output/server/chunks/build/{pages-BmRUbGUi.mjs → pages-Aexs6LjD.mjs} +27 -15
  26. package/.output/server/chunks/build/pages-Aexs6LjD.mjs.map +1 -0
  27. package/.output/server/chunks/build/{teams-CNflUtPh.mjs → teams-DD8ZXTKL.mjs} +29 -32
  28. package/.output/server/chunks/build/teams-DD8ZXTKL.mjs.map +1 -0
  29. package/.output/server/chunks/build/useDaqStream-BkmyQT06.mjs +1 -1
  30. package/.output/server/chunks/build/useDcwStream-DWVoU96J.mjs +1 -1
  31. package/.output/server/chunks/build/useWorkshopApi-D2gq06N2.mjs.map +1 -1
  32. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +1 -1
  33. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +1 -1
  34. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +1 -1
  35. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +14 -2
  36. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs.map +1 -1
  37. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +1 -1
  38. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +1 -1
  39. package/.output/server/chunks/routes/api/workshop/index.put.mjs +1 -1
  40. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
  41. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
  42. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
  43. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
  44. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +1 -1
  45. package/.output/server/chunks/routes/renderer.mjs +2 -2
  46. package/.output/server/chunks/virtual/entry.mjs +21 -9
  47. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  48. package/.output/server/package.json +1 -1
  49. package/app/composables/workshop/useWorkshopApi.ts +11 -1
  50. package/app/pages/index.vue +72 -0
  51. package/app/pages/workshop/agents.vue +71 -6
  52. package/app/pages/workshop/channel-templates.vue +2 -1
  53. package/app/pages/workshop/teams.vue +24 -2
  54. package/app/plugins/http.ts +4 -3
  55. package/i18n/locales/en.ts +7 -0
  56. package/i18n/locales/zh-CN.ts +7 -0
  57. package/package.json +148 -148
  58. package/scripts/_dbg-harness-e2e.mjs +92 -0
  59. package/scripts/_dbg-harness-ui-dbg.py +49 -0
  60. package/scripts/_dbg-harness-ui-e2e.py +97 -0
  61. package/scripts/_dbg-login-e2e.mjs +26 -0
  62. package/scripts/aw-expose.mjs +159 -0
  63. package/server/api/workshop/harnesses.get.ts +15 -2
  64. package/server/data/dcw-lines.json +14 -0
  65. package/server/data/dcw-rollback.json +6 -6
  66. package/server/data/dcw-writes.json +24 -0
  67. package/server/data/dcws.json +198 -198
  68. package/server/services/workshop/agents/adapters/line-spawn.ts +3 -2
  69. package/server/services/workshop/agents/harness-availability.ts +127 -0
  70. package/server/services/workshop/agents/registry.ts +21 -0
  71. package/server/services/workshop/runtime/manager.ts +16 -1
  72. package/.output/public/_nuxt/D8xY-Yjc.js +0 -19
  73. package/.output/public/_nuxt/QoCzfpo2.js +0 -1
  74. package/.output/public/_nuxt/agents.CEbox5-D.css +0 -1
  75. package/.output/public/_nuxt/builds/meta/bf43874b-06d3-4e20-a84d-e5b0d09e8a27.json +0 -1
  76. package/.output/public/_nuxt/channel-templates.De5ZvrGz.css +0 -1
  77. package/.output/public/_nuxt/eUGyJdiT.js +0 -1
  78. package/.output/public/_nuxt/pages.BkE-AfIb.css +0 -1
  79. package/.output/public/_nuxt/teams.CUMnbQGf.css +0 -1
  80. package/.output/server/chunks/build/agents-B10wmFri.mjs.map +0 -1
  81. package/.output/server/chunks/build/channel-templates-CpWxVk5A.mjs.map +0 -1
  82. package/.output/server/chunks/build/pages-BmRUbGUi.mjs.map +0 -1
  83. package/.output/server/chunks/build/teams-CNflUtPh.mjs.map +0 -1
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * aw-expose —— 把本机 AgentWorkShop 通过 Cloudflare Tunnel 映射到公网。
4
+ *
5
+ * 用法(在本机已能访问 Web UI 的前提下):
6
+ * node scripts/aw-expose.mjs # 自动探测本机实例(默认端口 3001/顺延)
7
+ * node scripts/aw-expose.mjs --port 3002 # 指定本地端口
8
+ * node scripts/aw-expose.mjs --token <TUNNEL_TOKEN> # 具名隧道(绑定自己的域名;token 来自
9
+ * # Cloudflare Zero Trust → Networks → Tunnels → Create tunnel 的安装令牌,
10
+ * # 也可用环境变量 CLOUDFLARE_TUNNEL_TOKEN 传入,避免进入 shell 历史)
11
+ *
12
+ * 两种模式:
13
+ * - 快速隧道(默认,免账号):分配 https://<随机>.trycloudflare.com 公网地址,每次启动会变;
14
+ * - 具名隧道(--token):固定绑定你 Cloudflare 账号里的域名,地址长期不变,生产推荐。
15
+ *
16
+ * 行为:
17
+ * 1) 定位 cloudflared(PATH → Windows 默认安装位 → ~/.AgentWorkShop/bin);
18
+ * 2) 探活 http://127.0.0.1:<port>/api/health,实例未启动则给出 `aw start` 提示(--start 自动拉起);
19
+ * 3) 拉起隧道进程,从输出解析公网 URL 并打印;
20
+ * 4) 常驻保活(cloudflared 崩溃自动重启,10s 退避);Ctrl+C 一并收尾本地实例(--start 模式)与隧道。
21
+ *
22
+ * 安全提示:公网地址任何人可访问,登录门/权限体系是唯一边界;建议用具名隧道 +
23
+ * Cloudflare Access(Zero Trust)做外层鉴权后再长期公开。
24
+ */
25
+ import { spawn } from 'node:child_process'
26
+ import { existsSync } from 'node:fs'
27
+ import { homedir, platform } from 'node:os'
28
+ import { join } from 'node:path'
29
+
30
+ // ---------- 参数 ----------
31
+ const argv = process.argv.slice(2)
32
+ const argOf = (name) => {
33
+ const i = argv.indexOf(name)
34
+ return i >= 0 && argv[i + 1] ? argv[i + 1] : undefined
35
+ }
36
+ const hasFlag = name => argv.includes(name)
37
+ const PORT = argOf('--port') ?? '3001'
38
+ const LOCAL = `http://127.0.0.1:${PORT}`
39
+ const TUNNEL_TOKEN = argOf('--token') ?? process.env.CLOUDFLARE_TUNNEL_TOKEN ?? ''
40
+ const WANT_START = hasFlag('--start')
41
+ const IS_WIN = platform() === 'win32'
42
+ const BIN = join(homedir(), '.AgentWorkShop', 'bin')
43
+
44
+ const say = msg => console.log(`[aw-expose] ${msg}`)
45
+ const die = (msg) => {
46
+ say(`✖ ${msg}`)
47
+ process.exit(1)
48
+ }
49
+
50
+ // ---------- 定位 cloudflared ----------
51
+ function findCloudflared() {
52
+ const candidates = [
53
+ argOf('--cloudflared'),
54
+ join(BIN, IS_WIN ? 'cloudflared.exe' : 'cloudflared'),
55
+ ...(IS_WIN ? [join(process.env['ProgramFiles(x86)'] ?? 'C:\\Program Files (x86)', 'cloudflared', 'cloudflared.exe')] : ['/usr/local/bin/cloudflared', '/usr/bin/cloudflared']),
56
+ ]
57
+ for (const c of candidates) {
58
+ if (c && existsSync(c)) return c
59
+ }
60
+ return null // 最后交给 PATH
61
+ }
62
+
63
+ async function healthy() {
64
+ try {
65
+ const res = await fetch(`${LOCAL}/api/health`, { signal: AbortSignal.timeout(3000) })
66
+ return res.ok
67
+ }
68
+ catch {
69
+ return false
70
+ }
71
+ }
72
+
73
+ async function waitForHealthy(timeoutMs) {
74
+ const deadline = Date.now() + timeoutMs
75
+ while (Date.now() < deadline) {
76
+ if (await healthy()) return true
77
+ await new Promise(r => setTimeout(r, 1500))
78
+ }
79
+ return false
80
+ }
81
+
82
+ // ---------- 主流程 ----------
83
+ const cloudflared = findCloudflared()
84
+ if (!cloudflared) {
85
+ die(`未找到 cloudflared。安装方式任选其一:
86
+ winget install --id Cloudflare.cloudflared
87
+ # 或下载到 ~/.AgentWorkShop/bin/cloudflared.exe
88
+ https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/`)
89
+ }
90
+ say(`cloudflared: ${cloudflared}`)
91
+ say(`本地实例: ${LOCAL}`)
92
+
93
+ if (!(await healthy())) {
94
+ if (!WANT_START) {
95
+ die(`本地实例未就绪。请先启动(或加 --start 由本脚本拉起):
96
+ aw start # 生产模式(默认端口 3001,占用时自动顺延)
97
+ aw start --port ${PORT}`)
98
+ }
99
+ say('本地实例未就绪,--start 模式:拉起 aw start …')
100
+ const appRoot = process.env.AW_PACKAGE_ROOT ?? process.cwd()
101
+ const awBin = join(appRoot, 'bin', 'aw.mjs')
102
+ if (!existsSync(awBin)) die(`未找到 ${awBin};请在项目/包目录内运行,或用 --port 指向已运行实例`)
103
+ const app = spawn(process.execPath, [awBin, 'start', '--port', PORT], {
104
+ cwd: appRoot,
105
+ stdio: 'ignore',
106
+ detached: false,
107
+ shell: false,
108
+ env: { ...process.env },
109
+ })
110
+ app.on('exit', (code) => {
111
+ if (code !== 0 && code !== null) say(`aw start 退出(code=${code})`)
112
+ })
113
+ say('等待本地实例就绪(最长 120s)…')
114
+ if (!(await waitForHealthy(120_000))) die('本地实例 120s 内未就绪,放弃(可手工 aw start 后重试)')
115
+ }
116
+
117
+ // ---------- 隧道进程(崩溃自动重启) ----------
118
+ let quitting = false
119
+ let child = null
120
+ let currentUrl = ''
121
+
122
+ function startTunnel() {
123
+ const args = TUNNEL_TOKEN
124
+ ? ['tunnel', '--no-autoupdate', 'run', '--token', TUNNEL_TOKEN]
125
+ : ['tunnel', '--no-autoupdate', '--url', LOCAL]
126
+ child = spawn(cloudflared, args, { stdio: ['ignore', 'pipe', 'pipe'], shell: false })
127
+ const scan = (buf) => {
128
+ for (const line of String(buf).split(/\r?\n/)) {
129
+ const m = line.match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/i)
130
+ if (m && m[0] !== currentUrl) {
131
+ currentUrl = m[0]
132
+ say('公网地址(快速隧道,重启会变):')
133
+ console.log(`\n ${currentUrl}\n`)
134
+ say('浏览器打开即为本机 AgentWorkShop;Ctrl+C 结束映射。')
135
+ }
136
+ if (/Registered tunnel connection|connect.*registered/i.test(line) && TUNNEL_TOKEN) {
137
+ say('具名隧道已连接(域名以 Cloudflare Tunnels 配置为准)。')
138
+ }
139
+ }
140
+ }
141
+ child.stdout.on('data', scan)
142
+ child.stderr.on('data', scan)
143
+ child.on('exit', (code) => {
144
+ if (quitting) return
145
+ say(`隧道进程退出(code=${code}),10s 后重启…`)
146
+ setTimeout(startTunnel, 10_000)
147
+ })
148
+ }
149
+
150
+ startTunnel()
151
+
152
+ const cleanup = () => {
153
+ quitting = true
154
+ say('正在结束隧道…')
155
+ if (child) child.kill(IS_WIN ? undefined : 'SIGTERM')
156
+ process.exit(0)
157
+ }
158
+ process.on('SIGINT', cleanup)
159
+ process.on('SIGTERM', cleanup)
@@ -1,12 +1,25 @@
1
1
  /**
2
- * GET /api/workshop/harnesses —— 可用执行引擎注册表(前端下拉/能力徽标)。
2
+ * GET /api/workshop/harnesses —— 可用执行引擎注册表(前端下拉/能力徽标/可用性)。
3
3
  * 数据源 HARNESS_REGISTRY(单一事实源;与 factory/manager 校验同源)。
4
+ * available = 环境探测:进程内引擎恒可用;进程型引擎按 PATH 探测外部 CLI。
5
+ * ?refresh=1 跳过 30s 探测缓存强制重探(装包/改命令后立即见效)。
4
6
  */
7
+ import { getQuery } from 'h3'
5
8
  import { resolveUser } from '@/server/api/workshop/caller'
6
9
  import { defineApiHandler } from '@/server/utils/response'
10
+ import { checkAllHarnessAvailability } from '@/server/services/workshop/agents/harness-availability'
7
11
  import { harnessMetas } from '@/server/services/workshop/agents/registry'
8
12
 
9
13
  export default defineApiHandler(async (event) => {
10
14
  resolveUser(event)
11
- return { harnesses: harnessMetas() }
15
+ const q = getQuery(event)
16
+ const refresh = q.refresh === '1' || q.refresh === 'true'
17
+ const avail = checkAllHarnessAvailability({ refresh })
18
+ const byId = new Map(avail.map(a => [a.id, a]))
19
+ return {
20
+ harnesses: harnessMetas().map(m => ({
21
+ ...m,
22
+ ...(byId.get(m.id) ?? { available: false, inprocess: false, command: null, resolvedPath: null, error: '探测失败' }),
23
+ })),
24
+ }
12
25
  })
@@ -1391,5 +1391,19 @@
1391
1391
  "color": "#3aa0ff",
1392
1392
  "description": "",
1393
1393
  "createdAt": "2026-09-06T02:24:50.518+08:00"
1394
+ },
1395
+ {
1396
+ "id": "ln-8a32e91f",
1397
+ "name": "模拟器产线-mtpp41np",
1398
+ "color": "#f4c542",
1399
+ "description": "",
1400
+ "createdAt": "2026-09-06T18:55:51.506+08:00"
1401
+ },
1402
+ {
1403
+ "id": "ln-d8e727b7",
1404
+ "name": "admin���Բ���",
1405
+ "color": "#35e0a0",
1406
+ "description": "",
1407
+ "createdAt": "2026-09-06T18:56:52.853+08:00"
1394
1408
  }
1395
1409
  ]
@@ -5120,7 +5120,7 @@
5120
5120
  "channels": [],
5121
5121
  "degraded": true
5122
5122
  },
5123
- "evaluatedAt": "2026-09-06T15:27:48.724+08:00",
5123
+ "evaluatedAt": "2026-09-06T19:44:49.775+08:00",
5124
5124
  "windowAgg": {
5125
5125
  "at": "2026-08-31T16:25:17.398Z",
5126
5126
  "fromMs": 1788193396897,
@@ -11569,7 +11569,7 @@
11569
11569
  }
11570
11570
  ]
11571
11571
  },
11572
- "evaluatedAt": "2026-09-06T15:27:48.724+08:00",
11572
+ "evaluatedAt": "2026-09-06T19:44:49.775+08:00",
11573
11573
  "windowAgg": {
11574
11574
  "at": "2026-09-05T02:07:03.383Z",
11575
11575
  "fromMs": 1788573903195,
@@ -11630,7 +11630,7 @@
11630
11630
  }
11631
11631
  ]
11632
11632
  },
11633
- "evaluatedAt": "2026-09-06T15:27:48.724+08:00",
11633
+ "evaluatedAt": "2026-09-06T19:44:49.775+08:00",
11634
11634
  "windowAgg": {
11635
11635
  "at": "2026-09-05T02:44:52.815Z",
11636
11636
  "fromMs": 1788576172595,
@@ -11690,7 +11690,7 @@
11690
11690
  }
11691
11691
  ]
11692
11692
  },
11693
- "evaluatedAt": "2026-09-06T15:27:48.724+08:00",
11693
+ "evaluatedAt": "2026-09-06T19:44:49.775+08:00",
11694
11694
  "windowAgg": {
11695
11695
  "at": "2026-09-05T03:09:49.742Z",
11696
11696
  "fromMs": 1788577669697,
@@ -11750,7 +11750,7 @@
11750
11750
  }
11751
11751
  ]
11752
11752
  },
11753
- "evaluatedAt": "2026-09-06T15:27:48.724+08:00",
11753
+ "evaluatedAt": "2026-09-06T19:44:49.775+08:00",
11754
11754
  "windowAgg": {
11755
11755
  "at": "2026-09-05T03:34:32.268Z",
11756
11756
  "fromMs": 1788579151974,
@@ -11799,7 +11799,7 @@
11799
11799
  "channels": [],
11800
11800
  "degraded": true
11801
11801
  },
11802
- "evaluatedAt": "2026-09-06T15:27:48.724+08:00",
11802
+ "evaluatedAt": "2026-09-06T19:44:49.775+08:00",
11803
11803
  "windowAgg": {
11804
11804
  "at": "2026-09-05T09:01:07.414Z",
11805
11805
  "fromMs": 1788598747074,
@@ -12766,5 +12766,29 @@
12766
12766
  "message": "Mock PLC 写入成功:170 → raw 170,回读一致(标定后物理值 170)",
12767
12767
  "recipeRunId": null,
12768
12768
  "at": "2026-09-06T13:46:26.226+08:00"
12769
+ },
12770
+ {
12771
+ "id": "wh-85ff5529",
12772
+ "nodeId": "dw-d341d62e",
12773
+ "nodeName": "温度设定器·2号线(示例)",
12774
+ "param": "烘箱温度设定",
12775
+ "eng": 170,
12776
+ "raw": 170,
12777
+ "ok": true,
12778
+ "message": "Mock PLC 写入成功:170 → raw 170,回读一致(标定后物理值 170)",
12779
+ "recipeRunId": null,
12780
+ "at": "2026-09-06T19:24:52.674+08:00"
12781
+ },
12782
+ {
12783
+ "id": "wh-caa8f07a",
12784
+ "nodeId": "dw-d341d62e",
12785
+ "nodeName": "温度设定器·2号线(示例)",
12786
+ "param": "烘箱温度设定",
12787
+ "eng": 170,
12788
+ "raw": 170,
12789
+ "ok": true,
12790
+ "message": "Mock PLC 写入成功:170 → raw 170,回读一致(标定后物理值 170)",
12791
+ "recipeRunId": null,
12792
+ "at": "2026-09-06T19:25:01.709+08:00"
12769
12793
  }
12770
12794
  ]