abelien-harness 0.4.0 → 0.6.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 (104) hide show
  1. package/.env.example +4 -0
  2. package/README.md +11 -18
  3. package/package.json +2 -3
  4. package/skills/abelien-appearance/SKILL.md +1 -0
  5. package/skills/abelien-clarify/SKILL.md +12 -2
  6. package/skills/abelien-clarify/references/examples.md +22 -0
  7. package/skills/abelien-clarify/scripts/check_result.py +38 -3
  8. package/skills/abelien-clarify/scripts/test_check_result.py +32 -1
  9. package/skills/abelien-guide/SKILL.md +1 -1
  10. package/skills/abelien-hardware/SKILL.md +10 -5
  11. package/skills/abelien-hardware/domain.json +3 -3
  12. package/skills/abelien-hardware/references/search-index-format.md +13 -1
  13. package/skills/abelien-hardware/references/search-index-release.md +4 -2
  14. package/skills/abelien-hardware/references/web-evidence-contract.md +3 -3
  15. package/skills/abelien-hardware/scripts/dimensions.mjs +23 -8
  16. package/skills/abelien-hardware/scripts/electrical.mjs +168 -0
  17. package/skills/abelien-hardware/scripts/finalize-selection.mjs +4 -2
  18. package/skills/abelien-hardware/scripts/provider-chain-contract.mjs +27 -6
  19. package/skills/abelien-hardware/scripts/public-page.mjs +11 -121
  20. package/skills/abelien-hardware/scripts/response-redaction.mjs +1 -130
  21. package/skills/abelien-hardware/scripts/search-index-release.mjs +30 -17
  22. package/skills/abelien-hardware/scripts/selection-request.mjs +6 -5
  23. package/skills/abelien-hardware/scripts/tos-wiki-search.mjs +13 -8
  24. package/skills/abelien-hardware/scripts/volc-web-search.mjs +10 -27
  25. package/skills/abelien-hardware/scripts/web-common.mjs +8 -11
  26. package/skills/abelien-hardware/scripts/web-integrity.mjs +1 -1
  27. package/skills/abelien-hardware/scripts/web-provider-chain.mjs +10 -3
  28. package/skills/abelien-hardware/scripts/web-receipt.mjs +4 -2
  29. package/skills/abelien-hardware/scripts/web-search-plan.mjs +21 -2
  30. package/skills/abelien-hardware/scripts/web-search.mjs +5 -2
  31. package/skills/abelien-hardware-selection/SKILL.md +1 -1
  32. package/skills/abelien-hardware-selection/domain.json +2 -2
  33. package/skills/abelien-hardware-selection/references/selection-service-contract.md +30 -3
  34. package/skills/abelien-hardware-selection/scripts/select.mjs +35 -8
  35. package/skills/abelien-harness/scripts/ab.mjs +24 -2
  36. package/skills/abelien-harness/scripts/web/common.mjs +20 -0
  37. package/skills/abelien-harness/scripts/web/public-read.mjs +168 -0
  38. package/skills/abelien-harness/scripts/web/redact.mjs +136 -0
  39. package/skills/abelien-harness/scripts/web/volc.mjs +49 -0
  40. package/skills/abelien-reference/SKILL.md +51 -0
  41. package/skills/abelien-reference/domain.json +92 -0
  42. package/skills/abelien-reference/fixtures/create.final.json +102 -0
  43. package/skills/abelien-reference/fixtures/restore.collected.json +189 -0
  44. package/skills/abelien-reference/fixtures/restore.final.json +267 -0
  45. package/skills/abelien-reference/references/research-contract.md +74 -0
  46. package/skills/abelien-reference/schemas/reference-evidence.v1.json +140 -0
  47. package/skills/abelien-reference/scripts/evidence.mjs +60 -0
  48. package/skills/abelien-reference/scripts/finalize.mjs +116 -0
  49. package/skills/abelien-reference/scripts/measure.mjs +62 -0
  50. package/skills/abelien-reference/scripts/png.mjs +86 -0
  51. package/skills/abelien-reference/scripts/research.mjs +179 -0
  52. package/skills/abelien-structure/SKILL.md +2 -2
  53. package/skills/abelien-structure/domain.json +64 -0
  54. package/skills/abelien-structure/references/build123d-execution.md +1 -1
  55. package/skills/abelien-structure/references/handoff.md +1 -1
  56. package/skills/abelien-structure/worker/abelien_cad.py +585 -0
  57. package/skills/abelien-structure/worker/assembly-validation.mjs +106 -0
  58. package/skills/abelien-structure/worker/cad.py +1623 -0
  59. package/skills/abelien-structure/worker/cli-adapter.mjs +207 -0
  60. package/skills/abelien-structure/worker/component-fit-glb.mjs +173 -0
  61. package/skills/abelien-structure/worker/component-fit.d.mts +82 -0
  62. package/skills/abelien-structure/worker/component-fit.mjs +167 -0
  63. package/skills/abelien-structure/worker/component-target-image.d.mts +23 -0
  64. package/skills/abelien-structure/worker/component-target-image.mjs +107 -0
  65. package/skills/abelien-structure/worker/component-target-render.py +58 -0
  66. package/skills/abelien-structure/worker/config.mjs +6 -0
  67. package/skills/abelien-structure/worker/engineering-fit.d.mts +48 -0
  68. package/skills/abelien-structure/worker/engineering-fit.mjs +118 -0
  69. package/skills/abelien-structure/worker/engineering-policy.json +16 -0
  70. package/skills/abelien-structure/worker/engineering-repair.py +147 -0
  71. package/skills/abelien-structure/worker/engineering.py +324 -0
  72. package/skills/abelien-structure/worker/identity.mjs +98 -0
  73. package/skills/abelien-structure/worker/inspection-geometry.mjs +71 -0
  74. package/skills/abelien-structure/worker/jobs.mjs +451 -0
  75. package/skills/abelien-structure/worker/library-runtime.mjs +15 -0
  76. package/skills/abelien-structure/worker/main.mjs +102 -0
  77. package/skills/abelien-structure/worker/manifest-digest.mjs +11 -0
  78. package/skills/abelien-structure/worker/materials.mjs +52 -0
  79. package/skills/abelien-structure/worker/native-launcher.py +13 -0
  80. package/skills/abelien-structure/worker/native.mjs +157 -0
  81. package/skills/abelien-structure/worker/representation.mjs +47 -0
  82. package/skills/abelien-structure/worker/sandbox.mjs +41 -0
  83. package/skills/abelien-structure/worker/source-contract.mjs +143 -0
  84. package/skills/abelien-structure/worker/source_call_stats.py +59 -0
  85. package/skills/abelien-structure/worker/supervisor.mjs +38 -0
  86. package/skills/abelien-workspace/SKILL.md +11 -0
  87. package/skills/abelien-workspace/assets/journey-stage-plan.json +155 -0
  88. package/skills/abelien-workspace/domain.json +25 -2
  89. package/skills/abelien-workspace/references/hardware-journey-orchestration.md +1 -1
  90. package/skills/abelien-workspace/references/harness-binding.md +2 -2
  91. package/skills/abelien-workspace/references/user-journey.md +10 -0
  92. package/skills/abelien-workspace/scripts/journey-next.mjs +38 -0
  93. package/skills/abelien-workspace/workflows/definitions/0852e4949f5a6246880c1a26bf5ccaa42f8cda06b960e7c7ce234a0a176878f9.json +229 -0
  94. package/skills/abelien-workspace/workflows/definitions/399ef372790b7330d0ef88ce5096e7f69943d4793de97b2ed6c25165a332612f.json +230 -0
  95. package/skills/abelien-workspace/workflows/definitions/591a7f21e0b0ad586e340163f7533ac910356091ba8d2a26e250c0acbc80cd8b.json +176 -0
  96. package/skills/abelien-workspace/workflows/definitions/7c69ea0d51099b1ae947f08b056ea67f5cad6b40ae8bcb00efb496fa5b9d5ed3.json +149 -0
  97. package/skills/abelien-workspace/workflows/definitions/9b5c65ad03fdecc0148931a7677cfa684a3fb04ab2738d6f7a1086a2c79ac86c.json +149 -0
  98. package/skills/abelien-workspace/workflows/definitions/c1b5c6c653f0c4761d51efee923aafbbeea05512e7f35c60f7f7d36ec49fc1d1.json +229 -0
  99. package/skills/abelien-workspace/workflows/definitions/d9f8c6cdf0b2c41cdeb1c72ac5d1e37d95a7caac3272d434a3c7e8483fc565de.json +150 -0
  100. package/skills/abelien-workspace/workflows/definitions/e391e14c14cb39408a0a9e226ed54ffab7a36badea305ae4a3eafbac8124fc02.json +175 -0
  101. package/skills/abelien-workspace/workflows/definitions/fd8ce7074e2044985778446e93153864940bb9465471c1c71c41328cefff70bf.json +175 -0
  102. package/skills/abelien-workspace/workflows/user-journey-hardware-algorithm.json +5 -4
  103. package/skills/abelien-workspace/workflows/user-journey-hardware-candidates.json +5 -4
  104. package/skills/abelien-workspace/workflows/user-journey-hardware.json +5 -4
