agentworkshop 0.7.61 → 0.7.63

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/.AgentWorkShop/prompts/host-tools.json +2488 -2526
  2. package/.output/.AgentWorkShop/prompts/host-tools.json +2488 -2526
  3. package/.output/nitro.json +1 -1
  4. package/.output/public/_nuxt/{DKHA3XxF.js → B5RD2ZST.js} +1 -1
  5. package/.output/public/_nuxt/{CeEzUIvN.js → DAfWhONg.js} +2 -2
  6. package/.output/public/_nuxt/{analysis.DfMg76el.css → analysis.BwhKdel9.css} +1 -1
  7. package/.output/public/_nuxt/builds/latest.json +1 -1
  8. package/.output/public/_nuxt/builds/meta/3097fe87-dd0d-4037-b7bb-ead0620af56b.json +1 -0
  9. package/.output/server/chunks/_/nitro.mjs +2186 -2281
  10. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  11. package/.output/server/chunks/build/{analysis-MVEnlO7A.mjs → analysis-CPIxT0FP.mjs} +5 -5
  12. package/.output/server/chunks/build/{analysis-MVEnlO7A.mjs.map → analysis-CPIxT0FP.mjs.map} +1 -1
  13. package/.output/server/chunks/routes/renderer.mjs +1 -1
  14. package/.output/server/chunks/virtual/entry.mjs +1 -1
  15. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  16. package/.output/server/package.json +1 -1
  17. package/README-zh.md +946 -945
  18. package/README.md +970 -969
  19. package/app/components/analysis/AnalysisEditModal.vue +192 -192
  20. package/config.yml +180 -180
  21. package/docs/cli.en.md +447 -447
  22. package/docs/cli.md +412 -412
  23. package/docs/full-test-plan.md +1 -1
  24. package/docs/plugins.en.md +1 -1
  25. package/docs/plugins.md +1 -1
  26. package/docs/sdk.en.md +1 -1
  27. package/docs/sdk.md +1 -1
  28. package/package.json +181 -181
  29. package/scripts/e2e-plc-plugin-closedloop.mjs +1 -1
  30. package/server/api/workshop/analysis/[id].patch.ts +100 -100
  31. package/server/plugins-builtin/diag-bridge/host/diagnosis.mjs +4 -2
  32. package/server/plugins-builtin/diag-bridge/host/plugin.mjs +2 -0
  33. package/server/services/workshop/agents/host-tool-bridge/dispatch.ts +241 -243
  34. package/server/services/workshop/agents/host-tool-bridge/tools/industrial.ts +96 -98
  35. package/server/services/workshop/agents/industrial/daq-tools.ts +16 -7
  36. package/server/services/workshop/agents/industrial/dcw-tools.ts +210 -255
  37. package/server/services/workshop/agents/industrial/index.ts +32 -32
  38. package/server/services/workshop/agents/industrial/param-tools.ts +0 -40
  39. package/server/services/workshop/prompts/loader.ts +15 -2
  40. package/.output/public/_nuxt/builds/meta/eba8574d-1991-47df-944c-18608bb58181.json +0 -1
@@ -1,6 +1,6 @@
1
1
  # AgentWorkShop 全功能测试流程 Plan
2
2
 
3
- > 版本无关的常备测试手册(撰写时基线 v0.7.48)。用途:后续直接指令 agent
3
+ > 版本无关的常备测试手册(撰写时基线 v0.7.62)。用途:后续直接指令 agent
4
4
  > 「按 docs/full-test-plan.md 执行 Phase 0–N」即可完成全功能测试。
5
5
  > 断言数为历史全绿基线(2026-09 上旬各轮验收),以脚本实际输出为准;括号内数字仅用于识别明显回退。
6
6
  > 最后核对:2026-09-12(脚本清单逐一经 `scripts/` 实存核对)。
@@ -9,7 +9,7 @@
9
9
  >
10
10
  > Applies to: plugin system v2 has been available since **v0.7.29** (frontend component
11
11
  > injection / plugin settings / plugin i18n / runtime services surface); this document
12
- > describes **v0.7.58**. `ctx.sdkVersion` is currently `0.3.0`.
12
+ > describes **v0.7.63**. `ctx.sdkVersion` is currently `0.3.0`.
13
13
 
14
14
  ## 1. Folder layout & quick start
15
15
 
package/docs/plugins.md CHANGED
@@ -6,7 +6,7 @@
6
6
  > 本文是唯一权威参考;`docs/site/plugins/` 的分页文档与本文同源。
7
7
  >
