dsh-ptc-plus 0.2.3 → 0.3.1

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 (42) hide show
  1. package/README.en.md +171 -0
  2. package/README.md +94 -67
  3. package/assets/dsh-ptc-plus-banner-en.webp +0 -0
  4. package/assets/ptc-plus-repair-en.png +0 -0
  5. package/assets/ptc-plus-settings-en.png +0 -0
  6. package/assets/ptc-plus-settings-zh.png +0 -0
  7. package/client.js +1211 -128
  8. package/docs/adr/0019-plugin-settings-and-kill-switch.md +20 -4
  9. package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
  10. package/docs/adr/0022-stage-npm-releases-with-oidc.md +31 -0
  11. package/docs/architecture.md +10 -9
  12. package/docs/client-ui.md +30 -12
  13. package/docs/installation.md +13 -5
  14. package/docs/publishing.md +25 -1
  15. package/docs/runtime-reference.md +18 -12
  16. package/docs/value-wire.md +1 -1
  17. package/index.js +43 -12
  18. package/internal/cell-analysis.js +20 -3
  19. package/internal/cell-rewriter.js +36 -2
  20. package/internal/config-spec.js +192 -82
  21. package/internal/direct-surface-owner.js +77 -23
  22. package/internal/edit-transport-owner.js +10 -1
  23. package/internal/failure-reporting.js +15 -0
  24. package/internal/rejected-cell-editor.js +21 -12
  25. package/internal/repl-memory-projection.js +277 -0
  26. package/internal/run-code-description.js +34 -0
  27. package/internal/runtime-bridge-owner.js +63 -15
  28. package/internal/runtime-config.js +2 -0
  29. package/internal/session-cell-executor.js +14 -4
  30. package/internal/session-events.js +7 -0
  31. package/internal/session-journal.js +3 -2
  32. package/internal/session-log-view.js +2 -1
  33. package/internal/session-runtime.js +19 -2
  34. package/internal/session-state.js +83 -4
  35. package/internal/settings-compat.js +31 -0
  36. package/package.json +20 -13
  37. package/src/client-activity.js +472 -0
  38. package/src/client.js +536 -38
  39. package/README.zh.md +0 -144
  40. package/assets/ptc-plus-settings.png +0 -0
  41. /package/assets/{dsh-ptc-plus-banner.webp → dsh-ptc-plus-banner-zh.webp} +0 -0
  42. /package/assets/{ptc-plus-repair.png → ptc-plus-repair-zh.png} +0 -0
package/client.js CHANGED
@@ -8,14 +8,99 @@
8
8
  type: "boolean",
9
9
  default: true,
10
10
  label: "\u542F\u7528 PTC Plus",
11
- description: ""
11
+ labelEn: "Enable PTC Plus",
12
+ description: "",
13
+ descriptionEn: ""
14
+ },
15
+ {
16
+ key: "enhancedToolView",
17
+ type: "boolean",
18
+ default: true,
19
+ label: "\u4F7F\u7528 PTC Plus \u589E\u5F3A\u5DE5\u5177\u5361\u7247",
20
+ labelEn: "Use enhanced PTC Plus tool cards",
21
+ description: "\u5F00\u542F\u65F6\u4F7F\u7528\u589E\u5F3A\u5DE5\u5177\u5361\u7247\uFF1B\u5173\u95ED\u540E\u4F7F\u7528 DSH \u539F\u751F\u5DE5\u5177\u5361\u7247\u3002",
22
+ descriptionEn: "Uses enhanced tool cards when enabled and DSH native tool cards when disabled."
23
+ },
24
+ {
25
+ key: "autoDescribeRunCode",
26
+ type: "boolean",
27
+ default: true,
28
+ label: "\u5141\u8BB8\u6267\u884C\u7F3A\u5C11\u6458\u8981\u7684 run_code",
29
+ labelEn: "Allow run_code execution without a summary",
30
+ description: "\u5141\u8BB8 run_code \u7F3A\u5C11\u5916\u5C42 description\uFF1B\u5173\u95ED\u540E\u6062\u590D DSH \u6821\u9A8C\u3002\u6A21\u578B\u8BF7\u6C42\u548C\u539F\u59CB\u8C03\u7528\u53C2\u6570\u4FDD\u6301\u4E0D\u53D8\u3002",
31
+ descriptionEn: "Allows run_code to omit its outer description; disabling restores DSH validation. Model requests and original call arguments remain unchanged."
32
+ },
33
+ {
34
+ key: "canonicalizeToolCalls",
35
+ type: "boolean",
36
+ default: true,
37
+ label: "\u4FEE\u590D\u53EF\u8BC6\u522B\u7684\u9876\u5C42 native \u5DE5\u5177\u8BEF\u8C03\u7528",
38
+ labelEn: "Repair recognizable top-level native tool mis-calls",
39
+ description: "\u4EC5\u5F53\u5F53\u524D schema \u80FD\u552F\u4E00\u786E\u8BA4\u76EE\u6807\u5DE5\u5177\u4E14\u53C2\u6570\u6709\u6548\u65F6\uFF0C\u624D\u628A\u9876\u5C42 native \u5DE5\u5177\u8BEF\u8C03\u7528\u4FEE\u590D\u4E3A\u5BF9\u5E94\u7684 run_code \u8C03\u7528\u3002",
40
+ descriptionEn: "Repairs a top-level native tool mis-call as the corresponding run_code call only when the current schema uniquely identifies the tool and validates its arguments."
12
41
  },
13
42
  {
14
43
  key: "cordisToolsEnabled",
15
44
  type: "boolean",
16
45
  default: false,
17
- label: "\u5728 PTC \u6A21\u5F0F\u4E2D\u542F\u7528 Cordis \u5DE5\u5177",
18
- description: "\u5373\u65F6\u4E3A PTC agent \u52A0\u5165\u6216\u79FB\u9664\u5B98\u65B9 Cordis \u5DE5\u5177\u3002"
46
+ label: "\u5728 PTC \u6A21\u5F0F\u4E2D\u542F\u7528\u5B98\u65B9 Cordis \u5DE5\u5177",
47
+ labelEn: "Enable official Cordis tools in PTC mode",
48
+ description: "\u5F00\u542F\u540E\uFF0CPTC agent \u53EF\u4F7F\u7528\u5B98\u65B9 Cordis \u5DE5\u5177\u3001\u914D\u5957\u6307\u5F15\u548C\u5F00\u53D1 Skill\uFF1B\u5173\u95ED\u540E\u79FB\u9664\u8FD9\u4E9B\u80FD\u529B\u3002Cordis \u5DE5\u5177\u4EE5 DSH \u8FDB\u7A0B\u6743\u9650\u8FD0\u884C\u3002",
49
+ descriptionEn: "When enabled, PTC agents can use the official Cordis tools, guidance, and development Skill; disabling removes them. Cordis tools run with the DSH process permissions."
50
+ },
51
+ {
52
+ key: "looseTopLevelRedeclarations",
53
+ type: "boolean",
54
+ default: true,
55
+ label: "\u5141\u8BB8\u9876\u5C42\u53D8\u91CF\u91CD\u58F0\u660E",
56
+ labelEn: "Allow top-level variable redeclarations",
57
+ description: "\u5141\u8BB8\u9876\u5C42 const \u6216 let \u58F0\u660E\u66FF\u6362\u5DF2\u6709\u53D8\u91CF\uFF1B\u5173\u95ED\u540E\uFF0C\u91CD\u58F0\u660E\u4F1A\u5728\u6267\u884C\u524D\u88AB\u62D2\u7EDD\u3002",
58
+ descriptionEn: "Allows top-level const or let declarations to replace existing variables; disabling rejects redeclarations before execution."
59
+ },
60
+ {
61
+ key: "autoRewriteImports",
62
+ type: "boolean",
63
+ default: true,
64
+ label: "\u652F\u6301\u9759\u6001 import \u58F0\u660E",
65
+ labelEn: "Support static import declarations",
66
+ description: "\u5141\u8BB8\u5728 run_code \u4E2D\u4F7F\u7528\u9759\u6001 import\uFF0C\u5E76\u4FDD\u7559\u6A21\u5757\u89E3\u6790\u548C\u53EA\u8BFB binding \u8BED\u4E49\u3002",
67
+ descriptionEn: "Allows static import declarations in run_code while preserving module resolution and read-only binding semantics."
68
+ },
69
+ {
70
+ key: "autoStripExports",
71
+ type: "boolean",
72
+ default: true,
73
+ label: "\u652F\u6301\u9876\u5C42 export \u4FEE\u9970\u7B26",
74
+ labelEn: "Support top-level export modifiers",
75
+ description: "\u5141\u8BB8\u5728 run_code \u4E2D\u4F7F\u7528\u9876\u5C42 export\uFF0C\u5E76\u4FDD\u7559\u5BF9\u5E94\u7684\u672C\u5730\u58F0\u660E\u6216\u6A21\u5757\u526F\u4F5C\u7528\u3002",
76
+ descriptionEn: "Allows top-level export syntax in run_code while preserving the corresponding local declaration or module side effect."
77
+ },
78
+ {
79
+ key: "autoSplitRedeclarations",
80
+ type: "boolean",
81
+ default: true,
82
+ label: "\u652F\u6301\u6DF7\u5408\u89E3\u6784\u91CD\u58F0\u660E",
83
+ labelEn: "Support mixed destructuring redeclarations",
84
+ description: "\u5141\u8BB8\u9876\u5C42\u89E3\u6784\u58F0\u660E\u540C\u65F6\u5305\u542B\u65B0\u53D8\u91CF\u548C\u5DF2\u6709\u53D8\u91CF\u3002",
85
+ descriptionEn: "Allows top-level destructuring declarations to contain both new and existing variables."
86
+ },
87
+ {
88
+ key: "durableReplay",
89
+ type: "boolean",
90
+ default: true,
91
+ label: "\u542F\u7528\u6301\u4E45 REPL \u6062\u590D",
92
+ labelEn: "Enable durable REPL recovery",
93
+ description: "worker \u91CD\u542F\u540E\u4ECE session journal \u91CD\u5EFA\u53EF\u6062\u590D\u7684 REPL \u72B6\u6001\u3002",
94
+ descriptionEn: "Rebuilds recoverable REPL state from the session journal after a worker restart."
95
+ },
96
+ {
97
+ key: "tipsEnabled",
98
+ type: "boolean",
99
+ default: true,
100
+ label: "\u542F\u7528\u5931\u8D25\u6062\u590D\u63D0\u793A",
101
+ labelEn: "Enable failure recovery tips",
102
+ description: "\u5728\u7B26\u5408\u6761\u4EF6\u7684\u5931\u8D25\u540E\u663E\u793A\u6709\u51B7\u5374\u95F4\u9694\u7684\u6062\u590D\u63D0\u793A\u3002",
103
+ descriptionEn: "Shows recovery tips with a cooldown after qualifying failures."
19
104
  },
20
105
  {
21
106
  key: "computeMs",
@@ -23,8 +108,10 @@
23
108
  default: 6e4,
24
109
  min: 1,
25
110
  max: Number.MAX_SAFE_INTEGER,
26
- label: "\u5355 cell \u6700\u5927 CPU \u65F6\u95F4 (ms)",
27
- description: "\u540C\u6B65\u8BA1\u7B97\u8D85\u8FC7\u8BE5\u9884\u7B97\u7684 cell \u4F1A\u88AB\u4E2D\u65AD\u3002"
111
+ label: "\u5355 cell CPU \u65F6\u95F4\u4E0A\u9650 (ms)",
112
+ labelEn: "CPU time limit per cell (ms)",
113
+ description: "\u540C\u6B65\u8BA1\u7B97\u8D85\u8FC7\u8BE5\u4E0A\u9650\u65F6\u4E2D\u65AD\u5F53\u524D cell\u3002",
114
+ descriptionEn: "Interrupts the current cell when synchronous computation exceeds this limit."
28
115
  },
29
116
  {
30
117
  key: "maxWallMs",
@@ -32,26 +119,43 @@
32
119
  default: 6e5,
33
120
  min: 1,
34
121
  max: MAX_TIMER_DELAY_MS,
35
- label: "\u5355 cell \u6700\u5927\u5899\u949F\u65F6\u95F4 (ms)",
36
- description: "\u5B8C\u6574 cell \u6267\u884C\uFF08\u542B\u5F02\u6B65\u7B49\u5F85\uFF09\u7684\u6700\u957F\u8017\u65F6\u3002"
122
+ label: "\u5355 cell \u603B\u8017\u65F6\u4E0A\u9650 (ms)",
123
+ labelEn: "Elapsed time limit per cell (ms)",
124
+ description: "\u9650\u5236\u5B8C\u6574 cell \u6267\u884C\u7684\u8017\u65F6\uFF0C\u5305\u62EC\u5F02\u6B65\u7B49\u5F85\u3002",
125
+ descriptionEn: "Limits the complete cell execution time, including asynchronous waits."
37
126
  },
38
127
  {
39
- key: "maxOutputBytes",
128
+ key: "maxOldGenerationSizeMb",
40
129
  type: "integer",
41
- default: 64 * 1024 * 1024,
130
+ default: 512,
42
131
  min: 1,
43
132
  max: Number.MAX_SAFE_INTEGER,
44
- label: "\u6700\u5927\u8F93\u51FA\u5B57\u8282",
45
- description: "\u9650\u5236\u5355\u4E2A cell \u7684\u8F93\u51FA\u548C\u7ED3\u679C\u6570\u636E\u603B\u5927\u5C0F\u3002"
133
+ label: "\u6BCF\u4E2A worker \u65E7\u751F\u4EE3\u5185\u5B58\u4E0A\u9650 (MiB)",
134
+ labelEn: "Old-generation memory limit per worker (MiB)",
135
+ description: "\u9650\u5236\u6BCF\u4E2A worker \u7684 V8 \u65E7\u751F\u4EE3\uFF1B\u6D3B\u52A8 worker \u5B58\u5728\u65F6\u4E0D\u80FD\u4FEE\u6539\u3002",
136
+ descriptionEn: "Limits the V8 old generation for each worker; this setting cannot change while a worker is active."
46
137
  },