@@ -0,0 +1,155 @@
1
+ {
2
+ "schema": "abelien.journey-stage-plan.v1",
3
+ "plan_version": "2026-10-12.2",
4
+ "description": "按意图的作品旅程阶段计划。orders 是自动推进的主线;side 阶段由宿主守卫按真实结果触发。每个阶段的 directives 是领域规则(宿主中立),宿主把它们附在自己的执行说明(工具名、字段)之后,不改写、不删减。",
5
+ "artifacts": ["reference_final", "concept_image", "hardware", "appearance_baseline", "cad_candidate", "review"],
6
+ "orders": {
7
+ "create": ["reference", "concept", "hardware", "real_image", "cad", "review"],
8
+ "restore": ["identify", "hardware", "real_image", "cad", "review"],
9
+ "modify": ["identify", "concept", "hardware", "real_image", "cad", "review"],
10
+ "remix": ["concept", "real_image", "cad", "review"]
11
+ },
12
+ "completion": {
13
+ "identify": "reference_final",
14
+ "reference": "reference_final",
15
+ "concept": "concept_image",
16
+ "hardware": "hardware",
17
+ "real_image": "appearance_baseline",
18
+ "cad": "cad_candidate",
19
+ "review": "review"
20
+ },
21
+ "side": ["hardware_reselect", "hardware_decision", "fallback", "repair", "questions"],
22
+ "stages": {
23
+ "identify": {
24
+ "goal": "识别用户要的现成产品,并取得规格与逆向资料",
25
+ "directives": [
26
+ "调用 reference.research 执行识别与逆向资料检索(用途 identify / teardown;用户给了链接时先读链接),再读取证据,用 reference.finalize 提交识别判断。",
27
+ "识别不确定时按最可能的候选继续,保留其他候选供用户切换;不向用户提问。",
28
+ "完成后用一两句话说明识别为哪款产品、依据是什么,以及比例核对结果。"
29
+ ]
30
+ },
31
+ "reference": {
32
+ "goal": "检索相似产品,作为尺寸、结构、器件与实现方式的参考",
33
+ "directives": [
34
+ "调用 reference.research 检索相似产品(用途 similar),再读取证据,用 reference.finalize 提交借用什么、为什么合适、哪些不照搬。",
35
+ "找不到完整的相似产品时,按声学、供电、交互等子系统分别参考,不硬凑数量;不向用户提问。",
36
+ "相似产品只作参考,不成为可编辑模板,也不自动采用其 BOM。"
37
+ ]
38
+ },
39
+ "concept": {
40
+ "goal": "生成第一张概念图",
41
+ "directives": [
42
+ "按外观目标生成第一张概念图;需求没说到的外观细节按常见做法补全,不向用户提问。",
43
+ "出图后用一两句话告诉用户并结束本轮,硬件选型在下一阶段进行。"
44
+ ],
45
+ "variants": {
46
+ "modify": [
47
+ "以识别出的原产品图为输入生成修改后的图,只改用户要求修改的部分,保留清单中的特征。",
48
+ "出图后用一两句话说明改了什么、保留了什么,并结束本轮;硬件选型在下一阶段进行。"
49
+ ]
50
+ }
51
+ },
52
+ "hardware": {
53
+ "goal": "为当前需求选型并登记",
54
+ "directives": [
55
+ "主要元器件选定即可;供电、电池、联网方式等用户没说的未定项按推荐默认值选型,并作为待确认项登记,不向用户提问。",
56
+ "不要修改需求,也不要出图。",
57
+ "登记后用一两句话说明选了什么、哪些按默认值处理,然后结束本轮;待确认项在首版之后合并成一张问题卡统一询问。"
58
+ ],
59
+ "variants": {
60
+ "restore": [
61
+ "以参考证据中的来源产品规格与拆解资料为对照逐项选择替代件,区分原件、替代件与未知;主要元器件选定即可,未定项按推荐默认值登记为待确认项,不向用户提问。",
62
+ "不要修改需求,也不要出图。",
63
+ "登记后用一两句话说明替代关系与默认值,然后结束本轮;待确认项在首版之后合并成一张问题卡统一询问。"
64
+ ]
65
+ }
66
+ },
67
+ "hardware_reselect": {
68
+ "goal": "当前硬件放不下用户的硬尺寸上限或锁定分区时重新选型",
69
+ "directives": [
70
+ "沿用当前需求的尺寸上限与尺寸检查重新选型,选择能装下的更小型号并登记;不要放宽用户尺寸,不要修改其他需求,不要出图。",
71
+ "旧选型只作来源证据,不能原样重新登记。",
72
+ "没有能装下的候选时,发一张问题卡,让用户在“换件”和“放宽尺寸”之间选择。"
73
+ ],
74
+ "locks": {
75
+ "shape": {
76
+ "true": "外形已锁定:槽位的 locked 分区(fit_envelope)同样不得放宽。没有能装下的候选时,先由结构在锁定外形内调整骨架(分区、层高、朝向)并给出新的 fit_envelope 后再选,仍装不下才发问题卡;此时“放宽尺寸”就是改外形,记为外观偏差。"
77
+ }
78
+ }
79
+ },
80
+ "hardware_decision": {
81
+ "goal": "硬尺寸上限下没有能装下的候选,交用户取舍",
82
+ "directives": [
83
+ "本轮不重新选型、不修改需求、不出图;只发一张问题卡,让用户在“换件”和“放宽尺寸”之间选择,然后结束本轮。"
84
+ ]
85
+ },
86
+ "real_image": {
87
+ "goal": "把外观基准图与当前硬件绑定",
88
+ "directives": [
89
+ "将可复用的概念图绑定当前硬件,作为外观基准;缺少可用图片时回到概念图阶段,不在绑定阶段生图。",
90
+ "用户明确要求重画时,在用户回合准备新的图片版本,保留原产物。",
91
+ "不要修改需求;待答的问题卡保持原样,不代用户回答。"
92
+ ],
93
+ "variants": {
94
+ "restore": [
95
+ "将参考证据中识别出的真实产品图绑定当前硬件,作为外观基准;还原路径不生成概念图。",
96
+ "用户明确要求重画时,在用户回合准备新的图片版本,保留原产物。",
97
+ "不要修改需求;待答的问题卡保持原样,不代用户回答。"
98
+ ]
99
+ }
100
+ },
101
+ "cad": {
102
+ "goal": "形成可旋转的首版 CAD",
103
+ "directives": [
104
+ "优先快速形成可旋转的首版,结合外观基准图与真实硬件重建。",
105
+ "不缩放任何原生元器件;组件优先复用可信 CAD 的原生比例,只有缺少真实资产的项才明确标为包络;缺失的尺寸不要当作已知值。",
106
+ "坐落件相对结构骨架的基准面放置,不为每个组件手填独立的绝对坐标。",
107
+ "保留外观基准图的轮廓、长宽厚比例、圆角、屏幕和按钮相对位置及材质,按匹配的参考视角输出实际渲染,不用通用方盒替代。",
108
+ "失败就按回执诊断修正后重试;同一错误连续出现时换一种实现方式。",
109
+ "不要重新登记硬件、不要修改需求或重新出图;视觉审查在下一阶段进行;待答的问题卡保持原样,不代用户回答。"
110
+ ],
111
+ "locks": {
112
+ "shape": {
113
+ "false": "硬件放得下优先;冲突时可以等比例放大外壳,并记录倍率及依据。",
114
+ "true": "外形尺寸与比例已锁定:不得放大或缩小外壳;装不下时停止建模,先交回硬件换件,仍不行再调整结构骨架,改外形必须由用户决定。"
115
+ }
116
+ }
117
+ },
118
+ "fallback": {
119
+ "goal": "建模没有产出可展示的 CAD 时,由宿主生成标注清楚的简化草模",
120
+ "directives": [
121
+ "宿主按冻结的硬件尺寸生成一份已明确标注的简化草模;本轮不调用模型,不进行视觉审查。"
122
+ ]
123
+ },
124
+ "review": {
125
+ "goal": "审查这一版的实际渲染",
126
+ "directives": [
127
+ "按契约审查这一版,审查对象全部取自 CAD 回执,不要猜;然后用一两句话向用户说明结果。",
128
+ "不要重新建模、不要重新出图、不要修改需求;待答的问题卡保持原样,不代用户回答。"
129
+ ],
130
+ "variants": {
131
+ "restore": [
132
+ "以识别出的真实产品图为基准,按契约审查这一版,审查对象全部取自 CAD 回执,不要猜;然后用一两句话说明与原产品的差异。",
133
+ "不要重新建模、不要重新出图、不要修改需求;待答的问题卡保持原样,不代用户回答。"
134
+ ]
135
+ }
136
+ },
137
+ "repair": {
138
+ "goal": "只修正检查发现的问题",
139
+ "directives": [
140
+ "只修改检查报告或几何分诊指出的冲突部位与实例,逐项保留其余实例;需要整体重建时按缺失的硬件与冲突证据完整重建。",
141
+ "尽量保留外观基准图的轮廓、比例、特征位置与材质;不缩放原生元器件。",
142
+ "不要修改需求、重新选型或重新出图;先完成轻量预览,视觉复检在下一阶段进行;待答的问题卡保持原样,不代用户回答。"
143
+ ]
144
+ },
145
+ "questions": {
146
+ "goal": "首版之后合并询问待确认项",
147
+ "directives": [
148
+ "读取已登记的硬件选型,把待确认的未定项合并成一张问题卡:最多三题,每题最多三个可直接选的方案,第一个选项写首版当前采用的默认值并注明“(首版已按此)”。",
149
+ "意图、目标深度或型号识别仍有疑问时,可以作为其中一题,第一个选项写首版采用的判断。",
150
+ "没有待确认项就不发卡,一两句话说明后结束本轮。",
151
+ "不要修改需求、重新选型、建模或出图;用户的答复作为对首版的修订处理。"
152
+ ]
153
+ }
154
+ }
155
+ }
@@ -1,11 +1,34 @@
1
1
  {
2
2
  "name": "abelien-workspace",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "作品旅程、PRD 与业务契约;user-journey 由 Agent 驱动,draft 供真实硬件阶段使用;不声明假 PRD、确认、报价或支付能力",
5
5
  "resources": [
6
6
  "draft"
7
7
  ],
8
- "capabilities": {},
8
+ "capabilities": {
9
+ "workspace.journey-next": {
10
+ "description": "按意图(create / restore / modify / remix)的阶段计划给出下一阶段与该阶段的领域规则;纯计算,不联网、不写资源。宿主先跑完自己的守卫,再把 directives 附在自己的执行说明之后",
11
+ "adapter": {
12
+ "type": "module",
13
+ "path": "scripts/journey-next.mjs",
14
+ "export": "journeyNext"
15
+ },
16
+ "input": {
17
+ "from": "input"
18
+ },
19
+ "resultContract": {
20
+ "nonEmptyStrings": [
21
+ "plan_version",
22
+ "intent"
23
+ ],
24
+ "arrays": [
25
+ "directives",
26
+ "order",
27
+ "completed"
28
+ ]
29
+ }
30
+ }
31
+ },
9
32
  "machines": {},
10
33
  "adapters": {}
11
34
  }