8
8
  > 适用版本:插件系统 v2 自 **v0.7.29** 起可用(前端组件注入 / 插件设置 / 插件 i18n /
9
- > 运行时服务面);本文档对应当前版本 **v0.7.58**。`ctx.sdkVersion` 当前为 `0.3.0`。
9
+ > 运行时服务面);本文档对应当前版本 **v0.7.63**。`ctx.sdkVersion` 当前为 `0.3.0`。
10
10
 
11
11
  ## 一、目录结构与快速开始
12
12
 
package/docs/sdk.en.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  **SDK version constants**: server-side `SDK_VERSION = '0.3.0'`, browser-side `CLIENT_SDK_VERSION = '0.3.0'`.
9
9
  These two constants are the **interface version of the SDK itself** and evolve **independently**
10
- from the npm package version (the `version` field in `package.json`, currently 0.7.58) —
10
+ from the npm package version (the `version` field in `package.json`, currently 0.7.63) —
11
11
  them being out of sync is expected. Never use `SDK_VERSION` to infer the package version, or the reverse.
12
12
  **Module format**: ESM only (only `import` / `export`; there is no CJS entry).
13
13
  **Types**: `sdk/index.d.mts` and `sdk/client.d.mts` ship with the package, so TypeScript projects
package/docs/sdk.md CHANGED
@@ -5,7 +5,7 @@
5
5
  > 零第三方运行时依赖,Node ≥ 23.4 与现代浏览器双端可用。
6
6
 
7
7
  **SDK 版本常量**:服务端 `SDK_VERSION = '0.3.0'`,浏览器端 `CLIENT_SDK_VERSION = '0.3.0'`。
8
- 这两个常量是 **SDK 自身接口的版本号**,与 npm 包版本(`package.json` 的 `version`,当前 0.7.58)
8
+ 这两个常量是 **SDK 自身接口的版本号**,与 npm 包版本(`package.json` 的 `version`,当前 0.7.63)
9
9
  **各自独立演进** —— 常数不同步是预期行为,不要拿 `SDK_VERSION` 去推断包版本,反之亦然。
10
10
  **模块形态**:ESM only(只有 `import` / `export`,没有 CJS 入口)。
11
11
  **类型**:`sdk/index.d.mts`、`sdk/client.d.mts` 随包发布,TS 项目零配置获得提示(覆盖范围见 §7)。