47
138
  {
48
- key: "maxOldGenerationSizeMb",
139
+ key: "maxNestedRunCodeDepth",
49
140
  type: "integer",
50
- default: 512,
141
+ default: 8,
51
142
  min: 1,
52
143
  max: Number.MAX_SAFE_INTEGER,
53
- label: "worker \u65E7\u751F\u4EE3\u5185\u5B58\u4E0A\u9650 (MiB)",
54
- description: "\u6BCF\u4E2A worker \u7684 V8 \u65E7\u751F\u4EE3\u4E0A\u9650\uFF1B\u6D3B\u52A8 worker \u5B58\u5728\u65F6\u4FEE\u6539\u4F1A\u88AB\u62D2\u7EDD\u3002"
144
+ label: "code.run \u5D4C\u5957\u5C42\u6570\u4E0A\u9650",
145
+ labelEn: "code.run nesting depth limit",
146
+ description: "\u9650\u5236\u5355\u4E2A\u9876\u5C42 cell \u4E2D code.run \u7684\u6700\u5927\u5D4C\u5957\u5C42\u6570\u3002",
147
+ descriptionEn: "Limits the maximum code.run nesting depth within one top-level cell."
148
+ },
149
+ {
150
+ key: "maxOutputBytes",
151
+ type: "integer",
152
+ default: 64 * 1024 * 1024,
153
+ min: 1,
154
+ max: Number.MAX_SAFE_INTEGER,
155
+ label: "\u5355 cell \u8F93\u51FA\u4E0A\u9650 (bytes)",
156
+ labelEn: "Output limit per cell (bytes)",
157
+ description: "\u9650\u5236\u5355\u4E2A cell \u7684\u65E5\u5FD7\u548C\u8FD4\u56DE\u7ED3\u679C\u7684\u5408\u8BA1\u5927\u5C0F\u3002",
158
+ descriptionEn: "Limits the combined size of one cell's logs and returned result."
55
159
  },
56
160
  {
57
161
  key: "maxValueNodes",
@@ -59,8 +163,10 @@
59
163
  default: 1e5,
60
164
  min: 1,
61
165
  max: Number.MAX_SAFE_INTEGER,
62
- label: "Value Graph \u6700\u5927\u8282\u70B9\u6570",
63
- description: "\u9650\u5236\u5355\u6B21\u8FD4\u56DE\u503C\u7684\u8282\u70B9\u6570\u3002"
166
+ label: "\u8FD4\u56DE\u503C\u8282\u70B9\u6570\u4E0A\u9650",
167
+ labelEn: "Returned-value node limit",
168
+ description: "\u9650\u5236\u5355\u6B21\u8FD4\u56DE\u503C\u7684 Value Graph \u8282\u70B9\u6570\u3002",
169
+ descriptionEn: "Limits the Value Graph node count for one returned value."
64
170
  },
65
171
  {
66
172
  key: "maxValueEdges",
@@ -68,8 +174,10 @@
68
174
  default: 1e6,
69
175
  min: 1,
70
176
  max: Number.MAX_SAFE_INTEGER,
71
- label: "Value Graph \u6700\u5927\u8FB9\u6570",
72
- description: "\u9650\u5236\u5355\u6B21\u8FD4\u56DE\u503C\u7684\u5F15\u7528\u5173\u7CFB\u6570\u3002"
177
+ label: "\u8FD4\u56DE\u503C\u5F15\u7528\u8FB9\u6570\u4E0A\u9650",
178
+ labelEn: "Returned-value reference-edge limit",
179
+ description: "\u9650\u5236\u5355\u6B21\u8FD4\u56DE\u503C\u7684 Value Graph \u5F15\u7528\u8FB9\u6570\u3002",
180
+ descriptionEn: "Limits the Value Graph reference-edge count for one returned value."
73
181
  },
74
182
  {
75
183
  key: "maxValueArrayLength",
@@ -77,8 +185,10 @@
77
185
  default: 1e6,
78
186
  min: 1,
79
187
  max: Number.MAX_SAFE_INTEGER,
80
- label: "\u6570\u7EC4\u6700\u5927\u58F0\u660E\u957F\u5EA6",
81
- description: "\u9650\u5236\u8FD4\u56DE\u6570\u7EC4\u7684\u6700\u5927\u957F\u5EA6\u3002"
188
+ label: "\u8FD4\u56DE\u6570\u7EC4\u957F\u5EA6\u4E0A\u9650",
189
+ labelEn: "Returned-array length limit",
190
+ description: "\u9650\u5236\u8FD4\u56DE\u6570\u7EC4\u7684\u6700\u5927\u58F0\u660E\u957F\u5EA6\u3002",
191
+ descriptionEn: "Limits the maximum declared length of a returned array."
82
192
  },
83
193
  {
84
194
  key: "maxValueBigIntDigits",
@@ -86,66 +196,10 @@
86
196
  default: 1e5,
87
197
  min: 1,
88
198
  max: Number.MAX_SAFE_INTEGER,
89
- label: "BigInt \u6700\u5927\u5341\u8FDB\u5236\u4F4D\u6570",
90
- description: "\u9650\u5236\u8FD4\u56DE\u503C\u4E2D BigInt \u7684\u5341\u8FDB\u5236\u4F4D\u6570\u3002"
91
- },
92
- {
93
- key: "maxNestedRunCodeDepth",
94
- type: "integer",
95
- default: 8,
96
- min: 1,
97
- max: Number.MAX_SAFE_INTEGER,
98
- label: "code.run \u6700\u5927\u9012\u5F52\u6DF1\u5EA6",
99
- description: "\u9650\u5236 code.run \u7684\u5D4C\u5957\u5C42\u6570\u3002"
100
- },
101
- {
102
- key: "canonicalizeToolCalls",
103
- type: "boolean",
104
- default: true,
105
- label: "\u89C4\u8303\u9876\u5C42 native \u8BEF\u8C03",
106
- description: "\u4FEE\u6B63\u53EF\u4EE5\u660E\u786E\u8BC6\u522B\u7684\u9876\u5C42 native \u8BEF\u8C03\u3002"
107
- },
108
- {
109
- key: "looseTopLevelRedeclarations",
110
- type: "boolean",
111
- default: true,
112
- label: "\u5BBD\u677E\u9876\u5C42\u91CD\u58F0\u660E",
113
- description: "\u5141\u8BB8\u9876\u5C42 const/let \u91CD\u58F0\u660E\u5DF2\u6709\u53D8\u91CF\u3002"
114
- },
115
- {
116
- key: "durableReplay",
117
- type: "boolean",
118
- default: true,
119
- label: "\u6301\u4E45\u91CD\u653E",
120
- description: "worker \u91CD\u542F\u540E\u6062\u590D\u53EF\u4EE5\u91CD\u5EFA\u7684 REPL \u72B6\u6001\u3002"
121
- },
122
- {
123
- key: "autoRewriteImports",
124
- type: "boolean",
125
- default: true,
126
- label: "\u81EA\u52A8\u6539\u5199 import",
127
- description: "\u5141\u8BB8\u5728 run_code \u4E2D\u4F7F\u7528\u9759\u6001 import\u3002"
128
- },
129
- {
130
- key: "autoStripExports",
131
- type: "boolean",
132
- default: true,
133
- label: "\u81EA\u52A8\u5265\u79BB export",
134
- description: "\u5141\u8BB8\u5728 run_code \u4E2D\u4F7F\u7528\u9876\u5C42 export\u3002"
135
- },
136
- {
137
- key: "autoSplitRedeclarations",
138
- type: "boolean",
139
- default: true,
140
- label: "\u81EA\u52A8\u62C6\u5206\u6DF7\u5408\u91CD\u58F0\u660E",
141
- description: "\u5141\u8BB8\u9876\u5C42\u89E3\u6784\u58F0\u660E\u540C\u65F6\u5305\u542B\u65B0\u65E7\u53D8\u91CF\u3002"
142
- },
143
- {
144
- key: "tipsEnabled",
145
- type: "boolean",
146
- default: true,
147
- label: "\u542F\u7528\u6062\u590D\u63D0\u793A",
148
- description: "\u5728\u7B26\u5408\u6761\u4EF6\u7684\u5931\u8D25\u540E\u663E\u793A\u6062\u590D\u63D0\u793A\u3002"
199
+ label: "\u8FD4\u56DE\u503C BigInt \u5341\u8FDB\u5236\u4F4D\u6570\u4E0A\u9650",
200
+ labelEn: "Returned-value BigInt decimal-digit limit",
201
+ description: "\u9650\u5236\u8FD4\u56DE\u503C\u4E2D BigInt \u7684\u5341\u8FDB\u5236\u4F4D\u6570\u3002",
202
+ descriptionEn: "Limits the decimal-digit count of BigInt values in one returned value."
149
203
  },
150
204
  {
151
205
  key: "tipCooldownMessages",
@@ -153,8 +207,10 @@
153
207
  default: 3,
154
208
  min: 1,
155
209
  max: Number.MAX_SAFE_INTEGER,
156
- label: "\u6062\u590D\u63D0\u793A\u51B7\u5374\u6B65\u6570",
157
- description: "\u540C\u7C7B\u6062\u590D\u63D0\u793A\u4E4B\u95F4\u7684\u6700\u5C0F\u95F4\u9694\u3002"
210
+ label: "\u540C\u7C7B\u6062\u590D\u63D0\u793A\u95F4\u9694 (messages)",
211
+ labelEn: "Same-kind recovery tip interval (messages)",
212
+ description: "\u540C\u7C7B\u6062\u590D\u63D0\u793A\u4E4B\u95F4\u7684\u6700\u5C0F\u95F4\u9694\u3002",
213
+ descriptionEn: "The minimum gap between recovery tips of the same kind."
158
214
  },
159
215
  {
160
216
  key: "tipEscalationFailures",
@@ -162,14 +218,501 @@
162
218
  default: 2,
163
219
  min: 1,
164
220
  max: Number.MAX_SAFE_INTEGER,
165
- label: "\u6062\u590D\u63D0\u793A\u5347\u7EA7\u5931\u8D25\u6B21\u6570",
166
- description: "\u8FDE\u7EED\u5931\u8D25\u8FBE\u5230\u6B64\u6B21\u6570\u540E\u663E\u793A\u66F4\u8BE6\u7EC6\u7684\u6062\u590D\u63D0\u793A\u3002"
221
+ label: "\u8BE6\u7EC6\u6062\u590D\u63D0\u793A\u9608\u503C (failures)",
222
+ labelEn: "Detailed recovery tip threshold (failures)",
223
+ description: "\u8FDE\u7EED\u5931\u8D25\u8FBE\u5230\u6B64\u6B21\u6570\u540E\u663E\u793A\u66F4\u8BE6\u7EC6\u7684\u6062\u590D\u63D0\u793A\u3002",
224
+ descriptionEn: "After this many consecutive failures, a more detailed recovery tip is shown."
225
+ }
226
+ ]);
227
+ var CONFIG_GROUPS = Object.freeze([
228
+ {
229
+ key: "core",
230
+ label: "\u5E38\u7528\u4E0E\u517C\u5BB9\u6027",
231
+ labelEn: "Common and compatibility",
232
+ fields: Object.freeze(["enabled", "enhancedToolView", "autoDescribeRunCode", "canonicalizeToolCalls"])
233
+ },
234
+ {
235
+ key: "optional",
236
+ label: "\u53EF\u9009\u80FD\u529B",
237
+ labelEn: "Optional capabilities",
238
+ fields: Object.freeze(["cordisToolsEnabled"])
239
+ },
240
+ {
241
+ key: "advanced",
242
+ label: "\u9AD8\u7EA7\u884C\u4E3A",
243
+ labelEn: "Advanced behavior",
244
+ fields: Object.freeze([
245
+ "looseTopLevelRedeclarations",
246
+ "autoRewriteImports",
247
+ "autoStripExports",
248
+ "autoSplitRedeclarations",
249
+ "durableReplay",
250
+ "tipsEnabled"
251
+ ])
252
+ },
253
+ {
254
+ key: "limits",
255
+ label: "\u8D44\u6E90\u9650\u5236",
256
+ labelEn: "Resource limits",
257
+ fields: Object.freeze([
258
+ "computeMs",
259
+ "maxWallMs",
260
+ "maxOldGenerationSizeMb",
261
+ "maxNestedRunCodeDepth",
262
+ "maxOutputBytes",
263
+ "maxValueNodes",
264
+ "maxValueEdges",
265
+ "maxValueArrayLength",
266
+ "maxValueBigIntDigits",
267
+ "tipCooldownMessages",
268
+ "tipEscalationFailures"
269
+ ])
167
270
  }
168
271
  ]);
169
272
  var CONFIG_DEFAULTS = Object.freeze(
170
273
  Object.fromEntries(CONFIG_FIELDS.map((field) => [field.key, field.default]))
171
274
  );
172
275
 