@@ -26,4 +26,4 @@ All three new hardware definitions now share `review-hardware-candidates` -> `ha
26
26
 
27
27
  Prismer Parse pending holds the original search-hardware-web cursor as awaiting_external; no extract/merge/select runs. The controlled {runId} host resumes the same frozen args/resource with `workflow resume`; task progress uses fixed original-task GET, received synchronous POST results are reused and only undispatched original-plan operations may first POST. Unknown paid effects/failed terminal runs cannot restart. Running SIGKILL snapshots require same-ID latest-checkpoint/source/plan/fence-owner verification; see the hardware evidence architecture for exact fields.
28
28
 
29
- The fixed trusted Prismer-first chain permits one Volc search only after saved definitive primary denial/successful empty query/unsent missing Key. Source denial permits safe direct HTML/plaintext, not a Parse substitute. Saved denial/fallback receipt SIGKILL windows recover in the same run/resource; only original unstarted fallback/source work may first dispatch, and unknown effects remain closed. The v2 host uses the declared pure recovery guard against the trusted original step snapshot; see the architecture.
29
+ Prismer is temporarily off by default (P2-05.02): the chain saves unsent prismer_disabled markers, searches Volc directly with an English query and Count ≤ 5, and reads sources over public HTTPS (PDF/image sources stay unavailable). The current definitions pass plan_rules=volc-english-5 to search-hardware-web; runs pinned to an older archived definition omit it and keep the old plan rules. The switch is pinned per web evidence, so a run resumed after the host flips it continues with the value its evidence recorded. When the trusted host enables it, the Prismer-first chain permits one Volc search only after saved definitive primary denial/successful empty query/unsent missing Key. Source denial permits safe direct HTML/plaintext, not a Parse substitute. Saved denial/fallback receipt SIGKILL windows recover in the same run/resource; only original unstarted fallback/source work may first dispatch, and unknown effects remain closed. The v2 host uses the declared pure recovery guard against the trusted original step snapshot; see the architecture.
@@ -25,7 +25,7 @@ node "$AB" --workdir "$WD" workflow status <runId> --httl
25
25
  skills/
26
26
  abelien-guide/SKILL.md 对话调度与沟通入口
27
27
  abelien-guide/references/ 共用表达规则与旧路径指引
28
- abelien-clarify/SKILL.md 需求澄清(webapp agent-prd 的同步快照)
28
+ abelien-clarify/SKILL.md 需求澄清(本仓为唯一编辑源)
29
29
  abelien-harness/scripts/ab.mjs 通用 CLI
30
30
  abelien-workspace/SKILL.md 作品业务契约入口
31
31
  abelien-workspace/references/ 完整旅程、PRD 契约、领域模型与本调用说明
@@ -34,7 +34,7 @@ skills/
34
34
  abelien-hardware-selection/SKILL.md 真实硬件阶段的分类与服务指引
35
35
  ```