package/package.json CHANGED
@@ -1,181 +1,181 @@
1
- {
2
- "name": "agentworkshop",
3
- "version": "0.7.61",
4
- "type": "module",
5
- "description": "AgentWorkShop 软件开发系统 - 基于 Nuxt 4 的配置驱动运行范式",
6
- "license": "Apache-2.0",
7
- "exports": {
8
- ".": {
9
- "types": "./sdk/index.d.mts",
10
- "default": "./sdk/index.mjs"
11
- },
12
- "./sdk": {
13
- "types": "./sdk/index.d.mts",
14
- "default": "./sdk/index.mjs"
15
- },
16
- "./sdk/client": {
17
- "types": "./sdk/client.d.mts",
18
- "default": "./sdk/client.mjs"
19
- },
20
- "./package.json": "./package.json"
21
- },
22
- "bin": {
23
- "aw": "bin/aw.mjs",
24
- "agentworkshop": "bin/aw.mjs"
25
- },
26
- "files": [
27
- ".output",
28
- "bin",
29
- "cli",
30
- "sdk",
31
- "app",
32
- "server",
33
- "shared",
34
- "i18n",
35
- "public",
36
- "scripts",
37
- ".AgentWorkShop/prompts",
38
- "server/plugins-builtin",
39
- "mcp",
40
- "config.yml",
41
- "nuxt.config.ts",
42
- "tsconfig.json",
43
- "uno.config.ts",
44
- "docker-compose.yml",
45
- ".env.example",
46
- "README-zh.md",
47
- "docs/cli.md",
48
- "docs/cli.en.md",
49
- "docs/plugins.md",
50
- "docs/plugins.en.md",
51
- "docs/sdk.md",
52
- "docs/sdk.en.md",
53
- "docs/aml.md",
54
- "docs/mcp.md",
55
- "docs/mcp.en.md",
56
- "docs/tui.md",
57
- "docs/full-test-plan.md",
58
- "docs/multi-harness-architecture.md",
59
- "tui"
60
- ],
61
- "packageManager": "pnpm@11.9.0",
62
- "engines": {
63
- "node": ">=23.4.0"
64
- },
65
- "scripts": {
66
- "dev": "node bin/aw.mjs dev",
67
- "build": "node bin/aw.mjs build",
68
- "start": "node bin/aw.mjs start",
69
- "generate": "nuxt generate",
70
- "preview": "node bin/aw.mjs start",
71
- "cli": "node bin/aw.mjs",
72
- "tui": "node tui/aw-tui.mjs",
73
- "postinstall": "node scripts/home-bootstrap.mjs",
74
- "prepublishOnly": "node bin/aw.mjs build",
75
- "lint": "eslint .",
76
- "lint:fix": "eslint . --fix",
77
- "typecheck": "node scripts/typecheck.mjs",
78
- "docs:check": "node scripts/check-docs-sync.mjs",
79
- "docs:dev": "cd docs/site && npx vitepress dev",
80
- "docs:build": "cd docs/site && npx vitepress build",
81
- "test:plugin-lifecycle": "node scripts/test-plugin-lifecycle.mjs",
82
- "test:sdk-surface": "node scripts/test-sdk-surface.mjs",
83
- "test:twin-provider": "tsx --test tests/aml-twin-provider-registry.test.ts",
84
- "test:unit": "tsx --tsconfig .nuxt/tsconfig.server.json --test --test-force-exit tests/*.test.ts",
85
- "prepare": "husky",
86
- "test:api-live": "node scripts/api-live-e2e.mjs",
87
- "test:mcp": "tsx --tsconfig .nuxt/tsconfig.server.json --test --test-force-exit tests/aw-mcp-server.test.ts",
88
- "test:skills": "node scripts/test-aw-skills.mjs",
89
- "test:mcp-live": "node scripts/_audit/aw-mcp-live-e2e.mjs",
90
- "test:skills-guided": "node scripts/_audit/skills-guided-e2e.mjs",
91
- "ui:seed": "node scripts/ui/seed-demo.mjs",
92
- "ui:shots": "node scripts/ui/shots.mjs",
93
- "ui:audit": "node scripts/ui/audit-layout.mjs",
94
- "ui:verify": "node scripts/ui/verify-responsive.mjs",
95
- "ui:verify-nav": "node scripts/ui/verify-nav.mjs",
96
- "readme:lint": "node scripts/ui/md-lint.mjs README.md README-zh.md",
97
- "readme:assets": "node scripts/ui/readme-assets.mjs",
98
- "game:verify": "node scripts/verify-game.mjs",
99
- "game:build-assets": "node scripts/build-player-sheet.mjs",
100
- "game:build-wuwa": "node scripts/build-wuwa-assets.mjs",
101
- "game:build-models": "node scripts/build-character-models.mjs",
102
- "game:build-world": "node scripts/build-world-map.mjs",
103
- "game:build-model3d": "node scripts/build-model-3d.mjs"
104
- },
105
- "lint-staged": {
106
- "*.{js,mjs,cjs,ts,vue}": "eslint --fix"
107
- },
108
- "dependencies": {
109
- "@ant-design-vue/nuxt": "^1.4.6",
110
- "@ant-design/icons-vue": "^7.0.1",
111
- "@anthropic-ai/claude-agent-sdk": "0.3.266",
112
- "@earendil-works/pi-tui": "^0.84.4",
113
- "@fontsource-variable/fraunces": "^5.3.0",
114
- "@fontsource-variable/geist": "^5.3.0",
115
- "@fontsource-variable/geist-mono": "^5.3.0",
116
- "@fontsource-variable/inter": "^5.3.0",
117
- "@fontsource/eb-garamond": "^5.3.0",
118
- "@fontsource/ibm-plex-mono": "^5.3.0",
119
- "@iconify-json/tabler": "^1.2.0",
120
- "@modelcontextprotocol/sdk": "^1.30.0",
121
- "@nuxtjs/i18n": "^9.0.0",
122
- "@pinia/nuxt": "^0.11.0",
123
- "@unocss/nuxt": "^66.0.0",
124
- "@unocss/preset-attributify": "^66.0.0",
125
- "@unocss/preset-icons": "^66.7.5",
126
- "@unocss/preset-typography": "^66.0.0",
127
- "@vueuse/core": "^13.0.0",
128
- "@vueuse/nuxt": "^13.0.0",
129
- "@xterm/addon-fit": "^0.11.0",
130
- "@xterm/xterm": "^6.0.0",
131
- "ant-design-vue": "^4.2.6",
132
- "axios": "^1.7.9",
133
- "echarts": "^5.6.0",
134
- "h3": "2.0.1-rc.26",
135
- "js-yaml": "^4.1.0",
136
- "minio": "^8.0.7",
137
- "modbus-serial": "^8.0.25",
138
- "mqtt": "^5.15.2",
139
- "node-opcua": "2.178.0",
140
- "nuxt": "^4.0.0",
141
- "nuxt-auth-utils": "^0.5.0",
142
- "pg": "^8.23.0",
143
- "phaser": "^4.0.0",
144
- "pinia": "^3.0.0",
145
- "pinia-plugin-persistedstate": "^4.2.0",
146
- "sqlite-vec": "^0.1.9",
147
- "three": "^0.185.1",
148
- "unocss": "^66.0.0",
149
- "unplugin-icons": "^22.0.0",
150
- "vue": "^3.5.13",
151
- "vue-echarts": "^7.0.3",
152
- "vue-router": "^4.5.0",
153
- "zod": "^3.24.1"
154
- },
155
- "optionalDependencies": {
156
- "onnxruntime-node": "^1.20.1",
157
- "serialport": "^13.0.0"
158
- },
159
- "devDependencies": {
160
- "@commitlint/cli": "^19.6.1",
161
- "@commitlint/config-conventional": "^19.6.0",
162
- "@nuxt/eslint": "^1.0.0",
163
- "@types/js-yaml": "^4.0.9",
164
- "@types/node": "^26.2.0",
165
- "@types/pg": "^8.23.1",
166
- "@types/three": "^0.185.4",
167
- "eslint": "^9.17.0",
168
- "husky": "^9.1.7",
169
- "lint-staged": "^15.3.0",
170
- "pngjs": "^7.0.0",
171
- "puppeteer-core": "^25.5.0",
172
- "tsx": "^4.23.12",
173
- "typescript": "^5.7.3",
174
- "vue-tsc": "^3.3.10"
175
- },
176
- "pnpm": {
177
- "ignoredBuiltDependencies": [
178
- "@serialport/bindings-cpp"
179
- ]
180
- }
181
- }
1
+ {
2
+ "name": "agentworkshop",
3
+ "version": "0.7.63",
4
+ "type": "module",
5
+ "description": "AgentWorkShop 软件开发系统 - 基于 Nuxt 4 的配置驱动运行范式",
6
+ "license": "Apache-2.0",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./sdk/index.d.mts",
10
+ "default": "./sdk/index.mjs"
11
+ },
12
+ "./sdk": {
13
+ "types": "./sdk/index.d.mts",
14
+ "default": "./sdk/index.mjs"
15
+ },
16
+ "./sdk/client": {
17
+ "types": "./sdk/client.d.mts",
18
+ "default": "./sdk/client.mjs"
19
+ },
20
+ "./package.json": "./package.json"
21
+ },
22
+ "bin": {
23
+ "aw": "bin/aw.mjs",
24
+ "agentworkshop": "bin/aw.mjs"
25
+ },
26
+ "files": [
27
+ ".output",
28
+ "bin",
29
+ "cli",
30
+ "sdk",
31
+ "app",
32
+ "server",
33
+ "shared",
34
+ "i18n",
35
+ "public",
36
+ "scripts",
37
+ ".AgentWorkShop/prompts",
38
+ "server/plugins-builtin",
39
+ "mcp",
40
+ "config.yml",
41
+ "nuxt.config.ts",
42
+ "tsconfig.json",
43
+ "uno.config.ts",
44
+ "docker-compose.yml",
45
+ ".env.example",
46
+ "README-zh.md",
47
+ "docs/cli.md",
48
+ "docs/cli.en.md",
49
+ "docs/plugins.md",
50
+ "docs/plugins.en.md",
51
+ "docs/sdk.md",
52
+ "docs/sdk.en.md",
53
+ "docs/aml.md",
54
+ "docs/mcp.md",
55
+ "docs/mcp.en.md",
56
+ "docs/tui.md",
57
+ "docs/full-test-plan.md",
58
+ "docs/multi-harness-architecture.md",
59
+ "tui"
60
+ ],
61
+ "packageManager": "pnpm@11.9.0",
62
+ "engines": {
63
+ "node": ">=23.4.0"
64
+ },
65
+ "scripts": {
66
+ "dev": "node bin/aw.mjs dev",
67
+ "build": "node bin/aw.mjs build",
68
+ "start": "node bin/aw.mjs start",
69
+ "generate": "nuxt generate",
70
+ "preview": "node bin/aw.mjs start",
71
+ "cli": "node bin/aw.mjs",
72
+ "tui": "node tui/aw-tui.mjs",
73
+ "postinstall": "node scripts/home-bootstrap.mjs",
74
+ "prepublishOnly": "node bin/aw.mjs build",
75
+ "lint": "eslint .",
76
+ "lint:fix": "eslint . --fix",
77
+ "typecheck": "node scripts/typecheck.mjs",
78
+ "docs:check": "node scripts/check-docs-sync.mjs",
79
+ "docs:dev": "cd docs/site && npx vitepress dev",
80
+ "docs:build": "cd docs/site && npx vitepress build",
81
+ "test:plugin-lifecycle": "node scripts/test-plugin-lifecycle.mjs",
82
+ "test:sdk-surface": "node scripts/test-sdk-surface.mjs",
83
+ "test:twin-provider": "tsx --test tests/aml-twin-provider-registry.test.ts",
84
+ "test:unit": "tsx --tsconfig .nuxt/tsconfig.server.json --test --test-force-exit tests/*.test.ts",
85
+ "prepare": "husky",
86
+ "test:api-live": "node scripts/api-live-e2e.mjs",
87
+ "test:mcp": "tsx --tsconfig .nuxt/tsconfig.server.json --test --test-force-exit tests/aw-mcp-server.test.ts",
88
+ "test:skills": "node scripts/test-aw-skills.mjs",
89
+ "test:mcp-live": "node scripts/_audit/aw-mcp-live-e2e.mjs",
90
+ "test:skills-guided": "node scripts/_audit/skills-guided-e2e.mjs",
91
+ "ui:seed": "node scripts/ui/seed-demo.mjs",
92
+ "ui:shots": "node scripts/ui/shots.mjs",
93
+ "ui:audit": "node scripts/ui/audit-layout.mjs",
94
+ "ui:verify": "node scripts/ui/verify-responsive.mjs",
95
+ "ui:verify-nav": "node scripts/ui/verify-nav.mjs",
96
+ "readme:lint": "node scripts/ui/md-lint.mjs README.md README-zh.md",
97
+ "readme:assets": "node scripts/ui/readme-assets.mjs",
98
+ "game:verify": "node scripts/verify-game.mjs",
99
+ "game:build-assets": "node scripts/build-player-sheet.mjs",
100
+ "game:build-wuwa": "node scripts/build-wuwa-assets.mjs",
101
+ "game:build-models": "node scripts/build-character-models.mjs",
102
+ "game:build-world": "node scripts/build-world-map.mjs",
103
+ "game:build-model3d": "node scripts/build-model-3d.mjs"
104
+ },
105
+ "lint-staged": {
106
+ "*.{js,mjs,cjs,ts,vue}": "eslint --fix"
107
+ },
108
+ "dependencies": {
109
+ "@ant-design-vue/nuxt": "^1.4.6",
110
+ "@ant-design/icons-vue": "^7.0.1",
111
+ "@anthropic-ai/claude-agent-sdk": "0.3.266",
112
+ "@earendil-works/pi-tui": "^0.84.4",
113
+ "@fontsource-variable/fraunces": "^5.3.0",
114
+ "@fontsource-variable/geist": "^5.3.0",
115
+ "@fontsource-variable/geist-mono": "^5.3.0",
116
+ "@fontsource-variable/inter": "^5.3.0",
117
+ "@fontsource/eb-garamond": "^5.3.0",
118
+ "@fontsource/ibm-plex-mono": "^5.3.0",
119
+ "@iconify-json/tabler": "^1.2.0",
120
+ "@modelcontextprotocol/sdk": "^1.30.0",
121
+ "@nuxtjs/i18n": "^9.0.0",
122
+ "@pinia/nuxt": "^0.11.0",
123
+ "@unocss/nuxt": "^66.0.0",
124
+ "@unocss/preset-attributify": "^66.0.0",
125
+ "@unocss/preset-icons": "^66.7.5",
126
+ "@unocss/preset-typography": "^66.0.0",
127
+ "@vueuse/core": "^13.0.0",
128
+ "@vueuse/nuxt": "^13.0.0",
129
+ "@xterm/addon-fit": "^0.11.0",
130
+ "@xterm/xterm": "^6.0.0",
131
+ "ant-design-vue": "^4.2.6",
132
+ "axios": "^1.7.9",
133
+ "echarts": "^5.6.0",
134
+ "h3": "2.0.1-rc.26",
135
+ "js-yaml": "^4.1.0",
136
+ "minio": "^8.0.7",
137
+ "modbus-serial": "^8.0.25",
138
+ "mqtt": "^5.15.2",
139
+ "node-opcua": "2.178.0",
140
+ "nuxt": "^4.0.0",
141
+ "nuxt-auth-utils": "^0.5.0",
142
+ "pg": "^8.23.0",
143
+ "phaser": "^4.0.0",
144
+ "pinia": "^3.0.0",
145
+ "pinia-plugin-persistedstate": "^4.2.0",
146
+ "sqlite-vec": "^0.1.9",
147
+ "three": "^0.185.1",
148
+ "unocss": "^66.0.0",
149
+ "unplugin-icons": "^22.0.0",
150
+ "vue": "^3.5.13",
151
+ "vue-echarts": "^7.0.3",
152
+ "vue-router": "^4.5.0",
153
+ "zod": "^3.24.1"
154
+ },
155
+ "optionalDependencies": {
156
+ "onnxruntime-node": "^1.20.1",
157
+ "serialport": "^13.0.0"
158
+ },
159
+ "devDependencies": {
160
+ "@commitlint/cli": "^19.6.1",
161
+ "@commitlint/config-conventional": "^19.6.0",
162
+ "@nuxt/eslint": "^1.0.0",
163
+ "@types/js-yaml": "^4.0.9",
164
+ "@types/node": "^26.2.0",
165
+ "@types/pg": "^8.23.1",
166
+ "@types/three": "^0.185.4",
167
+ "eslint": "^9.17.0",
168
+ "husky": "^9.1.7",
169
+ "lint-staged": "^15.3.0",
170
+ "pngjs": "^7.0.0",
171
+ "puppeteer-core": "^25.5.0",
172
+ "tsx": "^4.23.12",
173
+ "typescript": "^5.7.3",
174
+ "vue-tsc": "^3.3.10"
175
+ },
176
+ "pnpm": {
177
+ "ignoredBuiltDependencies": [
178
+ "@serialport/bindings-cpp"
179
+ ]
180
+ }
181
+ }
@@ -535,7 +535,7 @@ console.log('\n── H Harness 集成面 ──')
535
535
  const names = (list?.json?.data?.tools ?? list?.json?.tools ?? []).map(t => t?.name)