276
+ // src/client-activity.js
277
+ var JOURNAL_VERSIONS = /* @__PURE__ */ new Set([1, 2, 3]);
278
+ var JOURNAL_STATUSES = /* @__PURE__ */ new Set(["durable", "volatile", "discarded", "noop"]);
279
+ var BINDING_MODES = /* @__PURE__ */ new Set(["loose", "strict"]);
280
+ var JOURNAL_FIELDS = /* @__PURE__ */ new Set([
281
+ "version",
282
+ "bindingMode",
283
+ "rewritePolicy",
284
+ "status",
285
+ "calls",
286
+ "operations",
287
+ "confirms",
288
+ "diagnostics",
289
+ "completion",
290
+ "volatileReason"
291
+ ]);
292
+ var LEGACY_JOURNAL_FIELDS = new Set([...JOURNAL_FIELDS].filter((key) => key !== "rewritePolicy"));
293
+ var REWRITE_POLICY_FIELDS = /* @__PURE__ */ new Set([
294
+ "autoRewriteImports",
295
+ "autoStripExports",
296
+ "autoSplitRedeclarations"
297
+ ]);
298
+ var CALL_SUCCESS_FIELDS = /* @__PURE__ */ new Set(["global", "member", "args", "ok", "value", "settle"]);
299
+ var CALL_ERROR_FIELDS = /* @__PURE__ */ new Set(["global", "member", "args", "ok", "error", "settle"]);
300
+ var OPERATION_FIELDS = /* @__PURE__ */ new Set(["action", "name"]);
301
+ var RETURN_FIELDS = /* @__PURE__ */ new Set(["kind", "hasValue", "value"]);
302
+ var THROW_FIELDS = /* @__PURE__ */ new Set(["kind", "error"]);
303
+ var ERROR_FIELDS = /* @__PURE__ */ new Set(["kind", "message"]);
304
+ var DIAGNOSTIC_FIELDS = /* @__PURE__ */ new Set([
305
+ "code",
306
+ "severity",
307
+ "phase",
308
+ "message",
309
+ "stateEffect",
310
+ "dispatchState",
311
+ "source",
312
+ "cause",
313
+ "help"
314
+ ]);
315
+ var SOURCE_FIELDS = /* @__PURE__ */ new Set(["cell", "start", "end"]);
316
+ var POSITION_FIELDS = /* @__PURE__ */ new Set(["line", "column"]);
317
+ var CAUSE_FIELDS = /* @__PURE__ */ new Set(["code", "message"]);
318
+ var SEVERITIES = /* @__PURE__ */ new Set(["error", "warning", "note"]);
319
+ var PHASES = /* @__PURE__ */ new Set(["parse", "preflight", "execute", "tool-dispatch", "replay", "recover"]);
320
+ var STATE_EFFECTS = /* @__PURE__ */ new Set(["unchanged", "partially-applied", "rolled-back", "unknown"]);
321
+ var DISPATCH_STATES = /* @__PURE__ */ new Set(["not-dispatched", "dispatched", "completed", "unknown"]);
322
+ var REWRITE_FIELDS = /* @__PURE__ */ new Set(["kind", "description", "source"]);
323
+ var REWRITE_KINDS = /* @__PURE__ */ new Set(["import", "redeclaration", "export"]);
324
+ var REWRITE_POLICY_BY_KIND = Object.freeze({
325
+ import: "autoRewriteImports",
326
+ redeclaration: "autoSplitRedeclarations",
327
+ export: "autoStripExports"
328
+ });
329
+ var EDIT_TARGET_FIELDS = /* @__PURE__ */ new Set(["targetCallSeq"]);
330
+ var DERIVED_RUN_FIELDS = /* @__PURE__ */ new Set(["code", "description"]);
331
+ var RECOVERY_BOUNDARY_FIELDS = /* @__PURE__ */ new Set(["failedCallSeq", "frontierCallSeq"]);
332
+ var VALUE_ENVELOPE_FIELDS = /* @__PURE__ */ new Set(["codec", "root", "nodes"]);
333
+ var VALUE_OBJECT_FIELDS = /* @__PURE__ */ new Set(["type", "prototype", "entries"]);
334
+ var VALUE_ARRAY_FIELDS = /* @__PURE__ */ new Set(["type", "length", "entries"]);
335
+ var VALUE_UNDEFINED_FIELDS = /* @__PURE__ */ new Set(["tag"]);
336
+ var VALUE_NUMBER_FIELDS = /* @__PURE__ */ new Set(["tag", "value"]);
337
+ var VALUE_BIGINT_FIELDS = /* @__PURE__ */ new Set(["tag", "value"]);
338
+ var VALUE_REFERENCE_FIELDS = /* @__PURE__ */ new Set(["tag", "index"]);
339
+ var MAX_VALUE_NODES = 1e5;
340
+ var MAX_VALUE_EDGES = 1e6;
341
+ var MAX_ARRAY_LENGTH = 1e6;
342
+ var MAX_BIGINT_DIGITS = 1e5;
343
+ var MAX_STRING_BYTES = 64 * 1024 * 1024;
344
+ var textEncoder = new TextEncoder();
345
+ function isRecord(value) {
346
+ return value !== null && typeof value === "object" && !Array.isArray(value);
347
+ }
348
+ function hasClosedFields(value, allowed, required = []) {
349
+ if (!isRecord(value)) return false;
350
+ const keys = Reflect.ownKeys(value);
351
+ if (keys.some((key) => typeof key !== "string" || !allowed.has(key) || !Object.prototype.propertyIsEnumerable.call(value, key))) return false;
352
+ return [...required].every((key) => Object.hasOwn(value, key));
353
+ }
354
+ function hasExactFields(value, fields) {
355
+ return hasClosedFields(value, fields, fields) && Reflect.ownKeys(value).length === fields.size;
356
+ }
357
+ function hasExactOrderedFields(value, fields) {
358
+ if (!isRecord(value)) return false;
359
+ const keys = Reflect.ownKeys(value);
360
+ const ordered = [...fields];
361
+ return keys.length === ordered.length && keys.every((key, index) => key === ordered[index] && Object.prototype.propertyIsEnumerable.call(value, key));
362
+ }
363
+ function isLine(value) {
364
+ return typeof value === "string" && value.length > 0 && !/[\r\n]/.test(value);
365
+ }
366
+ function isSafeSequence(value) {
367
+ return Number.isSafeInteger(value) && value >= 0;
368
+ }
369
+ function isValidPosition(value) {
370
+ return hasExactFields(value, POSITION_FIELDS) && Number.isSafeInteger(value.line) && value.line >= 1 && Number.isSafeInteger(value.column) && value.column >= 1;
371
+ }
372
+ function isValidDiagnosticCause(value, depth) {
373
+ if (depth > 16 || !isRecord(value)) return false;
374
+ if (Object.hasOwn(value, "severity")) return isValidDiagnostic(value, depth + 1);
375
+ return hasClosedFields(value, CAUSE_FIELDS, ["message"]) && (value.code === void 0 || isLine(value.code)) && isLine(value.message);
376
+ }
377
+ function isValidDiagnostic(value, depth = 0) {
378
+ if (!hasClosedFields(value, DIAGNOSTIC_FIELDS, [
379
+ "code",
380
+ "severity",
381
+ "phase",
382
+ "message",
383
+ "stateEffect"
384
+ ])) return false;
385
+ if (typeof value.code !== "string" || !/^[A-Z][A-Z0-9-]{2,31}$/.test(value.code) || !SEVERITIES.has(value.severity) || !PHASES.has(value.phase) || !STATE_EFFECTS.has(value.stateEffect) || !isLine(value.message)) return false;
386
+ if (value.dispatchState !== void 0 && !DISPATCH_STATES.has(value.dispatchState)) return false;
387
+ if (value.source !== void 0) {
388
+ if (!hasClosedFields(value.source, SOURCE_FIELDS, ["cell", "start"]) || !isLine(value.source.cell) || !isValidPosition(value.source.start) || value.source.end !== void 0 && !isValidPosition(value.source.end)) return false;
389
+ if (value.source.end !== void 0 && (value.source.end.line < value.source.start.line || value.source.end.line === value.source.start.line && value.source.end.column < value.source.start.column)) return false;
390
+ }
391
+ if (value.cause !== void 0 && !isValidDiagnosticCause(value.cause, depth)) return false;
392
+ return value.help === void 0 || Array.isArray(value.help) && value.help.length <= 3 && value.help.every(isLine);
393
+ }
394
+ function isArrayIndexKey(value) {
395
+ if (!/^(0|[1-9][0-9]*)$/.test(value)) return false;
396
+ const parsed = Number(value);
397
+ return Number.isInteger(parsed) && parsed >= 0 && parsed < 4294967295 && String(parsed) === value;
398
+ }
399
+ function accountText(value, state) {
400
+ state.textBytes += textEncoder.encode(value).byteLength;
401
+ return state.textBytes <= MAX_STRING_BYTES;
402
+ }
403
+ function isValidValueAtom(value, state) {
404
+ if (value === null || typeof value === "boolean") return true;
405
+ if (typeof value === "string") return accountText(value, state);
406
+ if (typeof value === "number") return Number.isFinite(value) && !Object.is(value, -0);
407
+ if (!isRecord(value) || typeof value.tag !== "string") return false;
408
+ if (value.tag === "undefined") return hasExactOrderedFields(value, VALUE_UNDEFINED_FIELDS);
409
+ if (value.tag === "number") {
410
+ return hasExactOrderedFields(value, VALUE_NUMBER_FIELDS) && ["nan", "infinity", "-infinity", "-0"].includes(value.value);
411
+ }
412
+ if (value.tag === "bigint") {
413
+ if (!hasExactOrderedFields(value, VALUE_BIGINT_FIELDS) || typeof value.value !== "string" || !/^(0|-[1-9][0-9]*|[1-9][0-9]*)$/.test(value.value)) return false;
414
+ const digits = value.value[0] === "-" ? value.value.length - 1 : value.value.length;
415
+ return digits <= MAX_BIGINT_DIGITS && accountText(value.value, state);
416
+ }
417
+ if (value.tag !== "reference" || !hasExactOrderedFields(value, VALUE_REFERENCE_FIELDS) || !isSafeSequence(value.index) || value.index >= state.nodeCount) return false;
418
+ if (!state.discovered.has(value.index)) {
419
+ if (value.index !== state.discovered.size) return false;
420
+ state.discovered.add(value.index);
421
+ }
422
+ return true;
423
+ }
424
+ function isValidValueWire(value) {
425
+ if (!hasExactOrderedFields(value, VALUE_ENVELOPE_FIELDS) || value.codec !== "ptc-value-graph/v1" || !Array.isArray(value.nodes) || value.nodes.length > MAX_VALUE_NODES) return false;
426
+ const state = {
427
+ nodeCount: value.nodes.length,
428
+ discovered: /* @__PURE__ */ new Set(),
429
+ edges: 0,
430
+ textBytes: 0
431
+ };
432
+ if (!isValidValueAtom(value.root, state)) return false;
433
+ for (const [nodeIndex, node] of value.nodes.entries()) {
434
+ if (!state.discovered.has(nodeIndex) || !isRecord(node)) return false;
435
+ if (node.type === "array") {
436
+ if (!hasExactOrderedFields(node, VALUE_ARRAY_FIELDS) || !Number.isSafeInteger(node.length) || node.length < 0 || node.length > MAX_ARRAY_LENGTH || !Array.isArray(node.entries)) return false;
437
+ let previous = -1;
438
+ for (const entry of node.entries) {
439
+ if (!Array.isArray(entry) || entry.length !== 2 || !Number.isSafeInteger(entry[0]) || entry[0] <= previous || entry[0] < 0 || entry[0] >= node.length) return false;
440
+ previous = entry[0];
441
+ state.edges += 1;
442
+ if (state.edges > MAX_VALUE_EDGES || !isValidValueAtom(entry[1], state)) return false;
443
+ }
444
+ continue;
445
+ }
446
+ if (node.type !== "object" || !hasExactOrderedFields(node, VALUE_OBJECT_FIELDS) || !["object", "null"].includes(node.prototype) || !Array.isArray(node.entries)) return false;
447
+ const keys = /* @__PURE__ */ new Set();
448
+ let previousArrayIndex = -1;
449
+ let sawOtherKey = false;
450
+ for (const entry of node.entries) {
451
+ if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string" || keys.has(entry[0]) || !accountText(entry[0], state)) return false;
452
+ keys.add(entry[0]);
453
+ if (isArrayIndexKey(entry[0])) {
454
+ const current = Number(entry[0]);
455
+ if (sawOtherKey || current <= previousArrayIndex) return false;
456
+ previousArrayIndex = current;
457
+ } else {
458
+ sawOtherKey = true;
459
+ }
460
+ state.edges += 1;
461
+ if (state.edges > MAX_VALUE_EDGES || !isValidValueAtom(entry[1], state)) return false;
462
+ }
463
+ }
464
+ return state.discovered.size === value.nodes.length;
465
+ }
466
+ function isValidRewritePolicy(value) {
467
+ return hasExactFields(value, REWRITE_POLICY_FIELDS) && [...REWRITE_POLICY_FIELDS].every((key) => typeof value[key] === "boolean");
468
+ }
469
+ function isValidCall(value) {
470
+ if (!isRecord(value) || value.ok !== true && value.ok !== false) return false;
471
+ const fields = value.ok ? CALL_SUCCESS_FIELDS : CALL_ERROR_FIELDS;
472
+ if (!hasExactFields(value, fields) || typeof value.global !== "string" || typeof value.member !== "string" || !isValidValueWire(value.args) || !isSafeSequence(value.settle)) return false;
473
+ return value.ok ? isValidValueWire(value.value) : typeof value.error === "string";
474
+ }
475
+ function isValidOperation(value) {
476
+ if (!hasClosedFields(value, OPERATION_FIELDS, ["action"]) || !["save", "restore", "delete"].includes(value.action)) return false;
477
+ if (value.action === "restore" && value.name === void 0) return true;
478
+ return typeof value.name === "string" && /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(value.name);
479
+ }
480
+ function isValidCompletion(value) {
481
+ if (!isRecord(value) || !["return", "throw"].includes(value.kind)) return false;
482
+ if (value.kind === "return") {
483
+ if (!hasClosedFields(value, RETURN_FIELDS, ["kind", "hasValue"]) || typeof value.hasValue !== "boolean") return false;
484
+ return value.hasValue ? Object.hasOwn(value, "value") && isValidValueWire(value.value) : !Object.hasOwn(value, "value");
485
+ }
486
+ return hasExactFields(value, THROW_FIELDS) && hasExactFields(value.error, ERROR_FIELDS) && typeof value.error.kind === "string" && typeof value.error.message === "string";
487
+ }
488
+ function isValidConfirms(value, version) {
489
+ if (value === void 0) return true;
490
+ if (!Array.isArray(value) || new Set(value).size !== value.length) return false;
491
+ if (version === 1) return value.length === 0;
492
+ return value.every(isSafeSequence);
493
+ }
494
+ function isReadableJournalUnchecked(value) {
495
+ if (!isRecord(value) || !JOURNAL_VERSIONS.has(value.version) || !JOURNAL_STATUSES.has(value.status)) {
496
+ return false;
497
+ }
498
+ const fields = value.version === 1 ? LEGACY_JOURNAL_FIELDS : JOURNAL_FIELDS;
499
+ const required = ["version", "bindingMode", "status", "calls", "operations", "diagnostics"];
500
+ if (value.version !== 1) required.push("rewritePolicy");
501
+ if (!hasClosedFields(value, fields, required) || !BINDING_MODES.has(value.bindingMode) || value.version !== 1 && !isValidRewritePolicy(value.rewritePolicy) || !Array.isArray(value.calls) || !value.calls.every(isValidCall) || !Array.isArray(value.operations) || !value.operations.every(isValidOperation) || !isValidConfirms(value.confirms, value.version) || !Array.isArray(value.diagnostics) || !value.diagnostics.every(isValidDiagnostic)) return false;
502
+ const settlementOrder = value.calls.map((call) => call.settle).sort((left, right) => left - right);
503
+ if (settlementOrder.some((settle, index) => settle !== index)) return false;
504
+ const requiresCompletion = value.status === "durable" || value.status === "volatile";
505
+ if (requiresCompletion && !isValidCompletion(value.completion) || !requiresCompletion && value.completion !== void 0 && !isValidCompletion(value.completion)) return false;
506
+ if ((value.status === "discarded" || value.status === "noop") && (value.calls.length !== 0 || value.operations.length !== 0)) return false;
507
+ if (value.volatileReason !== void 0 && (typeof value.volatileReason !== "string" || value.status !== "volatile" && value.status !== "discarded")) return false;
508
+ return true;
509
+ }
510
+ function isReadableJournal(value) {
511
+ try {
512
+ return isReadableJournalUnchecked(value);
513
+ } catch {
514
+ return false;
515
+ }
516
+ }
517
+ function isCountableJournal(value) {
518
+ return isReadableJournal(value) && JOURNAL_STATUSES.has(value.status) && Array.isArray(value.calls) && Array.isArray(value.operations) && Array.isArray(value.diagnostics);
519
+ }
520
+ function isValidRewrites(value, journal) {
521
+ try {
522
+ return journal.status !== "noop" && isValidRewritePolicy(journal.rewritePolicy) && Array.isArray(value) && value.every((rewrite) => hasClosedFields(rewrite, REWRITE_FIELDS, ["kind", "description"]) && REWRITE_KINDS.has(rewrite.kind) && journal.rewritePolicy[REWRITE_POLICY_BY_KIND[rewrite.kind]] === true && typeof rewrite.description === "string" && rewrite.description.length > 0 && (rewrite.source === void 0 || typeof rewrite.source === "string"));
523
+ } catch {
524
+ return false;
525
+ }
526
+ }
527
+ function isValidEditTarget(value) {
528
+ try {
529
+ return hasExactFields(value, EDIT_TARGET_FIELDS) && isSafeSequence(value.targetCallSeq);
530
+ } catch {
531
+ return false;
532
+ }
533
+ }
534
+ function isValidDerivedRun(value) {
535
+ try {
536
+ return hasExactFields(value, DERIVED_RUN_FIELDS) && typeof value.code === "string" && typeof value.description === "string";
537
+ } catch {
538
+ return false;
539
+ }
540
+ }
541
+ function isValidRecoveryBoundaries(value) {
542
+ try {
543
+ return Array.isArray(value) && value.every((boundary) => hasExactFields(boundary, RECOVERY_BOUNDARY_FIELDS) && isSafeSequence(boundary.failedCallSeq) && (boundary.frontierCallSeq === null || isSafeSequence(boundary.frontierCallSeq)));
544
+ } catch {
545
+ return false;
546
+ }
547
+ }
548
+ function isValidEditRelation(meta, args, journal) {
549
+ try {
550
+ if (!isRecord(meta) || !isRecord(args) || !isValidEditTarget(meta.dshPtcPlusEdit) || !isValidDerivedRun(meta.dshPtcPlusDerivedRun) || journal.status === "noop") return false;
551
+ if (Object.hasOwn(meta, "dshPtcPlusRecoveryBoundaries") && !isValidRecoveryBoundaries(meta.dshPtcPlusRecoveryBoundaries)) return false;
552
+ return !Object.hasOwn(args, "expected_target_call_seq") || args.expected_target_call_seq === meta.dshPtcPlusEdit.targetCallSeq;
553
+ } catch {
554
+ return false;
555
+ }
556
+ }
557
+ function rawArguments(block, settled) {
558
+ const call = settled ? block.call : block;
559
+ return typeof call?.argsRaw === "string" ? call.argsRaw : typeof call?.arguments === "string" ? call.arguments : "";
560
+ }
561
+ function parseArguments(raw) {
562
+ try {
563
+ const value = JSON.parse(raw);
564
+ return isRecord(value) ? value : void 0;
565
+ } catch {
566
+ return void 0;
567
+ }
568
+ }
569
+ function resultText(block) {
570
+ if (!Array.isArray(block.content)) return "";
571
+ try {
572
+ const parts = block.content.map((item) => item?.type === "text" && typeof item.text === "string" ? item.text : JSON.stringify(item, null, 2));
573
+ if (parts.length === 0 && isRecord(block.error)) {
574
+ return [block.error.name, block.error.code].filter((value) => typeof value === "string").join(": ");
575
+ }
576
+ return parts.filter((value) => typeof value === "string").join("\n");
577
+ } catch {
578
+ return "";
579
+ }
580
+ }
581
+ var MIXED_REDECLARATION = "split a mixed top-level declaration while preserving native pattern initialization";
582
+ var GENERATED_RUN_CODE_DESCRIPTION_KEY = "dshPtcPlusRunCodeDescription";
583
+ function rewriteFeature(rewrites, predicate, key) {
584
+ const matching = rewrites.filter(predicate);
585
+ if (matching.length === 0) return void 0;
586
+ const sources = [...new Set(matching.map((rewrite) => rewrite.source).filter((source) => source !== void 0))];
587
+ return { key, detail: sources.join(", ") };
588
+ }
589
+ function operationFeatures(operations) {
590
+ const keys = {
591
+ save: "feature.stateSaved",
592
+ restore: "feature.stateRestored",
593
+ delete: "feature.stateDeleted"
594
+ };
595
+ return operations.map((operation) => ({
596
+ key: keys[operation.action],
597
+ detail: operation.name ?? ""
598
+ }));
599
+ }
600
+ function uniqueFeatures(features) {
601
+ const seen = /* @__PURE__ */ new Set();
602
+ return features.filter((feature) => {
603
+ if (feature === void 0) return false;
604
+ const identity = `${feature.key}\0${feature.detail}`;
605
+ if (seen.has(identity)) return false;
606
+ seen.add(identity);
607
+ return true;
608
+ });
609
+ }
610
+ function isDurableRecoveryDiagnostic(diagnostic) {
611
+ return diagnostic.code === "PTC-R002" && diagnostic.severity === "warning" && diagnostic.phase === "recover" && diagnostic.stateEffect === "rolled-back";
612
+ }
613
+ function derivePtcToolView(block, toolName = void 0) {
614
+ const settled = isRecord(block) && block.kind === "tool-result";
615
+ const argsRaw = isRecord(block) ? rawArguments(block, settled) : "";
616
+ const args = parseArguments(argsRaw);
617
+ const code = typeof args?.code === "string" ? args.code : argsRaw;
618
+ const explicitDescription = typeof args?.description === "string" && args.description.length > 0 ? args.description : void 0;
619
+ const generatedDescription = settled && isRecord(block.meta) && typeof block.meta[GENERATED_RUN_CODE_DESCRIPTION_KEY] === "string" && block.meta[GENERATED_RUN_CODE_DESCRIPTION_KEY].length > 0 ? block.meta[GENERATED_RUN_CODE_DESCRIPTION_KEY] : void 0;
620
+ const description = (explicitDescription ?? generatedDescription)?.split(/\r?\n/, 1)[0] ?? "";
621
+ const output = settled ? resultText(block) : "";
622
+ const state = !settled ? "running" : block.error?.code === "interrupted" ? "stopped" : block.isError === true ? "error" : "ok";
623
+ const journal = settled && isRecord(block.meta) && isCountableJournal(block.meta.dshPtcPlus) ? block.meta.dshPtcPlus : void 0;
624
+ if (journal === void 0) {
625
+ return Object.freeze({ state, description, code, output, ptc: false, features: Object.freeze([]) });
626
+ }
627
+ const rewrites = isValidRewrites(block.meta.dshPtcPlusRewrites, journal) ? block.meta.dshPtcPlusRewrites : [];
628
+ const resolvedToolName = typeof toolName === "string" ? toolName : typeof block.call?.name === "string" ? block.call.name : "";
629
+ const recordedToolName = typeof block.call?.name === "string" ? block.call.name : void 0;
630
+ const safeEdit = resolvedToolName === "edit_run_code" && (recordedToolName === void 0 || recordedToolName === "edit_run_code") && isValidEditRelation(block.meta, args, journal);
631
+ const features = uniqueFeatures([
632
+ safeEdit ? { key: "feature.safeEdit", detail: "" } : void 0,
633
+ rewriteFeature(rewrites, (rewrite) => rewrite.kind === "import", "autoRewriteImports.label"),
634
+ rewriteFeature(rewrites, (rewrite) => rewrite.kind === "export", "autoStripExports.label"),
635
+ rewriteFeature(rewrites, (rewrite) => rewrite.kind === "redeclaration" && rewrite.description === MIXED_REDECLARATION, "autoSplitRedeclarations.label"),
636
+ journal.calls.some((call) => call.global === "code" && call.member === "run" && call.ok === true) ? { key: "feature.codeRun", detail: "" } : void 0,
637
+ journal.diagnostics.some(isDurableRecoveryDiagnostic) ? { key: "durableReplay.label", detail: "" } : void 0,
638
+ ...operationFeatures(journal.operations)
639
+ ]);
640
+ return Object.freeze({ state, description, code, output, ptc: true, features: Object.freeze(features) });
641
+ }
642
+
643
+ // internal/record-utils.js
644
+ function isRecord2(value) {
645
+ return value !== null && typeof value === "object" && !Array.isArray(value);
646
+ }
647
+
648
+ // internal/repl-memory-projection.js
649
+ var BINDING_KINDS = /* @__PURE__ */ new Set(["variable", "function", "class", "import"]);
650
+ var MAX_BINDINGS = 128;
651
+ var MAX_BINDING_NAME_LENGTH = 128;
652
+ var MAX_DEFINITION_SOURCE_LENGTH = 1024;
653
+ var MAX_DEFINITION_SOURCE_TOTAL_LENGTH = 16 * 1024;
654
+ var SNAPSHOT_FIELDS = /* @__PURE__ */ new Set(["available", "entries", "total", "omitted"]);
655
+ var ENTRY_FIELDS = /* @__PURE__ */ new Set(["name", "kind", "definition"]);
656
+ var DEFINITION_FIELDS = /* @__PURE__ */ new Set(["source", "line", "column"]);
657
+ function exactFields(value, fields) {
658
+ if (!isRecord2(value)) return false;
659
+ const keys = Reflect.ownKeys(value);
660
+ return keys.length === fields.size && keys.every((key) => typeof key === "string" && fields.has(key) && Object.prototype.propertyIsEnumerable.call(value, key));
661
+ }
662
+ var EMPTY_REPL_MEMORY = Object.freeze({
663
+ available: false,
664
+ entries: Object.freeze([]),
665
+ total: 0,
666
+ omitted: 0
667
+ });
668
+ function unavailableReplMemorySnapshot() {
669
+ return EMPTY_REPL_MEMORY;
670
+ }
671
+ function normalizeDefinition(value) {
672
+ if (!exactFields(value, DEFINITION_FIELDS) || typeof value.source !== "string" || value.source.length === 0 || value.source.length > MAX_DEFINITION_SOURCE_LENGTH || !Number.isSafeInteger(value.line) || value.line < 1 || !Number.isSafeInteger(value.column) || value.column < 1) {
673
+ throw new Error("invalid dsh-ptc-plus REPL binding definition");
674
+ }
675
+ return Object.freeze({ source: value.source, line: value.line, column: value.column });
676
+ }
677
+ function normalizeBinding(value) {
678
+ if (!exactFields(value, ENTRY_FIELDS) || typeof value.name !== "string" || value.name.length === 0 || value.name.length > MAX_BINDING_NAME_LENGTH || !BINDING_KINDS.has(value.kind)) {
679
+ throw new Error("invalid dsh-ptc-plus REPL memory binding");
680
+ }
681
+ return Object.freeze({
682
+ name: value.name,
683
+ kind: value.kind,
684
+ definition: normalizeDefinition(value.definition)
685
+ });
686
+ }
687
+ function normalizeReplMemorySnapshot(value) {
688
+ if (!exactFields(value, SNAPSHOT_FIELDS) || typeof value.available !== "boolean" || !Array.isArray(value.entries) || value.entries.length > MAX_BINDINGS || !Number.isSafeInteger(value.total) || value.total < 0 || !Number.isSafeInteger(value.omitted) || value.omitted < 0 || value.total !== value.entries.length + value.omitted) {
689
+ throw new Error("invalid dsh-ptc-plus REPL memory snapshot");
690
+ }
691
+ if (!value.available && (value.total !== 0 || value.entries.length !== 0)) {
692
+ throw new Error("unavailable dsh-ptc-plus REPL memory snapshot must be empty");
693
+ }
694
+ const names = /* @__PURE__ */ new Set();
695
+ let sourceLength = 0;
696
+ const entries = value.entries.map((entry) => {
697
+ const normalized = normalizeBinding(entry);
698
+ if (names.has(normalized.name)) {
699
+ throw new Error("invalid dsh-ptc-plus REPL memory binding");
700
+ }
701
+ sourceLength += normalized.definition.source.length;
702
+ if (sourceLength > MAX_DEFINITION_SOURCE_TOTAL_LENGTH) {
703
+ throw new Error("dsh-ptc-plus REPL binding definitions exceed the presentation budget");
704
+ }
705
+ names.add(normalized.name);
706
+ return normalized;
707
+ });
708
+ return Object.freeze({
709
+ available: value.available,
710
+ entries: Object.freeze(entries),
711
+ total: value.total,
712
+ omitted: value.omitted
713
+ });
714
+ }
715
+
173
716
  // src/client.js