36
36
 
37
- guide 与 clarify 自身不声明新资源、适配器或实体状态机,故不增加空 `domain.json`。clarify 正文与共用表达规则的编辑源在 `abelienwebapplication/docs/agent-prd/v2`,快照对应的 webapp commit 登记在开发仓 `tools/snapshot-sources.json`;用 `npm run sync:clarify` 从该 commit 同步进本包,`prepack` 检查漂移;只改源,不在快照上改。它作为 `abelien-*` bundle 随安装器分发,真实调用复用已发现域包。workspace 维护 A1–C 业务条件,guide 按这些条件组织调用和对话,clarify 仅提供需求建议。完整 A/B/C 回流由 `user-journey` 中的 `drive-product-journey` Agent 步骤承载。JSON 的 `journey` 只供 Agent 阅读;当前引擎顺序执行 `steps`,不解释该契约里的条件分支或 jump。
37
+ guide 与 clarify 自身不声明新资源、适配器或实体状态机,故不增加空 `domain.json`。clarify 正文与共用表达规则自 2026-10-11 起以 harness 仓为唯一编辑源,直接在本包修改,不再从 abelienwebapplication 同步。它作为 `abelien-*` bundle 随安装器分发,真实调用复用已发现域包。workspace 维护 A1–C 业务条件,guide 按这些条件组织调用和对话,clarify 仅提供需求建议。完整 A/B/C 回流由 `user-journey` 中的 `drive-product-journey` Agent 步骤承载。JSON 的 `journey` 只供 Agent 阅读;当前引擎顺序执行 `steps`,不解释该契约里的条件分支或 jump。
38
38
 