536
536
  // rag 侧工具面已收敛为单入口 kb_agent(+kb_agent_status);diag 侧仍是 diag_run/diag_status
537
537
  for (const t of ['kb_agent', 'kb_agent_status', 'diag_run', 'diag_status']) ok(names.includes(t), `omp 执行器工具清单含 ${t}`)
538
- for (const t of ['daq_query', 'dcw_control', 'dcw_judge', 'dcw_read', 'line_context']) ok(names.includes(t), `omp 执行器工业工具含 ${t}`)
538
+ for (const t of ['daq_query', 'dcw_control', 'dcw_judge', 'line_context']) ok(names.includes(t), `omp 执行器工业工具含 ${t}`)
539
539
  const ctxT = await invoke(exec, 'line_context', {}, 60000)
540
540
  ok(!resultText(ctxT).startsWith('工具') || resultText(ctxT).length > 0, 'line_context 可用(工业链路)', resultText(ctxT).slice(0, 60))
541
541
  }
@@ -1,100 +1,100 @@
1
- /**
2
- * PATCH /api/workshop/analysis/:id —— 人工修订分析报告(v27 编辑面)。
3
- * 权限:admin,或对该报告产线有「可操控」(operate)的用户;readonly/无授权 403。
4
- * 可编辑字段:title/category/summary/conclusions/report/metrics/recipe_id/recipe_version/
5
- * window_from/window_to/data_sources(缺省 = 保留原值);修订归因固化进 updated_*。
6
- * Agent 面仍无改删 —— 编辑是带审计的人类管理操作(recordOps analysis.update)。
7
- */
8
- import { getQuery, getRouterParam, readBody } from 'h3'
9
- import { resolveUser } from '@/server/api/workshop/caller'
10
- import { defineApiHandler } from '@/server/utils/response'
11
- import { AppError } from '@/server/utils/errors'
12
- import { lineMode } from '@/server/services/workshop/permissions'
13
- import { getAnalysisRepo } from '@/server/services/workshop/analysis/analysis.repo'
14
- import { getDcwRecipeRepo } from '@/server/services/workshop/dcw/dcw-recipe.repo'
15
- import { recordOps } from '@/server/services/workshop/ops/ops'
16
-
17
- export default defineApiHandler(async (event) => {
18
- const user = resolveUser(event)
19
- const id = getRouterParam(event, 'id')!
20
- const repo = getAnalysisRepo()
21
- const report = repo.get(id)
22
- if (!report) throw new AppError(404, 'NOT_FOUND', `分析报告不存在: ${id}`)
23
-
24
- // 编辑权限:admin 或产线 operate(readonly/无授权不可改)
25
- const isAdmin = user.role === 'admin'
26
- if (!isAdmin && (!report.lineId || lineMode(user, report.lineId) !== 'operate')) {
27
- throw new AppError(403, 'ANALYSIS_FORBIDDEN', `无权修订该分析报告:需要产线「可操控」权限或 admin(报告产线 ${report.lineName || report.lineId || '-'})`)
28
- }
29
-
30
- const body = (await readBody<Record<string, unknown>>(event)) ?? {}
31
- const str = (k: string): string | undefined => (body[k] === undefined ? undefined : String(body[k] ?? '').trim())
32
- const title = str('title')
33
- const summary = str('summary')
34
- if (title !== undefined && !title) throw new AppError(400, 'VALIDATION_ERROR', 'title 不能为空')
35
- if (summary !== undefined && !summary) throw new AppError(400, 'VALIDATION_ERROR', 'summary 不能为空')
36
-
37
- // 配方校验(与保存面同口径:存在且归属该产线)
38
- const recipeId = str('recipe_id')
39
- if (recipeId) {
40
- const recipe = getDcwRecipeRepo().list().find(r => r.id === recipeId)
41
- if (!recipe) throw new AppError(404, 'NOT_FOUND', `配方不存在: ${recipeId}`)
42
- if (recipe.lineId && report.lineId && recipe.lineId !== report.lineId) {
43
- throw new AppError(400, 'VALIDATION_ERROR', `配方「${recipe.name}」不属于该报告的产线`)
44
- }
45
- }
46
-
47
- // 时间窗归一:列内为本地 ISO(平台 toISOString 补丁),外部 Z 格式/epoch ms 归一后入库
48
- const timeArg = (k: string): string | null | undefined => {
49
- if (body[k] === undefined) return undefined
50
- const raw = String(body[k] ?? '').trim()
51
- if (!raw) return null
52
- const ms = /^\d{10,}$/.test(raw) ? Number(raw) : Date.parse(raw)
53
- if (!Number.isFinite(ms)) throw new AppError(400, 'VALIDATION_ERROR', `${k} 时间格式无效(ISO 8601 或 epoch ms)`)
54
- return new Date(ms).toISOString()
55
- }
56
-
57
- const conclusions = body.conclusions === undefined
58
- ? undefined
59
- : (Array.isArray(body.conclusions) ? body.conclusions : String(body.conclusions ?? '').split('\n'))
60
- .map((x: unknown) => String(x).replace(/^[-*\d.\s]+/, '').trim())
61
- .filter(Boolean)
62
- let metrics: Record<string, unknown> | undefined
63
- if (body.metrics !== undefined && body.metrics !== null && String(body.metrics).trim() !== '') {
64
- try {
65
- metrics = typeof body.metrics === 'object' && !Array.isArray(body.metrics)
66
- ? (body.metrics as Record<string, unknown>)
67
- : JSON.parse(String(body.metrics))
68
- }
69
- catch {
70
- throw new AppError(400, 'VALIDATION_ERROR', 'metrics 需为 JSON 对象(或留空保留原值)')
71
- }
72
- }
73
-
74
- const updated = repo.update(id, {
75
- title: title ?? undefined,
76
- category: str('category') ?? undefined,
77
- summary: summary ?? undefined,
78
- conclusions,
79
- report: body.report === undefined ? undefined : String(body.report ?? ''),
80
- metrics,
81
- recipeId,
82
- recipeVersion: str('recipe_version'),
83
- windowFrom: timeArg('window_from'),
84
- windowTo: timeArg('window_to'),
85
- dataSources: str('data_sources'),
86
- }, { id: user.id, name: user.name })
87
- if (!updated) throw new AppError(404, 'NOT_FOUND', `分析报告不存在: ${id}`)
88
-
89
- try {
90
- recordOps({
91
- actor: user.id, actorName: user.name, actorKind: 'user',
92
- action: 'analysis.update', kind: 'analysis', targetKind: 'analysis', targetId: id,
93
- lineId: updated.lineId, recipeId: updated.recipeId,
94
- summary: `人工修订分析报告「${updated.title}」(产线「${updated.lineName || updated.lineId || '-'}」)`,
95
- })
96
- }
97
- catch { /* 审计失败不阻断 */ }
98
-
99
- return { report: updated }
100
- })
1
+ /**
2
+ * PATCH /api/workshop/analysis/:id —— 人工修订分析报告(v27 编辑面)。
3
+ * 权限:admin,或对该报告产线有「可操控」(operate)的用户;readonly/无授权 403。
4
+ * 可编辑字段:title/category/summary/conclusions/report/metrics/recipe_id/recipe_version/
5
+ * window_from/window_to/data_sources(缺省 = 保留原值);修订归因固化进 updated_*。
6
+ * Agent 面仍无改删 —— 编辑是带审计的人类管理操作(recordOps analysis.update)。
7
+ */
8
+ import { getRouterParam, readBody } from 'h3'
9
+ import { resolveUser } from '@/server/api/workshop/caller'
10
+ import { defineApiHandler } from '@/server/utils/response'
11
+ import { AppError } from '@/server/utils/errors'
12
+ import { lineMode } from '@/server/services/workshop/permissions'
13
+ import { getAnalysisRepo } from '@/server/services/workshop/analysis/analysis.repo'
14
+ import { getDcwRecipeRepo } from '@/server/services/workshop/dcw/dcw-recipe.repo'
15
+ import { recordOps } from '@/server/services/workshop/ops/ops'
16
+
17
+ export default defineApiHandler(async (event) => {
18
+ const user = resolveUser(event)
19
+ const id = getRouterParam(event, 'id')!
20
+ const repo = getAnalysisRepo()
21
+ const report = repo.get(id)
22
+ if (!report) throw new AppError(404, 'NOT_FOUND', `分析报告不存在: ${id}`)
23
+
24
+ // 编辑权限:admin 或产线 operate(readonly/无授权不可改)
25
+ const isAdmin = user.role === 'admin'
26
+ if (!isAdmin && (!report.lineId || lineMode(user, report.lineId) !== 'operate')) {
27
+ throw new AppError(403, 'ANALYSIS_FORBIDDEN', `无权修订该分析报告:需要产线「可操控」权限或 admin(报告产线 ${report.lineName || report.lineId || '-'})`)
28
+ }
29
+
30
+ const body = (await readBody<Record<string, unknown>>(event)) ?? {}
31
+ const str = (k: string): string | undefined => (body[k] === undefined ? undefined : String(body[k] ?? '').trim())
32
+ const title = str('title')
33
+ const summary = str('summary')
34
+ if (title !== undefined && !title) throw new AppError(400, 'VALIDATION_ERROR', 'title 不能为空')
35
+ if (summary !== undefined && !summary) throw new AppError(400, 'VALIDATION_ERROR', 'summary 不能为空')
36
+
37
+ // 配方校验(与保存面同口径:存在且归属该产线)
38
+ const recipeId = str('recipe_id')
39
+ if (recipeId) {
40
+ const recipe = getDcwRecipeRepo().list().find(r => r.id === recipeId)
41
+ if (!recipe) throw new AppError(404, 'NOT_FOUND', `配方不存在: ${recipeId}`)
42
+ if (recipe.lineId && report.lineId && recipe.lineId !== report.lineId) {
43
+ throw new AppError(400, 'VALIDATION_ERROR', `配方「${recipe.name}」不属于该报告的产线`)
44
+ }
45
+ }
46
+
47
+ // 时间窗归一:列内为本地 ISO(平台 toISOString 补丁),外部 Z 格式/epoch ms 归一后入库
48
+ const timeArg = (k: string): string | null | undefined => {
49
+ if (body[k] === undefined) return undefined
50
+ const raw = String(body[k] ?? '').trim()
51
+ if (!raw) return null
52
+ const ms = /^\d{10,}$/.test(raw) ? Number(raw) : Date.parse(raw)
53
+ if (!Number.isFinite(ms)) throw new AppError(400, 'VALIDATION_ERROR', `${k} 时间格式无效(ISO 8601 或 epoch ms)`)
54
+ return new Date(ms).toISOString()
55
+ }
56
+
57
+ const conclusions = body.conclusions === undefined
58
+ ? undefined
59
+ : (Array.isArray(body.conclusions) ? body.conclusions : String(body.conclusions ?? '').split('\n'))
60
+ .map((x: unknown) => String(x).replace(/^[-*\d.\s]+/, '').trim())
61
+ .filter(Boolean)
62
+ let metrics: Record<string, unknown> | undefined
63
+ if (body.metrics !== undefined && body.metrics !== null && String(body.metrics).trim() !== '') {
64
+ try {
65
+ metrics = typeof body.metrics === 'object' && !Array.isArray(body.metrics)
66
+ ? (body.metrics as Record<string, unknown>)
67
+ : JSON.parse(String(body.metrics))
68
+ }
69
+ catch {
70
+ throw new AppError(400, 'VALIDATION_ERROR', 'metrics 需为 JSON 对象(或留空保留原值)')
71
+ }
72
+ }
73
+
74
+ const updated = repo.update(id, {
75
+ title: title ?? undefined,
76
+ category: str('category') ?? undefined,
77
+ summary: summary ?? undefined,
78
+ conclusions,
79
+ report: body.report === undefined ? undefined : String(body.report ?? ''),
80
+ metrics,
81
+ recipeId,
82
+ recipeVersion: str('recipe_version'),
83
+ windowFrom: timeArg('window_from'),
84
+ windowTo: timeArg('window_to'),
85
+ dataSources: str('data_sources'),
86
+ }, { id: user.id, name: user.name })
87
+ if (!updated) throw new AppError(404, 'NOT_FOUND', `分析报告不存在: ${id}`)
88
+
89
+ try {
90
+ recordOps({
91
+ actor: user.id, actorName: user.name, actorKind: 'user',
92
+ action: 'analysis.update', kind: 'analysis', targetKind: 'analysis', targetId: id,
93
+ lineId: updated.lineId, recipeId: updated.recipeId,
94
+ summary: `人工修订分析报告「${updated.title}」(产线「${updated.lineName || updated.lineId || '-'}」)`,
95
+ })
96
+ }
97
+ catch { /* 审计失败不阻断 */ }
98
+
99
+ return { report: updated }
100
+ })