174
717
  var CLIENT_STYLE_ID = "ptc-plus-client-style";
175
718
  var CLIENT_CSS = `
@@ -178,20 +721,140 @@
178
721
  .ptcPlusHeader:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06))}.ptcPlusHeader:focus-visible,.ptcPlusButton:focus-visible,.ptcPlusInput:focus-visible{outline:2px solid var(--dsw-alias-interactive-primary,#4d6bfe);outline-offset:-2px}
179
722
  .ptcPlusHeadText{display:flex;flex:1;min-width:0;flex-direction:column;align-items:flex-start;gap:1px}.ptcPlusName{font-size:14px;font-weight:600;line-height:20px}.ptcPlusDescription{color:var(--dsw-alias-label-tertiary,#74777d);font-size:12px;line-height:18px;overflow-wrap:anywhere}.ptcPlusStatus{display:inline-flex;align-items:center;flex:none;padding:2px 8px;border-radius:999px;font-size:11px;font-weight:500;line-height:16px}.ptcPlusStatus[data-enabled=true]{color:var(--dsw-alias-state-success-primary,#16794f);background:var(--dsw-alias-state-success-tertiary,#e7f7ef)}.ptcPlusStatus[data-enabled=false]{color:var(--dsw-alias-label-tertiary,#74777d);background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06))}
180
723
  .ptcPlusChevron{display:flex;color:var(--dsw-alias-label-tertiary,#74777d);transition:transform .18s ease}.ptcPlusChevron[data-open=true]{transform:rotate(180deg)}.ptcPlusBody{display:grid;grid-template-rows:0fr;transition:grid-template-rows .2s ease}.ptcPlusBody[data-open=true]{grid-template-rows:1fr}.ptcPlusBodyInner{min-height:0;overflow:hidden}.ptcPlusFields{margin:0 16px;padding:8px 0 12px;border-top:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1))}
181
- .ptcPlusRow{display:flex;align-items:center;gap:12px;min-height:48px;border-top:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1))}.ptcPlusRow:first-child{border-top:0}.ptcPlusMain{flex:1;min-width:0}.ptcPlusLabel{font-size:14px;font-weight:500;line-height:20px}.ptcPlusDetail,.ptcPlusMessage{color:var(--dsw-alias-label-tertiary,#74777d);font-size:12px;line-height:18px;overflow-wrap:anywhere}.ptcPlusInput{box-sizing:border-box;min-width:72px;width:140px;padding:5px 8px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));border-radius:6px;background:var(--dsw-alias-bg-layer-1,#fff);color:inherit;font:12px/18px ui-monospace,SFMono-Regular,Consolas,monospace}.ptcPlusCheck{width:18px;height:18px;accent-color:var(--dsw-alias-interactive-primary,#4d6bfe)}
182
- .ptcPlusFooter{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:8px}.ptcPlusButton{min-height:32px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));border-radius:6px;background:transparent;color:inherit;cursor:pointer;font:500 13px/20px inherit;transition:background-color .16s ease,border-color .16s ease}.ptcPlusButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06))}.ptcPlusButton:disabled,.ptcPlusInput:disabled,.ptcPlusCheck:disabled{cursor:not-allowed;opacity:.55}.ptcPlusActive{display:inline-flex;align-items:center;gap:5px;color:var(--dsw-alias-state-success-primary,#16794f);font-size:12px;line-height:18px;white-space:nowrap}
183
- @media(max-width:560px){.ptcPlusHeader{padding:12px}.ptcPlusFields{margin:0 12px}.ptcPlusRow{align-items:flex-start;flex-direction:column;gap:6px;padding:10px 0}.ptcPlusInput{width:100%}.ptcPlusFooter{align-items:stretch;flex-direction:column}.ptcPlusButton{width:100%}}
184
- @media(prefers-reduced-motion:reduce){.ptcPlusHeader,.ptcPlusChevron,.ptcPlusBody,.ptcPlusButton{transition:none}}
724
+ .ptcPlusGroup+.ptcPlusGroup{margin-top:14px}.ptcPlusGroupTitle{margin:0;padding:8px 0 5px;color:var(--dsw-alias-label-secondary,#52565d);font-size:11px;font-weight:600;letter-spacing:0;line-height:16px}.ptcPlusRow{display:flex;align-items:center;gap:12px;min-height:48px;border-top:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1))}.ptcPlusRow:first-child{border-top:0}.ptcPlusMain{flex:1;min-width:0}.ptcPlusLabel{font-size:14px;font-weight:500;line-height:20px}.ptcPlusDetail,.ptcPlusMessage{color:var(--dsw-alias-label-tertiary,#74777d);font-size:12px;line-height:18px;overflow-wrap:anywhere}.ptcPlusInput{box-sizing:border-box;min-width:72px;width:140px;padding:5px 8px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));border-radius:6px;background:var(--dsw-alias-bg-layer-1,#fff);color:inherit;font:12px/18px ui-monospace,SFMono-Regular,Consolas,monospace}.ptcPlusCheck{width:18px;height:18px;accent-color:var(--dsw-alias-interactive-primary,#4d6bfe)}
725
+ .ptcPlusFooter{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:8px}.ptcPlusButton{min-height:32px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));border-radius:6px;background:transparent;color:inherit;cursor:pointer;font:500 13px/20px inherit;transition:background-color .16s ease,border-color .16s ease}.ptcPlusButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06))}.ptcPlusButton:disabled,.ptcPlusInput:disabled,.ptcPlusCheck:disabled{cursor:not-allowed;opacity:.55}
726
+ .ptcPlusActiveShell{display:inline-flex;align-items:center}.ptcPlusActive{appearance:none;display:inline-flex;height:24px;align-items:center;gap:5px;padding:0 8px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-success-primary,#16794f) 32%,transparent);border-radius:6px;background:var(--dsw-alias-state-success-tertiary,#e7f7ef);color:var(--dsw-alias-state-success-primary,#16794f);cursor:help;font:600 12px/18px inherit;white-space:nowrap;transition:background-color .14s ease,border-color .14s ease}.ptcPlusActive:hover,.ptcPlusActive[aria-expanded=true]{border-color:color-mix(in srgb,var(--dsw-alias-state-success-primary,#16794f) 48%,transparent);background:color-mix(in srgb,var(--dsw-alias-state-success-primary,#16794f) 16%,var(--dsw-alias-bg-layer-3,#fff))}.ptcPlusActive:focus-visible{outline:2px solid var(--dsw-alias-state-success-primary,#16794f);outline-offset:2px}.ptcPlusReplPopover{position:fixed;z-index:2147483000;inset:auto;display:none;box-sizing:border-box;margin:0;padding:0;border:0;overflow:visible;background:transparent;color:var(--dsw-alias-label-primary,#18191c)}.ptcPlusReplPopover:popover-open,.ptcPlusReplPopover[data-open=true]{display:block}.ptcPlusReplPopover::backdrop{background:transparent}.ptcPlusReplCard{display:flex;max-height:inherit;overflow:hidden;flex-direction:column;border:1px solid color-mix(in srgb,var(--dsw-alias-state-success-primary,#16794f) 22%,var(--dsw-alias-border-l2,rgba(0,0,0,.1)));border-top:3px solid var(--dsw-alias-state-success-primary,#16794f);border-radius:8px;background:var(--dsw-alias-bg-layer-3,#fff);box-shadow:0 14px 36px rgba(16,24,40,.2),0 3px 10px rgba(16,24,40,.1);color:var(--dsw-alias-label-primary,#18191c);white-space:normal}.ptcPlusReplHead{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:center;column-gap:8px;padding:11px 13px 10px;border-bottom:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));background:color-mix(in srgb,var(--dsw-alias-state-success-primary,#16794f) 7%,var(--dsw-alias-bg-layer-3,#fff))}.ptcPlusReplStatusDot{grid-row:1/3;width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-state-success-primary,#16794f);box-shadow:0 0 0 3px color-mix(in srgb,var(--dsw-alias-state-success-primary,#16794f) 14%,transparent)}.ptcPlusReplTitle,.ptcPlusReplSummary{display:block;min-width:0}.ptcPlusReplTitle{font-size:13px;font-weight:600;line-height:19px}.ptcPlusReplSummary{color:var(--dsw-alias-label-tertiary,#74777d);font-size:11px;line-height:16px}.ptcPlusReplList{min-height:0;margin:0;padding:5px 0;overflow:auto;overscroll-behavior:contain;list-style:none;scrollbar-gutter:stable}.ptcPlusReplBinding{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:4px 10px;padding:7px 12px}.ptcPlusReplBinding:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06))}.ptcPlusReplIdentity{display:flex;min-width:0;align-items:center;gap:7px}.ptcPlusReplName{min-width:0;overflow:hidden;font:12px/18px ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.ptcPlusReplKind{flex:none;padding:1px 6px;border:1px solid color-mix(in srgb,currentColor 22%,transparent);border-radius:999px;background:color-mix(in srgb,currentColor 10%,transparent);font-size:10px;font-weight:600;line-height:15px}.ptcPlusReplKind[data-kind=variable]{color:var(--dsw-alias-interactive-primary,#315fbd)}.ptcPlusReplKind[data-kind=function]{color:#7651b5}.ptcPlusReplKind[data-kind=class]{color:var(--dsw-alias-state-warning-primary,#946200)}.ptcPlusReplKind[data-kind=import]{color:#14766f}.ptcPlusReplPreview{grid-column:1;min-width:0;overflow:hidden;color:var(--dsw-alias-label-tertiary,#74777d);font:11px/16px ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.ptcPlusReplInspect{grid-column:2;grid-row:1/3;display:inline-flex;align-items:center;gap:4px;padding:3px 5px;border:0;border-radius:4px;background:transparent;color:var(--dsw-alias-label-secondary,#52565d);cursor:pointer;font:500 11px/17px inherit;white-space:nowrap}.ptcPlusReplInspect:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06));color:var(--dsw-alias-interactive-primary,#4d6bfe)}.ptcPlusReplInspect:focus-visible{outline:2px solid var(--dsw-alias-interactive-primary,#4d6bfe);outline-offset:1px}.ptcPlusReplDefinition{grid-column:1/-1;min-width:0;margin-top:4px;padding:8px;border-left:2px solid var(--dsw-alias-interactive-primary,#4d6bfe);background:var(--dsw-alias-bg-layer-2,rgba(38,49,72,.03))}.ptcPlusReplLocation{display:block;margin-bottom:5px;color:var(--dsw-alias-label-tertiary,#74777d);font-size:10px;line-height:15px}.ptcPlusReplCode{max-height:180px;margin:0;overflow:auto;color:inherit;font:11px/16px ui-monospace,SFMono-Regular,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.ptcPlusReplEmpty,.ptcPlusReplMore{display:block;color:var(--dsw-alias-label-tertiary,#74777d)}.ptcPlusReplEmpty{padding:18px 13px;font-size:12px;line-height:18px}.ptcPlusReplMore{padding:8px 13px;border-top:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));background:var(--dsw-alias-bg-layer-2,rgba(38,49,72,.03));font-size:11px;line-height:17px}
727
+ .ptcPlusReplList{max-height:min(52vh,480px)}.ptcPlusReplBinding{grid-template-columns:minmax(0,1fr) 24px;gap:3px 8px;min-height:36px;padding:5px 12px;content-visibility:auto;contain-intrinsic-size:36px;cursor:pointer;transition:background-color .16s ease}.ptcPlusReplBinding:focus-visible{outline:2px solid var(--dsw-alias-interactive-primary,#4d6bfe);outline-offset:-2px}.ptcPlusReplBinding[data-expanded=true]{background:color-mix(in srgb,var(--dsw-alias-interactive-primary,#4d6bfe) 5%,transparent)}.ptcPlusReplName{grid-column:1}.ptcPlusReplName[data-kind=variable]{color:var(--dsw-alias-interactive-primary,#315fbd)}.ptcPlusReplName[data-kind=function]{color:#7651b5}.ptcPlusReplName[data-kind=class]{color:var(--dsw-alias-state-warning-primary,#946200)}.ptcPlusReplName[data-kind=import]{color:#14766f}.ptcPlusReplPreview{grid-column:1}.ptcPlusReplChevron{grid-column:2;grid-row:1/3;display:flex;align-items:center;justify-content:center;color:var(--dsw-alias-label-tertiary,#74777d);transition:transform .2s ease}.ptcPlusReplChevron[data-open=true]{transform:rotate(180deg)}.ptcPlusReplDefinitionWrap{grid-column:1/-1;display:grid;grid-template-rows:0fr;min-width:0;transition:grid-template-rows .24s cubic-bezier(.2,.7,.2,1)}.ptcPlusReplDefinitionWrap[data-open=true]{grid-template-rows:1fr}.ptcPlusReplDefinitionInner{min-height:0;overflow:hidden}
728
+ .ptcPlusTool{display:flex;min-width:0;flex-direction:column}.ptcPlusToolPreview{display:flex;min-width:0;flex:1 1 auto;flex-direction:row;align-items:center;overflow:hidden;margin-left:7px}.ptcPlusToolPreview .ptcPlusFeatures{flex:0 1 auto;flex-wrap:nowrap;overflow:hidden;margin:0 0 0 7px}.ptcPlusToolSummaryLine{box-sizing:border-box;display:flex;min-width:0;min-height:20px;flex:1 1 auto;align-items:center;gap:7px;padding:0;color:inherit;line-height:20px}.ptcPlusToolSummary{box-sizing:border-box;display:flex;min-width:0;min-height:32px;align-items:center;gap:7px;padding:0;color:inherit;line-height:20px}.ptcPlusToolSummary[data-expandable=true]{cursor:pointer}.ptcPlusToolSummary[data-expandable=true]:hover .ptcPlusToolTitle{color:var(--dsw-alias-interactive-primary,#4d6bfe)}.ptcPlusToolSummary:focus-visible{outline:2px solid var(--dsw-alias-interactive-primary,#4d6bfe);outline-offset:2px}.ptcPlusToolLeading{display:flex;width:16px;height:20px;flex:none;align-items:center;justify-content:center;color:var(--dsw-alias-label-tertiary,#74777d)}.ptcPlusToolChevron{transition:transform .16s ease}.ptcPlusToolChevron[data-open=true]{transform:rotate(180deg)}.ptcPlusToolTitle{display:flex;height:20px;flex:none;align-items:center;font-size:13px;font-weight:500;line-height:20px}.ptcPlusToolState{display:flex;height:20px;flex:none;align-items:center;color:var(--dsw-alias-label-tertiary,#74777d);font-size:11px;line-height:20px}.ptcPlusToolSummaryLine[data-state=running] .ptcPlusToolState,.ptcPlusToolSummary[data-state=running] .ptcPlusToolState{color:var(--dsw-alias-interactive-primary,#4d6bfe)}.ptcPlusToolSummaryLine[data-state=error] .ptcPlusToolState,.ptcPlusToolSummary[data-state=error] .ptcPlusToolState{color:var(--dsw-alias-state-danger-primary,#c43d3d)}.ptcPlusToolSummaryLine[data-state=stopped] .ptcPlusToolState,.ptcPlusToolSummary[data-state=stopped] .ptcPlusToolState{color:var(--dsw-alias-state-warning-primary,#a15c00)}.ptcPlusToolSep{width:3px;height:3px;flex:none;border-radius:50%;background:var(--dsw-alias-label-tertiary,#74777d)}.ptcPlusToolDescription{display:flex;min-width:0;min-height:20px;flex:1 1 auto;align-items:center;overflow:hidden;color:var(--dsw-alias-label-secondary,#52565d);font-size:13px;line-height:20px;text-overflow:ellipsis;white-space:nowrap}.ptcPlusToolPreview .ptcPlusFeature{flex:none;max-width:180px;white-space:nowrap}.ptcPlusToolPreview .ptcPlusFeatureDetail{max-width:120px}.ptcPlusToolSummaryLine[data-state=error] .ptcPlusToolDescription,.ptcPlusToolSummary[data-state=error] .ptcPlusToolDescription{color:var(--dsw-alias-state-danger-primary,#c43d3d)}.ptcPlusToolSummaryLine[data-state=stopped] .ptcPlusToolDescription,.ptcPlusToolSummary[data-state=stopped] .ptcPlusToolDescription{color:var(--dsw-alias-state-warning-primary,#a15c00)}
729
+ .ptcPlusFeatures{display:flex;min-width:0;flex-wrap:wrap;gap:3px 14px;margin:0 0 5px 23px}.ptcPlusFeature{display:inline-flex;min-width:0;align-items:center;gap:5px;color:var(--dsw-alias-label-secondary,#52565d);font-size:11px;line-height:17px}.ptcPlusFeature::before{width:4px;height:4px;flex:none;border-radius:50%;background:var(--dsw-alias-interactive-primary,#4d6bfe);content:''}.ptcPlusFeatureName{font-weight:500}.ptcPlusFeatureDetail{min-width:0;overflow:hidden;color:var(--dsw-alias-label-tertiary,#74777d);font-family:ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}
730
+ .ptcPlusToolBody{margin:4px 0 8px 23px;border-left:2px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));background:var(--dsw-alias-bg-layer-2,rgba(38,49,72,.03))}.ptcPlusToolSection{display:flex;min-width:0;flex-direction:column;gap:4px;padding:9px 11px}.ptcPlusToolSection+.ptcPlusToolSection{border-top:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1))}.ptcPlusToolSectionLabel{color:var(--dsw-alias-label-tertiary,#74777d);font-size:10px;font-weight:600;line-height:16px;text-transform:uppercase}.ptcPlusToolCode{max-height:320px;margin:0;overflow:auto;color:inherit;font:12px/18px ui-monospace,SFMono-Regular,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.ptcPlusIoCard{display:flex;flex-direction:column;border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.1));border-radius:12px;background:var(--dsw-alias-markdown-code-block,rgba(38,49,72,.06));overflow:hidden}.ptcPlusIoText{max-height:320px;margin:0;padding:12px 16px;overflow:auto;color:var(--dsw-alias-label-secondary,#52565d);font:12px/18px ui-monospace,SFMono-Regular,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.ptcPlusIoText[data-error]{color:var(--dsw-alias-state-error-primary,#c43d3d)}.ptcPlusInspect{display:inline-flex;align-self:flex-start;align-items:center;gap:4px;margin:4px 0 2px 4px;padding:2px 8px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));border-radius:999px;background:var(--dsw-alias-bg-base,#fff);color:var(--dsw-alias-label-secondary,#52565d);cursor:pointer;opacity:0;font-size:11px;line-height:16px;transition:opacity .1s ease;display:inline-flex}.ptcPlusTool:hover .ptcPlusInspect,.ptcPlusInspect:focus-visible{opacity:1}.ptcPlusInspect:hover{background:var(--dsw-alias-interactive-bg-hover-solid,rgba(38,49,72,.06));color:var(--dsw-alias-label-primary,#18191c)}
731
+ @media(max-width:560px){.ptcPlusHeader{padding:12px}.ptcPlusFields{margin:0 12px}.ptcPlusRow{align-items:flex-start;flex-direction:column;gap:6px;padding:10px 0}.ptcPlusInput{width:100%}.ptcPlusFooter{align-items:stretch;flex-direction:column}.ptcPlusButton{width:100%}.ptcPlusFeatures,.ptcPlusToolBody{margin-left:0}.ptcPlusToolSummary .ptcPlusToolDescription{white-space:normal;overflow-wrap:anywhere}}
732
+ @media(prefers-reduced-motion:reduce){.ptcPlusHeader,.ptcPlusChevron,.ptcPlusBody,.ptcPlusButton,.ptcPlusActive,.ptcPlusToolChevron,.ptcPlusReplChevron,.ptcPlusReplDefinitionWrap,.ptcPlusInspect{transition:none}}
733
+ /* The summary button owns disclosure; definition content is a separate grid item. */
734
+ .ptcPlusReplBinding{padding:0;cursor:default}.ptcPlusReplBindingTrigger{appearance:none;display:grid;width:100%;grid-column:1/-1;grid-template-columns:minmax(0,1fr) 24px;gap:3px 8px;min-height:36px;padding:5px 12px;border:0;background:transparent;color:inherit;text-align:left;cursor:pointer;font:inherit;transition:background-color .16s ease}.ptcPlusReplBindingTrigger:hover,.ptcPlusReplBindingTrigger[aria-expanded=true]{background:color-mix(in srgb,var(--dsw-alias-interactive-primary,#4d6bfe) 5%,transparent)}.ptcPlusReplBindingTrigger:focus-visible{outline:2px solid var(--dsw-alias-interactive-primary,#4d6bfe);outline-offset:-2px}
735
+ /* High-contrast TypeScript-like token colors adapt to the active text theme. */
736
+ .ptcPlusReplCard .ptcPlusReplName[data-kind=variable]{color:color-mix(in srgb,#005cc5 78%,var(--dsw-alias-label-primary,#18191c))}
737
+ .ptcPlusReplCard .ptcPlusReplName[data-kind=function]{color:color-mix(in srgb,#795e26 78%,var(--dsw-alias-label-primary,#18191c))}
738
+ .ptcPlusReplCard .ptcPlusReplName[data-kind=class]{color:color-mix(in srgb,#267f99 78%,var(--dsw-alias-label-primary,#18191c))}
739
+ .ptcPlusReplCard .ptcPlusReplName[data-kind=import]{color:color-mix(in srgb,#af00db 78%,var(--dsw-alias-label-primary,#18191c))}
740
+ /* Keep the session-header action on the same compact 32px rhythm as DSH chrome. */
741
+ .ptcPlusActiveShell{display:inline-flex;height:28px;align-items:center;justify-content:center;line-height:0;vertical-align:middle}.ptcPlusActive{box-sizing:border-box;height:28px;justify-content:center;gap:6px;padding:0 6px;border:0;background:transparent;font-family:inherit;font-size:13px;font-weight:500;line-height:18px}.ptcPlusActive::before{width:6px;height:6px;flex:none;border-radius:50%;background:currentColor;box-shadow:0 0 0 2px color-mix(in srgb,currentColor 18%,transparent);content:''}.ptcPlusActive:hover,.ptcPlusActive[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06))}.ptcPlusActiveLabel{display:inline-flex;height:18px;align-items:center;line-height:18px}
185
742
  `;