39
39
  | 需要的事实 | 读取位置/含义 |
40
40
  | --- | --- |
@@ -58,6 +58,16 @@ Web 已提交基线 91fac59a 仍在 real_image 生图;原图绑定、CAD 原
58
58
 
59
59
  当前作品的刷新、断线恢复和确认后的继续修改属于同一创作上下文;“历史作品续编”独立入口及“付款后复制副本再改”不纳入本轮一期创作主线。
60
60
 
61
+ ### 2.4 还原或修改现成产品
62
+
63
+ 用户用图片、链接或产品名指向一个现成产品,要求还原它或在它基础上修改;这与从零创作、二创共用 A1–C。clarify 判定意图:还原(restore)、新创(create)、改现成(modify),以及保留什么、允许改什么,写入需求的 `intent` 字段;宿主据此安排阶段顺序,参考研究的输入也从这里取。判定依据是原话,不是输入形式:商品图配“参考这个风格做一个”属于新创,“参考某产品再加一个功能”属于改现成。
64
+
65
+ - 还原与改现成先识别产品:联网核对型号与规格,并与参考图实测比例交叉核对;向用户展示原产品图与来源后继续。识别有冲突时保留候选,用户切换即为需求修订。还原以真实产品图为外观目标,默认锁定外形尺寸与比例;改现成先展示原产品,再展示修改后的设计。
66
+ - 新创可参考相似产品的尺寸、结构、器件和实现方式,写明借用了什么、为什么合适、哪些不照搬;找不到完整相似产品时按子系统参考。
67
+ - §2.1 的图片规则对所有意图有效:来源产品的功能来自可靠规格,只作为候选需求登记,并区分“原产品有这个功能”和“本次要实现这个功能”;目标深度(外观模型、可装配结构、功能样机)按原话推断。
68
+ - 意图、目标深度与识别结果在首版之前不单独发问,作为系统假设展示,用户可随时修改。
69
+ - 第三方产品图只作参考展示并注明来源,不进入图鉴或公开分享。
70
+
61
71
  ## 3. 完整流程与分支
62
72
 
63
73
  ```mermaid
@@ -0,0 +1,38 @@
1
+ // workspace.journey-next(P2-13.05):按意图的阶段计划给出下一阶段及其领域规则。
2
+ // 纯函数:不联网、不写资源、不读宿主状态。宿主把自己保存的产物映射为 artifacts,先跑完自己的守卫
3
+ // (结算、计费、保底、预算、工具集、幂等),再调用本能力;拿到的 directives 原样附在宿主自己的执行说明之后。
4
+ import { readFileSync } from "node:fs";
5
+
6
+ export const PLAN = JSON.parse(readFileSync(new URL("../assets/journey-stage-plan.json", import.meta.url), "utf8"));
7
+ const INTENTS = Object.keys(PLAN.orders);
8
+ const STAGES = Object.keys(PLAN.stages);
9
+ const invalid = message => { throw Object.assign(new Error(message), { code: "VALIDATION" }); };
10
+ const record = value => value !== null && typeof value === "object" && !Array.isArray(value);
11
+
12
+ /** Directives for one stage: intent variant if present, plus the lock directive where the stage declares one for this lock state. */
13
+ export function stageDirectives(stage, intent, locks) {
14
+ const entry = PLAN.stages[stage];
15
+ const base = [...(entry.variants?.[intent] ?? entry.directives)];
16
+ const lock = entry.locks?.shape?.[String(locks.shape)];
17
+ if (lock) base.splice(1, 0, lock);
18
+ return base;
19
+ }
20
+
21
+ export function journeyNext({ input }) {
22
+ if (!record(input) || Object.keys(input).some(key => !["intent", "artifacts", "locks", "stage"].includes(key))) invalid("input accepts intent, artifacts, locks and stage only");
23
+ if (!INTENTS.includes(input.intent)) invalid(`intent must be one of ${INTENTS.join(", ")}`);
24
+ const artifacts = input.artifacts ?? {};
25
+ if (!record(artifacts) || Object.entries(artifacts).some(([key, value]) => !PLAN.artifacts.includes(key) || typeof value !== "boolean")) invalid(`artifacts must map ${PLAN.artifacts.join(", ")} to booleans`);
26
+ const locksIn = input.locks ?? {};
27
+ if (!record(locksIn) || Object.keys(locksIn).some(key => key !== "shape") || (locksIn.shape !== undefined && typeof locksIn.shape !== "boolean")) invalid("locks accepts shape: boolean only");
28
+ // Restoring an existing product keeps its outer size and proportions unless the host says otherwise.
29
+ const locks = { shape: locksIn.shape ?? input.intent === "restore" };
30
+ if (input.stage !== undefined && !STAGES.includes(input.stage)) invalid(`stage must be one of ${STAGES.join(", ")}`);
31
+ const order = PLAN.orders[input.intent];
32
+ const done = stage => artifacts[PLAN.completion[stage]] === true;
33
+ const stage = input.stage ?? order.find(s => !done(s)) ?? null;
34
+ return {
35
+ plan_version: PLAN.plan_version, intent: input.intent, stage, goal: stage ? PLAN.stages[stage].goal : null,
36
+ directives: stage ? stageDirectives(stage, input.intent, locks) : [], order, completed: order.filter(done), locks,
37
+ };
38
+ }
@@ -0,0 +1,229 @@
1
+ {
2
+ "name": "user-journey-hardware-algorithm",
3
+ "domain": "abelien-workspace",
4
+ "executionProtocol": "pinned-result-v1",
5
+ "description": "Library recall, suitability review, fixed Prismer-first/Volc evidence for unresolved slots, source-bound merge, then the same formal hardware.select and gate",
6
+ "input": {
7
+ "required": [
8
+ "requirements",
9
+ "reactions"
10
+ ]
11
+ },
12
+ "steps": [
13
+ {
14
+ "id": "record-requirements",
15
+ "executor": "cli",
16
+ "action": "resource.put",
17
+ "args": {
18
+ "kind": "draft",
19
+ "id": "hardware-algorithm-d-{{hash}}",
20
+ "body": {
21
+ "requirements": "{{input.requirements}}",
22
+ "reactions": "{{input.reactions}}"
23
+ }
24
+ }
25
+ },
26
+ {
27
+ "id": "classify-hardware",
28
+ "executor": "agent",
29
+ "instruction": "需求已澄清;requirements 是 clarify 的 Requirements:context 为落点与场景,reaction[] 为全部触发→反应,limits[] 每项带 strength。按全部 reaction 推导功能槽位与数量,strength=hard 的 limits 进 hard_constraints,preference 只作排序提示;缺 reaction 或只有品类标签时停止并说明。读取同级 abelien-hardware-selection/SKILL.md,并用其 scripts/load-guide.mjs 依次按需加载 entry、命中的 level1、命中的 level2、contract;仅提交功能槽位、数量、受控三级路径和需求硬约束,不提交型号或猜测数据库事实。回复 {\"slots\":[...]};若需求不足或路径不确定,停止并说明,不能伪造槽位。",
30
+ "replySchema": {
31
+ "slots": "array"
32
+ }
33
+ },
34
+ {
35
+ "id": "search-hardware-wikis",
36
+ "executor": "cli",
37
+ "action": "capability.run",
38
+ "args": {
39
+ "capability": "hardware.search",
40
+ "input": {
41
+ "operation": "search",
42
+ "query": "{{input.requirements}}",
43
+ "requirements": "{{input.requirements}}",
44
+ "slots": "{{steps.classify-hardware.result.slots}}",
45
+ "policy": {
46
+ "prefer_system_candidates": true,
47
+ "top_k_per_slot": 8,
48
+ "include_content": true
49
+ }
50
+ }
51
+ }
52
+ },
53
+ {
54
+ "id": "hardware-knowledge-recalled",
55
+ "executor": "cli",
56
+ "action": "machine.send",
57
+ "args": {
58
+ "machine": "hardware-recall",
59
+ "event": "confirmRecall",
60
+ "instance": "{{steps.search-hardware-wikis.resource.id}}"
61
+ }
62
+ },
63
+ {
64
+ "id": "review-hardware-candidates",
65
+ "executor": "agent",
66
+ "instruction": "Read the complete library candidates and original requirements/slots. Review suitability against function and every hard constraint. Reply {\"unresolved_slots\":[{\"slot_id\":\"original slot\",\"reason\":\"no candidates or specific reasons all candidates are unsuitable\",\"query\":\"official model search targeting function/category/key hard constraints\",\"count\":10}]}. Every zero-candidate slot requires supplemental search. All unsuitable candidates also require search. Preserve rechargeable built-in battery, wireless charging, and all other original requirements; do not ask the user to drop a requirement because the catalog is empty. unresolved_slots contains only slots that need search. Omit suitable library slots entirely; never add placeholder rows with an empty query or count=0. Return [] when all slots are suitable. Before committing this review, the trusted host validates the full original requirements, slots and recall with validate-web-search-plan.mjs; a VALIDATION reply preserves this pause so the same run can be corrected. Count is optional and a positive integer; Prismer search.topK and return.topK are explicit. Do not apply undocumented Prismer query/result limits or truncate requirements. The trusted fixed Prismer-first policy permits Volc only after a saved definitive denial, successful empty query or unsent missing Key; Volc alone checks its official 1-100 character Query and Count 1-50 at dispatch. Unknown dispatched effects never authorize fallback or a new invocation. Do not supply URLs, credentials, commands or providers. System reuse is optional: poor matches must not force complex whole systems. Concept visuals and the original requirements come first.",
67
+ "replySchema": {
68
+ "unresolved_slots": "array"
69
+ }
70
+ },
71
+ {
72
+ "id": "search-hardware-web",
73
+ "executor": "cli",
74
+ "action": "capability.run",
75
+ "args": {
76
+ "capability": "hardware.web-search",
77
+ "input": {
78
+ "requirements": "{{input.requirements}}",
79
+ "slots": "{{steps.classify-hardware.result.slots}}",
80
+ "recall_id": "{{steps.search-hardware-wikis.resource.id}}",
81
+ "unresolved_slots": "{{steps.review-hardware-candidates.result.unresolved_slots}}"
82
+ }
83
+ }
84
+ },
85
+ {
86
+ "id": "extract-web-hardware",
87
+ "executor": "agent",
88
+ "instruction": "When pages contain blob_ref, use resource get <evidenceResourceId> --page <pageId> to read each required full original page; never copy page bodies into replies. Read the persisted hardware-web-evidence pages from search-hardware-web in full. Search Content/snippets/provider official labels are not complete official pages or proof of authority. Extract only manufacturer pages; uncertain source authority remains unknown and third-party mirrors are not official merely because their URL contains a manufacturer domain. Reply {\"candidates\":[{\"slot_id\":\"original slot\",\"page_id\":\"persisted page ID\",\"manufacturer\":\"exact manufacturer\",\"manufacturer_quote\":\"at least 8 source characters\",\"model\":\"exact model\",\"model_quote\":\"at least 8 source characters\",\"parts\":[{\"name\":\"physical part name\",\"name_quote\":\"exact source quote\",\"shape\":\"box|cylinder|sphere|unknown\",\"shape_quote\":\"exact source quote\",\"dimensions_mm\":{\"length\":20,\"width\":12,\"height\":3},\"dimension_quotes\":{\"length\":\"exact quote identifying this part, axis, numeric value and unit\",\"width\":\"exact quote\",\"height\":\"exact quote\"}}]}]}. Quotes must include the exact part/name/shape they support. Each physical part has separate dimensions; cylinders use diameter/height, spheres use diameter. Unknown dimensions are omitted, never invented or defaulted. Conflicting versions and unknown multi-part overall dimensions remain unknown; do not combine contradictory versions. Do not submit page bodies, official/verified/CAD_available/source/geometry claims. Missing reliable pages or no network means candidates empty. This is envelope_only, not true component CAD or engineering verification. For an attributed tuple such as Back Panel: 48mm x 32mm x 0.5mm, add dimensions_quote with the entire exact source string and dimension_axes:[\"length\",\"width\",\"height\"] in original order; dimensions_mm must map each original value/unit to that explicitly declared axis. Preserve alternate imperial tuples in the quote; never use their values as mm or borrow another part's measurements. A 2-value tuple leaves height unknown. A box inferred from dimensions is only an envelope expression: actual part shape and orientation remain unknown. dimension_quotes may be empty for this tuple mode. Never invent coil thickness or total assembly dimensions.",
89
+ "replySchema": {
90
+ "candidates": "array"
91
+ }
92
+ },
93
+ {
94
+ "id": "merge-hardware-web",
95
+ "executor": "cli",
96
+ "action": "capability.run",
97
+ "args": {
98
+ "capability": "hardware.web-merge",
99
+ "input": {
100
+ "requirements": "{{input.requirements}}",
101
+ "slots": "{{steps.classify-hardware.result.slots}}",
102
+ "recall_id": "{{steps.search-hardware-wikis.resource.id}}",
103
+ "evidence_id": "{{steps.search-hardware-web.resource.id}}",
104
+ "candidates": "{{steps.extract-web-hardware.result.candidates}}"
105
+ }
106
+ }
107
+ },
108
+ {
109
+ "id": "select-hardware-from-wikis",
110
+ "executor": "agent",
111
+ "instruction": "先读 abelien-hardware-selection/references/selection-service-contract.md 与真实候选的完整 Wiki。每槽位选择一个真实 component_id,显式 quantity 等于槽位 quantity;manufacturer/model 取候选,selection_reason 非空,wiki_evidence 为至少 8 字符的 Wiki 原文引用数组。selected_models 每项需 constraint_checks,覆盖 function、slot:<hard_constraints 的键>、limit:<每项 hard limit.id>;每项包含 constraint_id、status=verified|unknown|incompatible、reason、evidence:[{component_id,quote}]。多型号另给 compatibility_checks:power、interfaces 两维须包含 status、reason、每个型号的原文 evidence,可信电气数据确定性通过时以 compatibility_report 为准;mechanical、thermal、software 只作提示,可选填写,但填 incompatible 仍阻塞。证据不足填 unknown,不可编造。status=verified|needs_confirmation,plan_mode=assemble_new|adapt_system,其余数组 selected_models/coverage_ledger/remaining_slots/unknowns/replacement_plan 必填。先比较整机,但整机继承缺 manifest 必须待确认,不凭文案抵扣数量。verified 只表示 Wiki 证据判断通过,不是独立工程兼容求解或实测,不代表采用。 Read only merge-hardware-web candidates for the final choice. Preserve structured limits.envelope and source strength; dimension metadata/name/selection-line identity are supplied by the trusted finalizer, never invented. Incompatible dimension candidates require replacement; only decision_required (user hard limit, measured/datasheet size, no axis-aligned fit) returns needs_confirmation, other risk/unknown stays advisory and risk candidates rank last. Electrically incompatible candidates (trusted data: missing bus type or count) require replacing one side; ELECTRICAL_SUPPLY_GAP means add a power or regulator part. all_indexed_candidates_rejected is scoped to this indexed category; occupancy is advisory and clear is only coarse single-part screening. Whole-system reuse is optional; a poor match never forces a complex baseline. External IDs are external:<hash>, with source authority and engineering unknowns; envelopes are not component CAD and cannot grant adoption or delivery.",
112
+ "replySchema": {
113
+ "status": "verified|needs_confirmation",
114
+ "plan_mode": "adapt_system|assemble_new",
115
+ "selected_models": "array",
116
+ "coverage_ledger": "array",
117
+ "remaining_slots": "array",
118
+ "unknowns": "array",
119
+ "replacement_plan": "array",
120
+ "compatibility_checks": "array"
121
+ }
122
+ },
123
+ {
124
+ "id": "select-hardware",
125
+ "executor": "cli",
126
+ "action": "capability.run",
127
+ "args": {
128
+ "capability": "hardware.select",
129
+ "input": {
130
+ "requirements": "{{input.requirements}}",
131
+ "slots": "{{steps.classify-hardware.result.slots}}",
132
+ "recall_id": "{{steps.merge-hardware-web.resource.id}}",
133
+ "selection_proposal": "{{steps.select-hardware-from-wikis.result}}"
134
+ }
135
+ }
136
+ },
137
+ {
138
+ "id": "record-hardware-selection",
139
+ "executor": "cli",
140
+ "action": "resource.update",
141
+ "args": {
142
+ "id": "{{steps.record-requirements.resource.id}}",
143
+ "bodyPatch": {
144
+ "hardwareSelectionId": "{{steps.select-hardware.resource.id}}",
145
+ "hardwareSelectionStatus": "{{steps.select-hardware.result.status}}",
146
+ "hardwareSelectionRevision": "{{steps.select-hardware.result.revision}}",
147
+ "hardwarePlanMode": "{{steps.select-hardware.result.plan_mode}}"
148
+ }
149
+ }
150
+ },
151
+ {
152
+ "id": "hardware-selected",
153
+ "executor": "cli",
154
+ "action": "machine.send",
155
+ "args": {
156
+ "machine": "hardware-selection",
157
+ "event": "confirmSelection",
158
+ "instance": "{{steps.record-requirements.resource.id}}"
159
+ },
160
+ "completeWhen": {
161
+ "path": "steps.hardware-selected.result.to",
162
+ "equals": "selected_pending_confirmation"
163
+ },
164
+ "completionResult": {
165
+ "selectionId": "{{steps.select-hardware.resource.id}}",
166
+ "selectionStatus": "{{steps.select-hardware.result.status}}",
167
+ "selectionRevision": "{{steps.select-hardware.result.revision}}"
168
+ }
169
+ },
170
+ {
171
+ "id": "research-algorithms",
172
+ "executor": "agent",
173
+ "instruction": "硬件选型已完成。读取同级 abelien-algorithm/SKILL.md 和 references/research-policy.md,并从 context-json 的 select-hardware.resource 读取准确厂商、型号、能力和 Wiki 证据。针对 input.reactions 先检索硬件厂商官方资料,再检索算法或模型官方资料与 Hugging Face;端侧不满足且用户允许联网时才比较成熟云服务。选择每个 reaction 的最合适实现并回复 {\"bindings\":[...],\"candidates\":[...],\"sources\":[...],\"unavailable_sources\":[...],\"unknowns\":[...],\"blocking_unknowns\":[...]};来源必须回读,binding 必须明确 edge、cloud 或 hybrid。",
174
+ "replySchema": {
175
+ "bindings": "array",
176
+ "candidates": "array",
177
+ "sources": "array",
178
+ "unavailable_sources": "array",
179
+ "unknowns": "array",
180
+ "blocking_unknowns": "array"
181
+ }
182
+ },
183
+ {
184
+ "id": "select-algorithms",
185
+ "executor": "cli",
186
+ "action": "capability.run",
187
+ "args": {
188
+ "capability": "algorithm.finalize",
189
+ "input": {
190
+ "operation": "select",
191
+ "hardware_selection_id": "{{steps.select-hardware.resource.id}}",
192
+ "hardware_selection_revision": "{{steps.select-hardware.result.revision}}",
193
+ "requirements": "{{input.requirements}}",
194
+ "reactions": "{{input.reactions}}",
195
+ "research": "{{steps.research-algorithms.result}}"
196
+ }
197
+ }
198
+ },
199
+ {
200
+ "id": "algorithm-selected",
201
+ "executor": "cli",
202
+ "action": "machine.send",
203
+ "args": {
204
+ "machine": "algorithm-selection",
205
+ "event": "confirmSelection",
206
+ "instance": "{{steps.select-algorithms.resource.id}}"
207
+ }
208
+ },
209
+ {
210
+ "id": "record-algorithm-selection",
211
+ "executor": "cli",
212
+ "action": "resource.update",
213
+ "args": {
214
+ "id": "{{steps.record-requirements.resource.id}}",
215
+ "bodyPatch": {
216
+ "algorithmSelectionId": "{{steps.select-algorithms.resource.id}}",
217
+ "algorithmSelectionStatus": "{{steps.select-algorithms.result.status}}",
218
+ "algorithmSelectionRevision": "{{steps.select-algorithms.result.revision}}"
219
+ }
220
+ }
221
+ }
222
+ ],
223
+ "result": {
224
+ "selectionId": "{{steps.select-hardware.resource.id}}",
225
+ "selectionStatus": "{{steps.select-hardware.result.status}}",
226
+ "selectionRevision": "{{steps.select-hardware.result.revision}}"
227
+ },
228
+ "legacyResume": "read_only"
229
+ }