743
+ var LOCALE_NS = "settings.ptcPlus";
744
+ var CHROME_COPY = Object.freeze({
745
+ zh: Object.freeze({
746
+ "card.description": "PTC \u6A21\u5F0F\u7684\u4F1A\u8BDD\u7EA7 TypeScript REPL\u3002",
747
+ "status.enabled": "\u5DF2\u542F\u7528",
748
+ "status.disabled": "\u5DF2\u505C\u7528",
749
+ "action.expand": "\u5C55\u5F00 PTC Plus \u8BBE\u7F6E",
750
+ "action.collapse": "\u6536\u8D77 PTC Plus \u8BBE\u7F6E",
751
+ "state.syncing": "\u6B63\u5728\u540C\u6B65\u8BBE\u7F6E...",
752
+ "state.unavailable": "\u5F53\u524D DSH \u5B9E\u4F8B\u672A\u63D0\u4F9B\u8BBE\u7F6E\u670D\u52A1",
753
+ "footer.live": "\u8BBE\u7F6E\u4F1A\u5728\u4FEE\u6539\u540E\u7ACB\u5373\u751F\u6548",
754
+ "footer.readOnly": "\u5F53\u524D\u8BBE\u7F6E\u4E3A\u53EA\u8BFB",
755
+ "status.applied": "\u8BBE\u7F6E\u5DF2\u7ACB\u5373\u751F\u6548",
756
+ "status.conflict": "\u8BBE\u7F6E\u672A\u751F\u6548\uFF0C\u8BF7\u68C0\u67E5\u8BBE\u7F6E\u51B2\u7A81",
757
+ "status.failed": "\u8BBE\u7F6E\u5931\u8D25\uFF1A{error}",
758
+ "indicator.title": "PTC Plus \u5DF2\u542F\u7528\uFF1B\u67E5\u770B\u5F53\u524D\u53EF\u590D\u7528\u7684 REPL \u7ED1\u5B9A",
759
+ "memory.title": "REPL \u53EF\u590D\u7528\u7ED1\u5B9A",
760
+ "memory.count": "{count} \u4E2A\u53EF\u590D\u7528\u7ED1\u5B9A",
761
+ "memory.empty": "\u5F53\u524D\u6CA1\u6709\u53EF\u590D\u7528\u7ED1\u5B9A",
762
+ "memory.unavailable": "\u5F53\u524D\u7ED1\u5B9A\u72B6\u6001\u5C1A\u4E0D\u53EF\u786E\u8BA4",
763
+ "memory.more": "\u53E6\u6709 {count} \u4E2A\u7ED1\u5B9A\u672A\u663E\u793A",
764
+ "memory.kind.variable": "\u53D8\u91CF",
765
+ "memory.kind.function": "\u51FD\u6570",
766
+ "memory.kind.class": "\u7C7B",
767
+ "memory.kind.import": "\u5BFC\u5165",
768
+ "memory.location": "\u7B2C {line} \u884C\uFF0C\u7B2C {column} \u5217",
769
+ "tool.code": "\u6267\u884C",
770
+ "tool.codeEdit": "\u4FEE\u6B63\u6267\u884C",
771
+ "tool.running": "\u6B63\u5728\u8FD0\u884C",
772
+ "tool.completed": "\u6267\u884C\u5B8C\u6210",
773
+ "tool.failed": "\u6267\u884C\u5931\u8D25",
774
+ "tool.stopped": "\u6267\u884C\u5DF2\u4E2D\u65AD",
775
+ "tool.source": "\u6E90\u7801",
776
+ "tool.result": "\u7ED3\u679C",
777
+ "tool.copy": "\u590D\u5236\u4EE3\u7801",
778
+ "tool.copied": "\u5DF2\u590D\u5236",
779
+ "tool.inspect": "\u68C0\u67E5\u8C03\u7528",
780
+ "feature.safeEdit": "\u5B89\u5168\u7F16\u8F91\u6267\u884C",
781
+ "feature.codeRun": "\u9694\u79BB\u6267\u884C code.run",
782
+ "feature.stateSaved": "\u4FDD\u5B58 REPL \u72B6\u6001",
783
+ "feature.stateRestored": "\u6062\u590D REPL \u72B6\u6001",
784
+ "feature.stateDeleted": "\u5220\u9664 REPL \u72B6\u6001"
785
+ }),
786
+ en: Object.freeze({
787
+ "card.description": "The session-bound TypeScript REPL for PTC mode.",
788
+ "status.enabled": "Enabled",
789
+ "status.disabled": "Disabled",
790
+ "action.expand": "Expand PTC Plus settings",
791
+ "action.collapse": "Collapse PTC Plus settings",
792
+ "state.syncing": "Syncing settings...",
793
+ "state.unavailable": "This DSH instance does not provide a settings service",
794
+ "footer.live": "Changes take effect immediately.",
795
+ "footer.readOnly": "These settings are read-only.",
796
+ "status.applied": "Setting applied immediately.",
797
+ "status.conflict": "The setting did not take effect; check for conflicting settings.",
798
+ "status.failed": "Could not save: {error}",
799
+ "indicator.title": "PTC Plus is active; view reusable REPL bindings",
800
+ "memory.title": "Reusable REPL bindings",
801
+ "memory.count": "{count} reusable bindings",
802
+ "memory.empty": "No reusable bindings",
803
+ "memory.unavailable": "Current binding state cannot be confirmed",
804
+ "memory.more": "{count} more bindings not shown",
805
+ "memory.kind.variable": "Variable",
806
+ "memory.kind.function": "Function",
807
+ "memory.kind.class": "Class",
808
+ "memory.kind.import": "Import",
809
+ "memory.location": "Line {line}, column {column}",
810
+ "tool.code": "Code",
811
+ "tool.codeEdit": "Code edit",
812
+ "tool.running": "Running",
813
+ "tool.completed": "Completed",
814
+ "tool.failed": "Failed",
815
+ "tool.stopped": "Stopped",
816
+ "tool.source": "Source",
817
+ "tool.result": "Result",
818
+ "tool.inspect": "Inspect call",
819
+ "feature.safeEdit": "Safe edit execution",
820
+ "feature.codeRun": "Isolated code.run execution",
821
+ "feature.stateSaved": "Saved REPL state",
822
+ "feature.stateRestored": "Restored REPL state",
823
+ "feature.stateDeleted": "Deleted REPL state",
824
+ "tool.copy": "Copy code",
825
+ "tool.copied": "Copied"
826
+ })
827
+ });
828
+ function fieldCopy(field, locale) {
829
+ const copy = { [`${field.key}.label`]: locale === "en" ? field.labelEn : field.label };
830
+ const description = locale === "en" ? field.descriptionEn : field.description;
831
+ if (description !== "") copy[`${field.key}.description`] = description;
832
+ return copy;
833
+ }
834
+ var SETTINGS_COPY = Object.freeze(Object.fromEntries(
835
+ ["zh", "en"].map((locale) => [locale, Object.freeze({
836
+ ...CHROME_COPY[locale],
837
+ ...Object.assign({}, ...CONFIG_GROUPS.map((group) => ({
838
+ [`group.${group.key}`]: locale === "en" ? group.labelEn : group.label
839
+ }))),
840
+ ...Object.assign({}, ...CONFIG_FIELDS.map((field) => fieldCopy(field, locale)))
841
+ })])
842
+ ));
843
+ function sessionUsesPtcPreset(session) {
844
+ const preset = session?.projectionValues?.agentPreset ?? session?.agentPreset;
845
+ return preset === "ptc" || preset === "code";
846
+ }
186
847
  window.__ModuleLoader__.load({
187
848
  // Replaced by the bundle entry with the package name from package.json.
188
849
  id: "dsh-ptc-plus",
189
850
  factory: (require2) => {
190
851
  const React = require2("react");
191
852
  const {
853
+ CodeBlock,
854
+ DisclosureRow,
192
855
  IconCheckOutline14,
193
856
  IconChevronDownOutline14,
194
- IconSettingsOutline16
857
+ IconInspectOutline12
195
858
  } = require2("@deepseek-ai/dsh-client-ui-primitives");
196
859
  const module = { exports: {} };
197
860
  const h = React.createElement;
@@ -204,7 +867,7 @@
204
867
  document.head.append(style);
205
868
  return () => style.remove();
206
869
  }
207
- function fieldInput(field, value, disabled, onChange) {
870
+ function fieldInput(field, value, disabled, onChange, label) {
208
871
  if (field.type === "boolean") {
209
872
  return h("input", {
210
873
  type: "checkbox",
@@ -212,7 +875,7 @@
212
875
  className: "ptcPlusCheck",
213
876
  checked: value === true,
214
877
  disabled,
215
- "aria-label": field.label,
878
+ "aria-label": label,
216
879
  onChange: (event) => onChange(field, event.target.checked)
217
880
  });
218
881
  }
@@ -224,7 +887,7 @@
224
887
  max: field.max,
225
888
  step: 1,
226
889
  disabled,
227
- "aria-label": field.label,
890
+ "aria-label": label,
228
891
  onChange: (event) => {
229
892
  const input = event.target.value;
230
893
  const parsed = input === "" ? "" : Number(input);
@@ -234,10 +897,11 @@
234
897
  }
235
898
  function apply(ctx) {
236
899
  const preferenceScope = ctx.settingsScope.bind({ namespace: SETTINGS_NAMESPACE });
900
+ ctx.effect(() => ctx.locale.register(LOCALE_NS, SETTINGS_COPY), "ptc-plus: settings dictionaries");
237
901
  ctx.effect(installStyles, "ptc-plus: client styles");
238
- function PTCPlusSettingsCard() {
902
+ function PTCPlusSettingsCard({ t }) {
239
903
  const [open, setOpen] = React.useState(false);
240
- const [status, setStatus] = React.useState("");
904
+ const [status, setStatus] = React.useState(null);
241
905
  const [pending, setPending] = React.useState(() => /* @__PURE__ */ new Set());
242
906
  const writeTail = React.useRef(Promise.resolve());
243
907
  const subscribe = React.useCallback((listener) => preferenceScope.subscribe(listener), []);
@@ -254,17 +918,20 @@
254
918
  if (field.key !== "enabled" && before.value?.enabled !== true) return;
255
919
  if (before.value?.[field.key] === nextValue) return;
256
920
  setPending((current) => new Set(current).add(field.key));
257
- setStatus("");
921
+ setStatus(null);
258
922
  try {
259
923
  await preferenceScope.set(field.key, nextValue);
260
924
  const after = preferenceScope.getSnapshot();
261
925
  if (after.status !== "ready" || after.value?.[field.key] !== nextValue) {
262
- setStatus("\u8BBE\u7F6E\u672A\u751F\u6548\uFF0C\u8BF7\u68C0\u67E5\u8BBE\u7F6E\u51B2\u7A81");
926
+ setStatus({ key: "status.conflict" });
263
927
  } else {
264
- setStatus("\u8BBE\u7F6E\u5DF2\u7ACB\u5373\u751F\u6548");
928
+ setStatus({ key: "status.applied" });
265
929
  }
266
930
  } catch (error) {
267
- setStatus("\u8BBE\u7F6E\u5931\u8D25\uFF1A" + (error instanceof Error ? error.message : String(error)));
931
+ setStatus({
932
+ key: "status.failed",
933
+ params: { error: error instanceof Error ? error.message : String(error) }
934
+ });
268
935
  } finally {
269
936
  setPending((current) => {
270
937
  const next = new Set(current);
@@ -277,6 +944,33 @@
277
944
  });
278
945
  };
279
946
  const fieldDisabled = (field) => unavailable || pending.has(field.key) || field.key !== "enabled" && !enabled;
947
+ const settingGroups = CONFIG_GROUPS.map((group) => h(
948
+ "section",
949
+ {
950
+ key: group.key,
951
+ className: "ptcPlusGroup",
952
+ "aria-labelledby": `ptc-plus-settings-group-${group.key}`
953
+ },
954
+ h("h3", {
955
+ id: `ptc-plus-settings-group-${group.key}`,
956
+ className: "ptcPlusGroupTitle"
957
+ }, t(`group.${group.key}`)),
958
+ ...group.fields.map((key) => {
959
+ const field = CONFIG_FIELDS.find((candidate) => candidate.key === key);
960
+ if (field === void 0) return null;
961
+ return h(
962
+ "div",
963
+ { key: field.key, className: "ptcPlusRow" },
964
+ h(
965
+ "div",
966
+ { className: "ptcPlusMain" },
967
+ h("div", { className: "ptcPlusLabel" }, t(`${field.key}.label`)),
968
+ field.description === "" ? null : h("div", { className: "ptcPlusDetail" }, t(`${field.key}.description`))
969
+ ),
970
+ fieldInput(field, value[field.key], fieldDisabled(field), persist, t(`${field.key}.label`))
971
+ );
972
+ })
973
+ ));
280
974
  return h(
281
975
  "li",
282
976
  { className: "ptcPlusCard" },
@@ -286,18 +980,17 @@
286
980
  type: "button",
287
981
  className: "ptcPlusHeader",
288
982
  "aria-expanded": open,
289
- "aria-label": open ? "\u6536\u8D77 PTC Plus \u8BBE\u7F6E" : "\u5C55\u5F00 PTC Plus \u8BBE\u7F6E",
983
+ "aria-label": t(open ? "action.collapse" : "action.expand"),
290
984
  "aria-controls": "ptc-plus-settings-body",
291
985
  onClick: () => setOpen((current) => !current)
292
986
  },
293
- h(IconSettingsOutline16, { size: 16 }),
294
987
  h(
295
988
  "span",
296
989
  { className: "ptcPlusHeadText" },
297
990
  h("span", { className: "ptcPlusName" }, "PTC Plus"),
298
- h("span", { className: "ptcPlusDescription" }, "PTC \u6A21\u5F0F\u7684\u4F1A\u8BDD\u7EA7 TypeScript REPL\u3002")
991
+ h("span", { className: "ptcPlusDescription" }, t("card.description"))
299
992
  ),
300
- h("span", { className: "ptcPlusStatus", "data-enabled": enabled }, enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u505C\u7528"),
993
+ h("span", { className: "ptcPlusStatus", "data-enabled": enabled }, t(enabled ? "status.enabled" : "status.disabled")),
301
994
  h("span", { className: "ptcPlusChevron", "data-open": open, "aria-hidden": true }, h(IconChevronDownOutline14, { size: 14 }))
302
995
  ),
303
996
  h(
@@ -306,22 +999,12 @@
306
999
  h("div", { className: "ptcPlusBodyInner" }, h(
307
1000
  "div",
308
1001
  { className: "ptcPlusFields" },
309
- snapshot.status === "loading" ? h("p", { className: "ptcPlusMessage" }, "\u6B63\u5728\u540C\u6B65\u8BBE\u7F6E...") : snapshot.status === "unavailable" ? h("p", { className: "ptcPlusMessage" }, "\u5F53\u524D DSH \u5B9E\u4F8B\u672A\u63D0\u4F9B\u8BBE\u7F6E\u670D\u52A1") : [
310
- ...CONFIG_FIELDS.map((field) => h(
311
- "div",
312
- { key: field.key, className: "ptcPlusRow" },
313
- h(
314
- "div",
315
- { className: "ptcPlusMain" },
316
- h("div", { className: "ptcPlusLabel" }, field.label),
317
- field.description === "" ? null : h("div", { className: "ptcPlusDetail" }, field.description)
318
- ),
319
- fieldInput(field, value[field.key], fieldDisabled(field), persist)
320
- )),
1002
+ snapshot.status === "loading" ? h("p", { className: "ptcPlusMessage" }, t("state.syncing")) : snapshot.status === "unavailable" ? h("p", { className: "ptcPlusMessage" }, t("state.unavailable")) : [
1003
+ ...settingGroups,
321
1004
  h(
322
1005
  "div",
323
1006
  { key: "footer", className: "ptcPlusFooter" },
324
- h("span", { className: "ptcPlusMessage", role: "status" }, status || (snapshot.writable ? "\u8BBE\u7F6E\u4F1A\u5728\u4FEE\u6539\u540E\u7ACB\u5373\u751F\u6548" : "\u5F53\u524D\u8BBE\u7F6E\u4E3A\u53EA\u8BFB"))
1007
+ h("span", { className: "ptcPlusMessage", role: "status" }, status === null ? t(snapshot.writable ? "footer.live" : "footer.readOnly") : t(status.key, status.params))
325
1008
  )
326
1009
  ]
327
1010
  ))
@@ -330,36 +1013,436 @@
330
1013
  }
331
1014
  ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
332
1015
  name: "settings.plugin.item",
333
- key: SETTINGS_NAMESPACE
1016
+ key: SETTINGS_NAMESPACE,
1017
+ locale: LOCALE_NS
334
1018
  }, PTCPlusSettingsCard));
1019
+ function PTCPlusToolRow({ toolName, block, inspect, t }) {
1020
+ const [open, setOpen] = React.useState(false);
1021
+ const view = derivePtcToolView(block, toolName);
1022
+ const expandable = view.code !== "" || view.output !== "" || typeof inspect === "function";
1023
+ const stateKey = {
1024
+ running: "tool.running",
1025
+ ok: "tool.completed",
1026
+ error: "tool.failed",
1027
+ stopped: "tool.stopped"
1028
+ }[view.state];
1029
+ const outputSummary = view.state === "error" && view.output !== "" ? view.output.split(/\r?\n/, 1)[0] : "";
1030
+ const summary = outputSummary || view.description;
1031
+ const stateText = view.state === "ok" ? null : t(stateKey);
1032
+ const toggle = () => {
1033
+ if (expandable) setOpen((current) => !current);
1034
+ };
1035
+ const summaryText = summary === "" ? null : summary;
1036
+ const summaryLine = stateText === null && summaryText === null ? null : h(
1037
+ "div",
1038
+ { className: "ptcPlusToolSummaryLine", "data-state": view.state, role: "status" },
1039
+ stateText === null ? null : h("span", { className: "ptcPlusToolState" }, stateText),
1040
+ summaryText === null ? null : h("span", { className: "ptcPlusToolSep", "aria-hidden": true }),
1041
+ summaryText === null ? null : h("span", { className: "ptcPlusToolDescription" }, summaryText)
1042
+ );
1043
+ const body = !open ? null : h(
1044
+ "div",
1045
+ { className: "ptcPlusToolBody" },
1046
+ view.code === "" ? null : h(
1047
+ "div",
1048
+ { className: "ptcPlusToolSection" },
1049
+ h("span", { className: "ptcPlusToolSectionLabel" }, t("tool.source")),
1050
+ typeof CodeBlock === "function" ? h(CodeBlock, {
1051
+ code: view.code,
1052
+ lang: "typescript",
1053
+ className: "ptcPlusToolCode",
1054
+ copyLabel: t("tool.copy"),
1055
+ copiedLabel: t("tool.copied")
1056
+ }) : h("pre", { className: "ptcPlusToolCode" }, view.code)
1057
+ ),
1058
+ view.output === "" ? null : h(
1059
+ "div",
1060
+ { className: "ptcPlusToolSection" },
1061
+ h("span", { className: "ptcPlusToolSectionLabel" }, t("tool.result")),
1062
+ h(
1063
+ "div",
1064
+ { className: "ptcPlusIoCard" },
1065
+ h("pre", {
1066
+ className: "ptcPlusIoText",
1067
+ "data-error": view.state === "error" || void 0
1068
+ }, view.output)
1069
+ )
1070
+ ),
1071
+ typeof inspect !== "function" ? null : h("button", {
1072
+ type: "button",
1073
+ className: "ptcPlusInspect",
1074
+ onClick: inspect
1075
+ }, h(IconInspectOutline12, { "aria-hidden": true }), t("tool.inspect"))
1076
+ );
1077
+ const features = view.features.length === 0 ? null : h(
1078
+ "div",
1079
+ { className: "ptcPlusFeatures" },
1080
+ view.features.map((feature) => h(
1081
+ "span",
1082
+ {
1083
+ key: `${feature.key}:${feature.detail}`,
1084
+ className: "ptcPlusFeature"
1085
+ },
1086
+ h("span", { className: "ptcPlusFeatureName" }, t(feature.key)),
1087
+ feature.detail === "" ? null : h("span", { className: "ptcPlusFeatureDetail", title: feature.detail }, feature.detail)
1088
+ ))
1089
+ );
1090
+ const collapsedContent = h("div", { className: "ptcPlusToolPreview" }, summaryLine, features);
1091
+ if (typeof DisclosureRow === "function") {
1092
+ return h(
1093
+ "div",
1094
+ { className: "ptcPlusTool" },
1095
+ h(DisclosureRow, {
1096
+ icon: expandable ? h(IconChevronDownOutline14, { size: 14 }) : h(IconCheckOutline14, { size: 14 }),
1097
+ title: t(toolName === "edit_run_code" ? "tool.codeEdit" : "tool.code"),
1098
+ open,
1099
+ expandable,
1100
+ onToggle: toggle,
1101
+ expandOnRowClick: true,
1102
+ previewChevron: false,
1103
+ keepContentWhenOpen: true,
1104
+ collapsedContent,
1105
+ children: body
1106
+ })
1107
+ );
1108
+ }
1109
+ return h(
1110
+ "div",
1111
+ { className: "ptcPlusTool" },
1112
+ h(
1113
+ "div",
1114
+ {
1115
+ className: "ptcPlusToolSummary",
1116
+ "data-state": view.state,
1117
+ "data-expandable": expandable || void 0,
1118
+ role: expandable ? "button" : void 0,
1119
+ tabIndex: expandable ? 0 : void 0,
1120
+ "aria-expanded": expandable ? open : void 0,
1121
+ onClick: expandable ? toggle : void 0,
1122
+ onKeyDown: expandable ? (event) => {
1123
+ if (event.key !== "Enter" && event.key !== " ") return;
1124
+ event.preventDefault();
1125
+ toggle();
1126
+ } : void 0
1127
+ },
1128
+ h("span", { className: "ptcPlusToolLeading", "aria-hidden": true }, expandable ? h(IconChevronDownOutline14, { size: 14, className: "ptcPlusToolChevron", "data-open": open }) : h(IconCheckOutline14, { size: 14 })),
1129
+ h("span", { className: "ptcPlusToolTitle" }, t(
1130
+ toolName === "edit_run_code" ? "tool.codeEdit" : "tool.code"
1131
+ )),
1132
+ view.state === "ok" ? null : h("span", { className: "ptcPlusToolState", role: "status" }, t(stateKey)),
1133
+ h("span", { className: "ptcPlusToolSep", "aria-hidden": true }),
1134
+ h("span", { className: "ptcPlusToolDescription" }, summary)
1135
+ ),
1136
+ features,
1137
+ body
1138
+ );
1139
+ }
1140
+ ctx.slots.inject("tool.call.toolview", () => {
1141
+ let releaseRows;
1142
+ const release = () => {
1143
+ releaseRows?.();
1144
+ releaseRows = void 0;
1145
+ };
1146
+ const sync = () => {
1147
+ const snapshot = preferenceScope.getSnapshot();
1148
+ const enabled = snapshot.status === "ready" && snapshot.value?.enabled === true && snapshot.value?.enhancedToolView !== false;
1149
+ if (enabled === (releaseRows !== void 0)) return;
1150
+ release();
1151
+ if (!enabled) return;
1152
+ const disposers = [];
1153
+ try {
1154
+ disposers.push(ctx.slots.register({
1155
+ name: "tool.call.toolview",
1156
+ key: "run_code",
1157
+ locale: LOCALE_NS
1158
+ }, PTCPlusToolRow));
1159
+ disposers.push(ctx.slots.register({
1160
+ name: "tool.call.toolview",
1161
+ key: "edit_run_code",
1162
+ locale: LOCALE_NS
1163
+ }, PTCPlusToolRow));
1164
+ } catch (error) {
1165
+ disposers.reverse().forEach((dispose) => dispose());
1166
+ throw error;
1167
+ }
1168
+ releaseRows = () => disposers.reverse().forEach((dispose) => dispose());
1169
+ };
1170
+ sync();
1171
+ const unsubscribe = preferenceScope.subscribe(sync);
1172
+ return () => {
1173
+ unsubscribe();
1174
+ release();
1175
+ };
1176
+ });
335
1177
  ctx.inject(["slots", "sessions"], (scope) => {
336
- function PTCPlusSessionIndicator({ sessionId }) {
337
- const sessions = React.useSyncExternalStore(
338
- (listener) => scope.sessions.list.subscribe(listener),
339
- () => scope.sessions.list.getSnapshot(),
340
- () => scope.sessions.list.getSnapshot()
1178
+ function replPopoverIsOpen(popover) {
1179
+ if (popover?.dataset?.open === "true") return true;
1180
+ try {
1181
+ return popover?.matches?.(":popover-open") === true;
1182
+ } catch {
1183
+ return false;
1184
+ }
1185
+ }
1186
+ function placeReplPopover(trigger, popover) {
1187
+ if (trigger === null || popover === null) return;
1188
+ const margin = 12;
1189
+ const gap = 8;
1190
+ const viewportWidth = document.documentElement.clientWidth || window.innerWidth;
1191
+ const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
1192
+ const triggerRect = trigger.getBoundingClientRect();
1193
+ const width = Math.min(344, Math.max(0, viewportWidth - margin * 2));
1194
+ const left = Math.min(
1195
+ Math.max(margin, triggerRect.right - width),
1196
+ Math.max(margin, viewportWidth - width - margin)
341
1197
  );
1198
+ const below = Math.max(0, viewportHeight - triggerRect.bottom - gap - margin);
1199
+ const above = Math.max(0, triggerRect.top - gap - margin);
1200
+ const opensAbove = below < 260 && above > below;
1201
+ const availableHeight = Math.max(80, opensAbove ? above : below);
1202
+ popover.style.width = `${width}px`;
1203
+ popover.style.maxHeight = `${availableHeight}px`;
1204
+ popover.style.left = `${left}px`;
1205
+ popover.style.top = opensAbove ? `${Math.max(margin, triggerRect.top - gap - Math.min(popover.offsetHeight, availableHeight))}px` : `${Math.min(viewportHeight - margin, triggerRect.bottom + gap)}px`;
1206
+ }
1207
+ function ReplMemoryCard({ memory, t, id, titleId, popoverRef, onEnter, onLeave }) {
1208
+ const [expandedBinding, setExpandedBinding] = React.useState(null);
1209
+ return h(
1210
+ "div",
1211
+ {
1212
+ className: "ptcPlusReplPopover",
1213
+ id,
1214
+ ref: popoverRef,
1215
+ popover: "auto",
1216
+ role: "dialog",
1217
+ "aria-labelledby": titleId,
1218
+ onPointerEnter: onEnter,
1219
+ onPointerLeave: onLeave
1220
+ },
1221
+ h(
1222
+ "div",
1223
+ { className: "ptcPlusReplCard" },
1224
+ h(
1225
+ "div",
1226
+ { className: "ptcPlusReplHead" },
1227
+ h("span", { className: "ptcPlusReplStatusDot", "aria-hidden": true }),
1228
+ h("span", { className: "ptcPlusReplTitle", id: titleId }, t("memory.title")),
1229
+ memory.available ? h("span", { className: "ptcPlusReplSummary" }, t("memory.count", { count: memory.total })) : null
1230
+ ),
1231
+ !memory.available ? h("span", { className: "ptcPlusReplEmpty" }, t("memory.unavailable")) : memory.entries.length === 0 ? h("span", { className: "ptcPlusReplEmpty" }, t("memory.empty")) : h("ul", { className: "ptcPlusReplList" }, memory.entries.map((binding, index) => {
1232
+ const expanded = expandedBinding === binding.name;
1233
+ const preview = binding.definition.source.replace(/\s+/g, " ").trim();
1234
+ const definitionId = `${id}-binding-${index}`;
1235
+ const toggle = () => setExpandedBinding((current) => current === binding.name ? null : binding.name);
1236
+ return h(
1237
+ "li",
1238
+ {
1239
+ className: "ptcPlusReplBinding",
1240
+ key: binding.name,
1241
+ "data-expanded": expanded
1242
+ },
1243
+ h(
1244
+ "button",
1245
+ {
1246
+ className: "ptcPlusReplBindingTrigger",
1247
+ type: "button",
1248
+ "aria-expanded": expanded,
1249
+ "aria-controls": expanded ? definitionId : void 0,
1250
+ onClick: toggle
1251
+ },
1252
+ h("span", {
1253
+ className: "ptcPlusReplName",
1254
+ "data-kind": binding.kind,
1255
+ title: `${binding.name} - ${t(`memory.kind.${binding.kind}`)}`
1256
+ }, binding.name),
1257
+ h("span", { className: "ptcPlusReplPreview", title: preview }, preview),
1258
+ h("span", {
1259
+ className: "ptcPlusReplChevron",
1260
+ "data-open": expanded,
1261
+ "aria-hidden": true
1262
+ }, h(IconChevronDownOutline14, { size: 14 }))
1263
+ ),
1264
+ expanded ? h("div", {
1265
+ className: "ptcPlusReplDefinitionWrap",
1266
+ "data-open": true,
1267
+ id: definitionId,
1268
+ role: "region",
1269
+ "aria-label": binding.name
1270
+ }, h(
1271
+ "div",
1272
+ { className: "ptcPlusReplDefinitionInner" },
1273
+ h(
1274
+ "div",
1275
+ { className: "ptcPlusReplDefinition" },
1276
+ h("span", { className: "ptcPlusReplLocation" }, t("memory.location", {
1277
+ line: binding.definition.line,
1278
+ column: binding.definition.column
1279
+ })),
1280
+ typeof CodeBlock === "function" ? h(CodeBlock, {
1281
+ code: binding.definition.source,
1282
+ lang: "typescript",
1283
+ className: "ptcPlusReplCode",
1284
+ copyLabel: t("tool.copy"),
1285
+ copiedLabel: t("tool.copied")
1286
+ }) : h("pre", { className: "ptcPlusReplCode" }, binding.definition.source)
1287
+ )
1288
+ )) : null
1289
+ );
1290
+ })),
1291
+ memory.omitted === 0 ? null : h("span", { className: "ptcPlusReplMore" }, t("memory.more", { count: memory.omitted }))
1292
+ )
1293
+ );
1294
+ }
1295
+ function PTCPlusSessionIndicator({ sessionId, t, useSession, useProjection, useSessions }) {
1296
+ let conversation;
1297
+ try {
1298
+ conversation = typeof useSession === "function" ? useSession((snapshot) => snapshot) : void 0;
1299
+ } catch {
1300
+ conversation = void 0;
1301
+ }
1302
+ let projectionMemory;
1303
+ try {
1304
+ projectionMemory = typeof useProjection === "function" ? useProjection("ptcPlusRepl") : void 0;
1305
+ } catch {
1306
+ projectionMemory = void 0;
1307
+ }
1308
+ let sessions;
1309
+ try {
1310
+ sessions = typeof useSessions === "function" ? useSessions((snapshot) => snapshot) : React.useSyncExternalStore(
1311
+ (listener) => scope.sessions?.list?.subscribe?.(listener) ?? (() => {
1312
+ }),
1313
+ () => scope.sessions?.list?.getSnapshot?.() ?? {},
1314
+ () => scope.sessions?.list?.getSnapshot?.() ?? {}
1315
+ );
1316
+ } catch {
1317
+ sessions = {};
1318
+ }
342
1319
  const settings = React.useSyncExternalStore(
343
1320
  (listener) => preferenceScope.subscribe(listener),
344
1321
  () => preferenceScope.getSnapshot(),
345
1322
  () => preferenceScope.getSnapshot()
346
1323
  );
347
- if (sessions.byId?.[sessionId]?.agentPreset !== "code" || settings.status !== "ready" || settings.value?.enabled !== true) return null;
1324
+ const triggerRef = React.useRef(null);
1325
+ const popoverRef = React.useRef(null);
1326
+ const closeTimer = React.useRef(void 0);
1327
+ const [expanded, setExpanded] = React.useState(false);
1328
+ const positionPopover = React.useCallback(() => {
1329
+ if (!replPopoverIsOpen(popoverRef.current)) return;
1330
+ placeReplPopover(triggerRef.current, popoverRef.current);
1331
+ }, []);
1332
+ const showPopover = React.useCallback(() => {
1333
+ if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
1334
+ const popover = popoverRef.current;
1335
+ if (popover === null) return;
1336
+ popover.style.visibility = "hidden";
1337
+ if (!replPopoverIsOpen(popover)) {
1338
+ if (typeof popover.showPopover === "function") {
1339
+ try {
1340
+ popover.showPopover();
1341
+ } catch {
1342
+ popover.dataset.open = "true";
1343
+ }
1344
+ } else {
1345
+ popover.dataset.open = "true";
1346
+ }
1347
+ }
1348
+ placeReplPopover(triggerRef.current, popover);
1349
+ popover.style.visibility = "visible";
1350
+ setExpanded(true);
1351
+ }, []);
1352
+ const hidePopover = React.useCallback(() => {
1353
+ const popover = popoverRef.current;
1354
+ if (popover === null) return;
1355
+ if (popover.dataset.open === "true") delete popover.dataset.open;
1356
+ if (typeof popover.hidePopover === "function" && replPopoverIsOpen(popover)) {
1357
+ try {
1358
+ popover.hidePopover();
1359
+ } catch {
1360
+ }
1361
+ }
1362
+ setExpanded(false);
1363
+ }, []);
1364
+ const scheduleHide = React.useCallback(() => {
1365
+ if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
1366
+ closeTimer.current = setTimeout(() => {
1367
+ closeTimer.current = void 0;
1368
+ if (document.activeElement === triggerRef.current || popoverRef.current?.contains(document.activeElement)) return;
1369
+ hidePopover();
1370
+ }, 120);
1371
+ }, [hidePopover]);
1372
+ React.useEffect(() => {
1373
+ const syncPopoverState = (event) => {
1374
+ if (event.target !== popoverRef.current) return;
1375
+ setExpanded(replPopoverIsOpen(popoverRef.current));
1376
+ };
1377
+ window.addEventListener("resize", positionPopover);
1378
+ document.addEventListener("scroll", positionPopover, true);
1379
+ document.addEventListener("toggle", syncPopoverState, true);
1380
+ return () => {
1381
+ if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
1382
+ window.removeEventListener("resize", positionPopover);
1383
+ document.removeEventListener("scroll", positionPopover, true);
1384
+ document.removeEventListener("toggle", syncPopoverState, true);
1385
+ const popover = popoverRef.current;
1386
+ if (popover?.dataset?.open === "true") delete popover.dataset.open;
1387
+ if (typeof popover?.hidePopover === "function" && replPopoverIsOpen(popover)) {
1388
+ try {
1389
+ popover.hidePopover();
1390
+ } catch {
1391
+ }
1392
+ }
1393
+ };
1394
+ }, [hidePopover, positionPopover]);
1395
+ const resolvedSessionId = sessionId ?? conversation?.sessionId;
1396
+ const session = sessions?.byId?.[resolvedSessionId] ?? conversation;
1397
+ if (!sessionUsesPtcPreset(session) || settings.status !== "ready" || settings.value?.enabled !== true) return null;
1398
+ let memory;
1399
+ try {
1400
+ memory = normalizeReplMemorySnapshot(projectionMemory ?? session?.projectionValues?.ptcPlusRepl);
1401
+ } catch {
1402
+ memory = unavailableReplMemorySnapshot();
1403
+ }
1404
+ const popoverId = `ptc-plus-repl-${String(resolvedSessionId).replace(/[^A-Za-z0-9_-]/g, "-")}`;
1405
+ const titleId = `${popoverId}-title`;
348
1406
  return h(
349
1407
  "span",
350
- { className: "ptcPlusActive", title: "PTC Plus \u5DF2\u542F\u7528" },
351
- h(IconCheckOutline14, { size: 14 }),
352
- "PTC Plus"
1408
+ { className: "ptcPlusActiveShell" },
1409
+ h("button", {
1410
+ type: "button",
1411
+ className: "ptcPlusActive",
1412
+ ref: triggerRef,
1413
+ "aria-label": t("indicator.title"),
1414
+ "aria-controls": popoverId,
1415
+ "aria-expanded": expanded,
1416
+ "aria-haspopup": "dialog",
1417
+ onPointerEnter: showPopover,
1418
+ onPointerLeave: scheduleHide,
1419
+ onFocus: showPopover,
1420
+ onBlur: scheduleHide,
1421
+ onClick: showPopover,
1422
+ onKeyDown: (event) => {
1423
+ if (event.key === "Escape") hidePopover();
1424
+ }
1425
+ }, h("span", { className: "ptcPlusActiveLabel" }, "PTC Plus")),
1426
+ h(ReplMemoryCard, {
1427
+ memory,
1428
+ t,
1429
+ id: popoverId,
1430
+ titleId,
1431
+ popoverRef,
1432
+ onEnter: showPopover,
1433
+ onLeave: scheduleHide
1434
+ })
353
1435
  );
354
1436
  }
355
1437
  scope.slots.inject("conversation.session.header.actions", () => scope.slots.register({
356
1438
  name: "conversation.session.header.actions",
357
1439
  id: "ptc-plus-active",
358
- order: -9
1440
+ order: -9,
1441
+ locale: LOCALE_NS
359
1442
  }, PTCPlusSessionIndicator));
360
1443
  });
361
1444
  }
362
- module.exports = { apply, inject: ["settingsScope", "slots", "sessions"] };
1445
+ module.exports = { apply, inject: ["settingsScope", "slots", "sessions", "locale"] };
363
1446
  return module.exports;
364
1447
  }
365
1448
  });