@hienlh/ppm 0.18.11 → 0.18.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +81 -23
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/package.json +1 -1
- package/.spike/cdp-client.ts +0 -116
- package/.spike/cleanup-ppm-workspace.mjs +0 -44
- package/.spike/group-protected-probe.ts +0 -21
- package/.spike/pip-eval.ts +0 -17
- package/.spike/pip-page-helpers.js +0 -119
- package/.spike/pip-results-editor-glue.json +0 -105
- package/.spike/pip-results-editor.json +0 -158
- package/.spike/pip-results-input-isolation.json +0 -28
- package/.spike/pip-results-key-probe.json +0 -58
- package/.spike/pip-results-listener-survival.json +0 -98
- package/.spike/pip-results-listeners.json +0 -36
- package/.spike/pip-results-pagehide.json +0 -92
- package/.spike/pip-results-resize.json +0 -104
- package/.spike/pip-results-terminal-debug.json +0 -99
- package/.spike/pip-results-terminal-v2.json +0 -191
- package/.spike/pip-results-terminal.json +0 -220
- package/.spike/pip-results-xterm-trace.json +0 -73
- package/.spike/pip-spike-common.ts +0 -83
- package/.spike/pip-spike-editor-glue.ts +0 -82
- package/.spike/pip-spike-editor.ts +0 -129
- package/.spike/pip-spike-input-isolation.ts +0 -38
- package/.spike/pip-spike-key-probe.ts +0 -34
- package/.spike/pip-spike-listener-survival.ts +0 -54
- package/.spike/pip-spike-listeners.ts +0 -19
- package/.spike/pip-spike-pagehide.ts +0 -59
- package/.spike/pip-spike-resize.ts +0 -42
- package/.spike/pip-spike-setup.ts +0 -63
- package/.spike/pip-spike-terminal-debug.ts +0 -81
- package/.spike/pip-spike-terminal-v2.ts +0 -139
- package/.spike/pip-spike-terminal.ts +0 -169
- package/.spike/pip-spike-xterm-trace.ts +0 -36
- package/.spike/probe-drag-memo-error.mjs +0 -67
- package/.spike/read-dev-db.ts +0 -15
- package/.spike/s.err +0 -63
- package/.spike/scratch-editor-target.ts +0 -7
- package/.spike/smoke-unified-chrome-pip.mjs +0 -353
- package/.spike/tunnel.err +0 -63
- package/.spike/vite-restart.err +0 -663
- package/.spike/w.err +0 -571
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"baselineTyping": {
|
|
3
|
-
"sent": false,
|
|
4
|
-
"echoed": true
|
|
5
|
-
},
|
|
6
|
-
"baselineSize": {
|
|
7
|
-
"rows": 44,
|
|
8
|
-
"cols": 145,
|
|
9
|
-
"canvases": 2
|
|
10
|
-
},
|
|
11
|
-
"move": {
|
|
12
|
-
"phase": "done",
|
|
13
|
-
"value": {
|
|
14
|
-
"styles": {
|
|
15
|
-
"inlineSheets": 10,
|
|
16
|
-
"clonedLinks": 2,
|
|
17
|
-
"failed": 0,
|
|
18
|
-
"rules": 1474
|
|
19
|
-
},
|
|
20
|
-
"moved": {
|
|
21
|
-
"adopted": true,
|
|
22
|
-
"slotTag": "DIV",
|
|
23
|
-
"slotHasWrapper": false
|
|
24
|
-
},
|
|
25
|
-
"pipSize": [
|
|
26
|
-
1395,
|
|
27
|
-
842
|
|
28
|
-
],
|
|
29
|
-
"rowsCols": [
|
|
30
|
-
54,
|
|
31
|
-
197
|
|
32
|
-
],
|
|
33
|
-
"canvasesNow": 2,
|
|
34
|
-
"gl": [
|
|
35
|
-
{
|
|
36
|
-
"webgl2": false
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"webgl2": true,
|
|
40
|
-
"lost": false
|
|
41
|
-
}
|
|
42
|
-
],
|
|
43
|
-
"glEvents": [],
|
|
44
|
-
"domRows": 0,
|
|
45
|
-
"theme": {
|
|
46
|
-
"pipHtmlClass": "dark",
|
|
47
|
-
"statusBg": "rgb(30, 32, 40)",
|
|
48
|
-
"mainSurfaceBg": "rgb(30, 32, 40)"
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
|
-
"pipAttached": true,
|
|
53
|
-
"afterFocusEmu": {
|
|
54
|
-
"canvases": 2,
|
|
55
|
-
"domRows": 0,
|
|
56
|
-
"glEvents": [],
|
|
57
|
-
"rowsCols": [
|
|
58
|
-
54,
|
|
59
|
-
197
|
|
60
|
-
],
|
|
61
|
-
"vis": "visible"
|
|
62
|
-
},
|
|
63
|
-
"shotInPip": "C:/Users/PC/ppm/plans/reports/screenshots/spike-01-terminal-in-pip.png",
|
|
64
|
-
"typingInPip": {
|
|
65
|
-
"sent": false,
|
|
66
|
-
"echoed": true
|
|
67
|
-
},
|
|
68
|
-
"shotTyped": "C:/Users/PC/ppm/plans/reports/screenshots/spike-01b-terminal-in-pip-typed.png",
|
|
69
|
-
"dragSelect": {
|
|
70
|
-
"row": 17,
|
|
71
|
-
"cell": {
|
|
72
|
-
"w": 7,
|
|
73
|
-
"h": 15
|
|
74
|
-
},
|
|
75
|
-
"selection": "T2-IN-PIP",
|
|
76
|
-
"pass": true
|
|
77
|
-
},
|
|
78
|
-
"resizeViaStyle": {
|
|
79
|
-
"before": [
|
|
80
|
-
54,
|
|
81
|
-
197
|
|
82
|
-
],
|
|
83
|
-
"after": [
|
|
84
|
-
26,
|
|
85
|
-
137
|
|
86
|
-
],
|
|
87
|
-
"restored": [
|
|
88
|
-
54,
|
|
89
|
-
197
|
|
90
|
-
],
|
|
91
|
-
"refit": true
|
|
92
|
-
},
|
|
93
|
-
"resizeViaWindow": {
|
|
94
|
-
"before": [
|
|
95
|
-
54,
|
|
96
|
-
197,
|
|
97
|
-
1395,
|
|
98
|
-
842
|
|
99
|
-
],
|
|
100
|
-
"after": [
|
|
101
|
-
54,
|
|
102
|
-
197,
|
|
103
|
-
684,
|
|
104
|
-
408
|
|
105
|
-
],
|
|
106
|
-
"resizeToResult": "ok",
|
|
107
|
-
"refit": false
|
|
108
|
-
},
|
|
109
|
-
"shotResized": "C:/Users/PC/ppm/plans/reports/screenshots/spike-01d-terminal-in-pip-resized.png",
|
|
110
|
-
"reactClickInPip": {
|
|
111
|
-
"probe": {
|
|
112
|
-
"mainDocClick": 0,
|
|
113
|
-
"pipDocClick": 1,
|
|
114
|
-
"wrapperClick": 1,
|
|
115
|
-
"reactRootClick": 0
|
|
116
|
-
},
|
|
117
|
-
"toast": "",
|
|
118
|
-
"reactHandlerFired": false
|
|
119
|
-
},
|
|
120
|
-
"pullback": {
|
|
121
|
-
"inPipBefore": true,
|
|
122
|
-
"afterSwitchAway": {
|
|
123
|
-
"inPip": false,
|
|
124
|
-
"display": "none",
|
|
125
|
-
"parentIsSlot": true
|
|
126
|
-
},
|
|
127
|
-
"afterSwitchBack": {
|
|
128
|
-
"inPip": false,
|
|
129
|
-
"display": ""
|
|
130
|
-
},
|
|
131
|
-
"note": "ReparentingTab layout effect re-appends wrapper into the panel slot on every re-render"
|
|
132
|
-
},
|
|
133
|
-
"ensureBack": {
|
|
134
|
-
"wasInPip": false,
|
|
135
|
-
"inMain": true
|
|
136
|
-
},
|
|
137
|
-
"afterReturnTyping": {
|
|
138
|
-
"sent": false,
|
|
139
|
-
"echoed": true
|
|
140
|
-
},
|
|
141
|
-
"afterReturnState": {
|
|
142
|
-
"rows": 41,
|
|
143
|
-
"cols": 145,
|
|
144
|
-
"canvases": 3,
|
|
145
|
-
"scrollback": {
|
|
146
|
-
"base": true,
|
|
147
|
-
"inPip": true,
|
|
148
|
-
"after": true
|
|
149
|
-
},
|
|
150
|
-
"reactClickToast": true
|
|
151
|
-
},
|
|
152
|
-
"pagehideGuard": {
|
|
153
|
-
"phase": "done",
|
|
154
|
-
"value": {
|
|
155
|
-
"inMain": true,
|
|
156
|
-
"closed": true
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
"afterPagehideTyping": {
|
|
160
|
-
"sent": false,
|
|
161
|
-
"echoed": false
|
|
162
|
-
},
|
|
163
|
-
"closeWithWrapperInside": {
|
|
164
|
-
"phase": "done",
|
|
165
|
-
"value": {
|
|
166
|
-
"ownerAfterClose": "dead-pip-doc",
|
|
167
|
-
"connected": true,
|
|
168
|
-
"inMainNow": true
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
"afterDestroyTyping": {
|
|
172
|
-
"sent": false,
|
|
173
|
-
"echoed": false
|
|
174
|
-
},
|
|
175
|
-
"afterDestroyInputApi": {
|
|
176
|
-
"sent": true,
|
|
177
|
-
"echoed": true
|
|
178
|
-
},
|
|
179
|
-
"log": [
|
|
180
|
-
"19:23:31.098 helpers installed",
|
|
181
|
-
"19:24:59.061 helpers installed",
|
|
182
|
-
"19:26:26.233 helpers installed",
|
|
183
|
-
"19:28:51.146 helpers installed",
|
|
184
|
-
"19:29:51.270 helpers installed",
|
|
185
|
-
"19:30:44.854 helpers installed",
|
|
186
|
-
"19:32:40.112 helpers installed",
|
|
187
|
-
"19:32:53.797 pagehide: moved back",
|
|
188
|
-
"19:32:54.430 pagehide: moved back",
|
|
189
|
-
"19:32:54.943 pagehide: moved back"
|
|
190
|
-
]
|
|
191
|
-
}
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"reset": {
|
|
3
|
-
"hadPip": true,
|
|
4
|
-
"twInPip": false
|
|
5
|
-
},
|
|
6
|
-
"baseline": {
|
|
7
|
-
"rows": 54,
|
|
8
|
-
"cols": 197,
|
|
9
|
-
"echoed": true,
|
|
10
|
-
"renderer": "2 canvas"
|
|
11
|
-
},
|
|
12
|
-
"move": {
|
|
13
|
-
"phase": "done",
|
|
14
|
-
"value": {
|
|
15
|
-
"styles": {
|
|
16
|
-
"inlineSheets": 9,
|
|
17
|
-
"clonedLinks": 2,
|
|
18
|
-
"failed": 0,
|
|
19
|
-
"rules": 1471
|
|
20
|
-
},
|
|
21
|
-
"moved": {
|
|
22
|
-
"adopted": true,
|
|
23
|
-
"slotTag": "DIV",
|
|
24
|
-
"slotHasWrapper": false
|
|
25
|
-
},
|
|
26
|
-
"rowsCols": {
|
|
27
|
-
"rows": 54,
|
|
28
|
-
"cols": 197
|
|
29
|
-
},
|
|
30
|
-
"xtermRect": {
|
|
31
|
-
"w": 1387,
|
|
32
|
-
"h": 810
|
|
33
|
-
},
|
|
34
|
-
"canvases": [
|
|
35
|
-
{
|
|
36
|
-
"w": 1379,
|
|
37
|
-
"h": 810,
|
|
38
|
-
"ctx": "n/a"
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
"w": 1379,
|
|
42
|
-
"h": 810,
|
|
43
|
-
"ctx": "n/a"
|
|
44
|
-
}
|
|
45
|
-
],
|
|
46
|
-
"pipInner": {
|
|
47
|
-
"w": 1395,
|
|
48
|
-
"h": 842
|
|
49
|
-
},
|
|
50
|
-
"mainHasFocus": false,
|
|
51
|
-
"pipHasFocus": true,
|
|
52
|
-
"themeBg": "rgb(30, 32, 40)",
|
|
53
|
-
"mainThemeBg": "rgb(21, 22, 28)",
|
|
54
|
-
"pipHtmlClass": "dark"
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
"stillInPipAfterIdle": true,
|
|
58
|
-
"newTargets": [
|
|
59
|
-
{
|
|
60
|
-
"targetId": "F30BC13FB06D945181B894D00452D99E",
|
|
61
|
-
"type": "page",
|
|
62
|
-
"title": "about:blank",
|
|
63
|
-
"url": "about:blank",
|
|
64
|
-
"attached": false,
|
|
65
|
-
"openerId": "ABD2ADD39468D5F37A57F99D622368A1",
|
|
66
|
-
"canAccessOpener": true,
|
|
67
|
-
"openerFrameId": "ABD2ADD39468D5F37A57F99D622368A1",
|
|
68
|
-
"browserContextId": "8871A9D7F4E65EDDCED25B9DFAE50EEC"
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
"targetId": "69387E9109CA8AB281C29D852AE899B2",
|
|
72
|
-
"type": "browser_ui",
|
|
73
|
-
"title": "Omnibox Popup",
|
|
74
|
-
"url": "chrome://omnibox-popup.top-chrome/omnibox_popup_aim.html",
|
|
75
|
-
"attached": false,
|
|
76
|
-
"canAccessOpener": false,
|
|
77
|
-
"browserContextId": "8871A9D7F4E65EDDCED25B9DFAE50EEC"
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
"targetId": "6C54FB1DE5371071C9BA64B3569662BC",
|
|
81
|
-
"type": "browser_ui",
|
|
82
|
-
"title": "Omnibox Popup",
|
|
83
|
-
"url": "chrome://omnibox-popup.top-chrome/",
|
|
84
|
-
"attached": false,
|
|
85
|
-
"canAccessOpener": false,
|
|
86
|
-
"browserContextId": "8871A9D7F4E65EDDCED25B9DFAE50EEC"
|
|
87
|
-
}
|
|
88
|
-
],
|
|
89
|
-
"pipAttached": true,
|
|
90
|
-
"pipTargetInfo": {
|
|
91
|
-
"url": "about:blank",
|
|
92
|
-
"w": 1395,
|
|
93
|
-
"h": 842,
|
|
94
|
-
"hasWrapper": true,
|
|
95
|
-
"title": ""
|
|
96
|
-
},
|
|
97
|
-
"shot1": {
|
|
98
|
-
"screen": "FAILED (Exception calling \"CopyFromScreen\" with \"3\" argument(s): \"The handle is invalid\")",
|
|
99
|
-
"pip": "C:/Users/PC/ppm/plans/reports/screenshots/spike-01-terminal-in-pip.png"
|
|
100
|
-
},
|
|
101
|
-
"typingTrustedInPip": false,
|
|
102
|
-
"typingSyntheticInPip": {
|
|
103
|
-
"echoed": false,
|
|
104
|
-
"activeInPip": true
|
|
105
|
-
},
|
|
106
|
-
"dragSelectTrustedInPip": {
|
|
107
|
-
"selection": "",
|
|
108
|
-
"rect": {
|
|
109
|
-
"x": 4,
|
|
110
|
-
"y": 33,
|
|
111
|
-
"w": 1379,
|
|
112
|
-
"h": 810
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
"dragSelectSyntheticInPip": {
|
|
116
|
-
"viaPipDoc": "",
|
|
117
|
-
"viaMainDoc": ""
|
|
118
|
-
},
|
|
119
|
-
"resizeViaStyle": {
|
|
120
|
-
"before": {
|
|
121
|
-
"rows": 54,
|
|
122
|
-
"cols": 197
|
|
123
|
-
},
|
|
124
|
-
"after": {
|
|
125
|
-
"rows": 54,
|
|
126
|
-
"cols": 197
|
|
127
|
-
},
|
|
128
|
-
"restored": {
|
|
129
|
-
"rows": 54,
|
|
130
|
-
"cols": 197
|
|
131
|
-
},
|
|
132
|
-
"refit": false
|
|
133
|
-
},
|
|
134
|
-
"resizeViaWindow": {
|
|
135
|
-
"before": {
|
|
136
|
-
"rows": 54,
|
|
137
|
-
"cols": 197,
|
|
138
|
-
"w": 1395,
|
|
139
|
-
"h": 842
|
|
140
|
-
},
|
|
141
|
-
"after": {
|
|
142
|
-
"rows": 54,
|
|
143
|
-
"cols": 197,
|
|
144
|
-
"w": 1395,
|
|
145
|
-
"h": 842
|
|
146
|
-
},
|
|
147
|
-
"err": "NotAllowedError: Failed to execute 'resizeTo' on 'Window': resizeTo() requires user activation in document picture-in-picture"
|
|
148
|
-
},
|
|
149
|
-
"reactClick": {
|
|
150
|
-
"probeBefore": {
|
|
151
|
-
"mainDocClick": 0,
|
|
152
|
-
"pipDocClick": 1,
|
|
153
|
-
"wrapperClick": 1,
|
|
154
|
-
"reactRootClick": 0
|
|
155
|
-
},
|
|
156
|
-
"probeAfter": {
|
|
157
|
-
"mainDocClick": 0,
|
|
158
|
-
"pipDocClick": 2,
|
|
159
|
-
"wrapperClick": 2,
|
|
160
|
-
"reactRootClick": 0
|
|
161
|
-
},
|
|
162
|
-
"toast": "",
|
|
163
|
-
"synthetic": true
|
|
164
|
-
},
|
|
165
|
-
"reactClickTrusted": {
|
|
166
|
-
"probe": {
|
|
167
|
-
"mainDocClick": 0,
|
|
168
|
-
"pipDocClick": 3,
|
|
169
|
-
"wrapperClick": 3,
|
|
170
|
-
"reactRootClick": 0
|
|
171
|
-
},
|
|
172
|
-
"toast": ""
|
|
173
|
-
},
|
|
174
|
-
"pullbackProbe": {
|
|
175
|
-
"inPipBefore": true,
|
|
176
|
-
"inPipAfterTabClick": true,
|
|
177
|
-
"found": true
|
|
178
|
-
},
|
|
179
|
-
"shot2": "C:/Users/PC/ppm/plans/reports/screenshots/spike-01b-terminal-pip-after-resize.png",
|
|
180
|
-
"back": {
|
|
181
|
-
"wasInPip": true,
|
|
182
|
-
"back": {
|
|
183
|
-
"back": true
|
|
184
|
-
},
|
|
185
|
-
"rows": 47,
|
|
186
|
-
"cols": 147,
|
|
187
|
-
"scrollbackKept": {
|
|
188
|
-
"before": true,
|
|
189
|
-
"trusted": false,
|
|
190
|
-
"synth": false
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
"afterReturn": {
|
|
194
|
-
"echoed": false,
|
|
195
|
-
"rows": 47,
|
|
196
|
-
"cols": 147,
|
|
197
|
-
"reactClickControl": {
|
|
198
|
-
"probeBefore": {
|
|
199
|
-
"mainDocClick": 2,
|
|
200
|
-
"pipDocClick": 3,
|
|
201
|
-
"wrapperClick": 3,
|
|
202
|
-
"reactRootClick": 2
|
|
203
|
-
},
|
|
204
|
-
"probeAfter": {
|
|
205
|
-
"mainDocClick": 4,
|
|
206
|
-
"pipDocClick": 3,
|
|
207
|
-
"wrapperClick": 4,
|
|
208
|
-
"reactRootClick": 4
|
|
209
|
-
},
|
|
210
|
-
"toast": "Sent to chat"
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
"log": [
|
|
214
|
-
"19:16:07.504 helpers installed",
|
|
215
|
-
"19:17:40.004 helpers installed",
|
|
216
|
-
"19:19:47.238 helpers installed",
|
|
217
|
-
"19:19:47.243 pip pagehide",
|
|
218
|
-
"19:20:40.863 pip pagehide"
|
|
219
|
-
]
|
|
220
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"roundTripped_setup": {
|
|
3
|
-
"wrapped": [
|
|
4
|
-
"ok:keyDown",
|
|
5
|
-
"ok:keyPress",
|
|
6
|
-
"ok:inputEvent",
|
|
7
|
-
"ok:thirdLevel",
|
|
8
|
-
"ok:composition.keydown",
|
|
9
|
-
"ok:evaluateKeyDown",
|
|
10
|
-
"ok:triggerData"
|
|
11
|
-
],
|
|
12
|
-
"state": {
|
|
13
|
-
"unprocessedDeadKey": false,
|
|
14
|
-
"keyDownHandled": false,
|
|
15
|
-
"keyPressHandled": false,
|
|
16
|
-
"isComposing": false,
|
|
17
|
-
"isSending": false,
|
|
18
|
-
"useKitty": false,
|
|
19
|
-
"useWin32": false,
|
|
20
|
-
"customHandler": false,
|
|
21
|
-
"disableStdin": false,
|
|
22
|
-
"screenReader": false,
|
|
23
|
-
"textareaOwner": true,
|
|
24
|
-
"browser": {
|
|
25
|
-
"isWindows": true,
|
|
26
|
-
"isMac": false
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
"roundTripped_trace": [],
|
|
31
|
-
"fresh_setup": {
|
|
32
|
-
"wrapped": [
|
|
33
|
-
"ok:keyDown",
|
|
34
|
-
"ok:keyPress",
|
|
35
|
-
"ok:inputEvent",
|
|
36
|
-
"ok:thirdLevel",
|
|
37
|
-
"ok:composition.keydown",
|
|
38
|
-
"ok:evaluateKeyDown",
|
|
39
|
-
"ok:triggerData"
|
|
40
|
-
],
|
|
41
|
-
"state": {
|
|
42
|
-
"unprocessedDeadKey": false,
|
|
43
|
-
"keyDownHandled": false,
|
|
44
|
-
"keyPressHandled": false,
|
|
45
|
-
"isComposing": false,
|
|
46
|
-
"isSending": false,
|
|
47
|
-
"useKitty": false,
|
|
48
|
-
"useWin32": false,
|
|
49
|
-
"customHandler": false,
|
|
50
|
-
"disableStdin": false,
|
|
51
|
-
"screenReader": false,
|
|
52
|
-
"textareaOwner": true,
|
|
53
|
-
"browser": {
|
|
54
|
-
"isWindows": true,
|
|
55
|
-
"isMac": false
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
"fresh_trace": [
|
|
60
|
-
"composition.keydown -> true",
|
|
61
|
-
"evaluateKeyDown -> {\"type\":0,\"cancel\":false}",
|
|
62
|
-
"thirdLevel -> false",
|
|
63
|
-
"keyDown -> true",
|
|
64
|
-
"triggerData -> undefined",
|
|
65
|
-
"keyPress -> true",
|
|
66
|
-
"inputEvent -> false",
|
|
67
|
-
"composition.keydown -> true",
|
|
68
|
-
"evaluateKeyDown -> {\"type\":0,\"cancel\":true,\"key\":\"\\r\"}",
|
|
69
|
-
"thirdLevel -> false",
|
|
70
|
-
"triggerData -> undefined",
|
|
71
|
-
"keyDown -> false"
|
|
72
|
-
]
|
|
73
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
// Shared harness for the Document PiP spike stages (terminal / editor).
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { CdpClient, sleep } from "./cdp-client";
|
|
4
|
-
|
|
5
|
-
export const APP = "http://localhost:5173";
|
|
6
|
-
export const SHOTS = "C:/Users/PC/ppm/plans/reports/screenshots";
|
|
7
|
-
export { sleep };
|
|
8
|
-
|
|
9
|
-
export async function connectApp() {
|
|
10
|
-
const cdp = await CdpClient.connect(9333);
|
|
11
|
-
const page = (await cdp.targets()).find((t) => t.type === "page" && t.url.startsWith(APP));
|
|
12
|
-
if (!page) throw new Error("no app page target");
|
|
13
|
-
const sid = await cdp.attach(page.targetId);
|
|
14
|
-
await cdp.send("Page.enable", {}, sid);
|
|
15
|
-
await cdp.send("Runtime.enable", {}, sid);
|
|
16
|
-
const helpers = await Bun.file(join(import.meta.dir, "pip-page-helpers.js")).text();
|
|
17
|
-
await cdp.eval(sid, helpers);
|
|
18
|
-
const knownTargets = new Set((await cdp.targets()).map((t) => t.targetId));
|
|
19
|
-
|
|
20
|
-
const ev = <T = unknown>(expr: string) => cdp.eval<T>(sid, expr);
|
|
21
|
-
async function waitFor(expr: string, timeoutMs = 20000, label = expr) {
|
|
22
|
-
const t0 = Date.now();
|
|
23
|
-
while (Date.now() - t0 < timeoutMs) {
|
|
24
|
-
if (await ev<boolean>(`!!(${expr})`)) return;
|
|
25
|
-
await sleep(250);
|
|
26
|
-
}
|
|
27
|
-
throw new Error(`timeout waiting: ${label}`);
|
|
28
|
-
}
|
|
29
|
-
async function openViaUrl(path: string) {
|
|
30
|
-
await ev(`history.pushState(null, '', ${JSON.stringify(path)}); dispatchEvent(new PopStateEvent('popstate')); 'ok'`);
|
|
31
|
-
await sleep(600);
|
|
32
|
-
}
|
|
33
|
-
/** Click the injected trusted-gesture button and wait for its async work to settle. */
|
|
34
|
-
async function runGesture(id: string, fnSource: string, timeoutMs = 20000) {
|
|
35
|
-
const pt = await ev<{ x: number; y: number }>(`window.__spike.installButton(${JSON.stringify(id)}, ${fnSource})`);
|
|
36
|
-
await cdp.click(sid, pt.x, pt.y);
|
|
37
|
-
const t0 = Date.now();
|
|
38
|
-
while (Date.now() - t0 < timeoutMs) {
|
|
39
|
-
const r = await ev<any>(`window.__spike.results[${JSON.stringify(id)}]`);
|
|
40
|
-
if (r && r.phase !== "running") return r;
|
|
41
|
-
await sleep(200);
|
|
42
|
-
}
|
|
43
|
-
throw new Error(`gesture ${id} timed out`);
|
|
44
|
-
}
|
|
45
|
-
/** Any CDP target that appeared since connect (candidate PiP window). */
|
|
46
|
-
async function newTargets() {
|
|
47
|
-
return (await cdp.targets()).filter((t) => !knownTargets.has(t.targetId));
|
|
48
|
-
}
|
|
49
|
-
/** Whole-screen capture via PowerShell (PiP is a separate always-on-top OS window). */
|
|
50
|
-
async function screenShot(name: string) {
|
|
51
|
-
const out = `${SHOTS}/${name}`;
|
|
52
|
-
const ps = `Add-Type -AssemblyName System.Windows.Forms; Add-Type -AssemblyName System.Drawing; $b=[System.Windows.Forms.Screen]::PrimaryScreen.Bounds; $bmp=New-Object System.Drawing.Bitmap $b.Width,$b.Height; $g=[System.Drawing.Graphics]::FromImage($bmp); $g.CopyFromScreen($b.Location,[System.Drawing.Point]::Empty,$b.Size); $bmp.Save('${out}',[System.Drawing.Imaging.ImageFormat]::Png); $g.Dispose(); $bmp.Dispose(); 'saved'`;
|
|
53
|
-
const p = Bun.spawn(["powershell", "-NoProfile", "-Command", ps], { stdout: "pipe", stderr: "pipe" });
|
|
54
|
-
await p.exited;
|
|
55
|
-
const err = await new Response(p.stderr).text();
|
|
56
|
-
return p.exitCode === 0 && !err ? out : `FAILED (${err.split("\n")[0]?.trim()})`;
|
|
57
|
-
}
|
|
58
|
-
/** Attach to the PiP window (an about:blank page target created after connect). */
|
|
59
|
-
async function attachPip(): Promise<string | null> {
|
|
60
|
-
const cands = (await newTargets()).filter((t) => t.type === "page");
|
|
61
|
-
for (const t of cands) {
|
|
62
|
-
try { return await cdp.attach(t.targetId); } catch { /* try next */ }
|
|
63
|
-
}
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
/** Page.captureScreenshot of the PiP target — works even when the OS desktop is not capturable. */
|
|
67
|
-
async function pipShot(pipSid: string | null, name: string) {
|
|
68
|
-
if (!pipSid) return "no pip session";
|
|
69
|
-
const out = `${SHOTS}/${name}`;
|
|
70
|
-
await cdp.screenshot(pipSid, out);
|
|
71
|
-
return out;
|
|
72
|
-
}
|
|
73
|
-
return { cdp, sid, ev, waitFor, openViaUrl, runGesture, newTargets, screenShot, attachPip, pipShot };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export type Harness = Awaited<ReturnType<typeof connectApp>>;
|
|
77
|
-
|
|
78
|
-
export async function saveResults(name: string, data: unknown) {
|
|
79
|
-
const path = join(import.meta.dir, name);
|
|
80
|
-
await Bun.write(path, JSON.stringify(data, null, 2));
|
|
81
|
-
console.log(JSON.stringify(data, null, 2));
|
|
82
|
-
console.log("saved", path);
|
|
83
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
// Stage 3b: Monaco glue candidates — editContext:false for typing, explicit editor.layout() on pip resize, suggest widget placement.
|
|
2
|
-
import { connectApp, saveResults, sleep } from "./pip-spike-common";
|
|
3
|
-
|
|
4
|
-
const W = `window.__spike.ew`, E = `window.__spike.ed`;
|
|
5
|
-
const R: Record<string, unknown> = {};
|
|
6
|
-
const h = await connectApp();
|
|
7
|
-
const { ev, cdp, sid } = h;
|
|
8
|
-
await cdp.send("Emulation.setFocusEmulationEnabled", { enabled: true }, sid);
|
|
9
|
-
await ev(`(() => { const S = window.__spike; if (S.pip && !S.pip.closed) { if (S.ew && S.ew.ownerDocument !== document) S.moveBack(S.ew); S.pip.close(); } S.pip = null; S.results = {}; return 'reset'; })()`);
|
|
10
|
-
await h.openViaUrl("/project/ppm/editor/.spike/scratch-editor-target.ts");
|
|
11
|
-
await sleep(800);
|
|
12
|
-
await ev(`window.__spike.ew = document.querySelector('[data-tab-pool-id="editor:.spike/scratch-editor-target.ts"]'); window.__spike.ed = window.__spike.findEditor(window.__spike.ew); 'held'`);
|
|
13
|
-
R.mainState = await ev(`({ layout: [${E}.getLayoutInfo().width, ${E}.getLayoutInfo().height], slot: [${W}.offsetWidth, ${W}.offsetHeight], editContextOpt: ${E}.getOption(window.monaco.editor.EditorOption.editContext), nativeEditContextEl: !!${W}.querySelector('.native-edit-context'), editContextApi: 'EditContext' in window, minimapEnabled: ${E}.getOption(window.monaco.editor.EditorOption.minimap).enabled })`);
|
|
14
|
-
R.layoutFixInMain = await ev(`(() => { ${E}.layout(); return [${E}.getLayoutInfo().width, ${E}.getLayoutInfo().height]; })()`);
|
|
15
|
-
|
|
16
|
-
R.move = await h.runGesture("pip-editor-glue", `async () => {
|
|
17
|
-
const S = window.__spike; const w = ${W}; const ed = ${E};
|
|
18
|
-
const pip = await documentPictureInPicture.requestWindow({ width: 900, height: 600 }); S.pip = pip; S.copyStyles(pip.document); S.moveToPip(pip, w); S.pinToPip(w);
|
|
19
|
-
S.pipResizes = 0; pip.addEventListener('resize', () => { S.pipResizes++; ed.layout(); });
|
|
20
|
-
await new Promise(r => setTimeout(r, 600));
|
|
21
|
-
const before = [ed.getLayoutInfo().width, ed.getLayoutInfo().height]; ed.layout();
|
|
22
|
-
return { pipSize: [pip.innerWidth, pip.innerHeight], layoutBeforeExplicit: before, layoutAfterExplicit: [ed.getLayoutInfo().width, ed.getLayoutInfo().height], wrapper: [w.offsetWidth, w.offsetHeight] };
|
|
23
|
-
}`);
|
|
24
|
-
const pipSid = await h.attachPip();
|
|
25
|
-
await cdp.send("Emulation.setFocusEmulationEnabled", { enabled: true }, pipSid!);
|
|
26
|
-
await sleep(400);
|
|
27
|
-
|
|
28
|
-
// Typing with EditContext (default)
|
|
29
|
-
await ev(`${E}.setPosition({ lineNumber: 2, column: 1 }); 'p'`);
|
|
30
|
-
R.pipFocusTarget = await cdp.eval(pipSid!, `(() => { const nec = document.querySelector('.native-edit-context'); const ta = document.querySelector('.monaco-editor textarea'); (nec || ta).focus(); return { focused: document.activeElement.className, hasEditContext: !!(nec && nec.editContext) }; })()`);
|
|
31
|
-
await cdp.typeText(pipSid!, "EC ");
|
|
32
|
-
await sleep(300);
|
|
33
|
-
R.typingEditContext = await ev(`({ line2: ${E}.getModel().getLineContent(2), pass: ${E}.getModel().getLineContent(2).startsWith('EC ') })`);
|
|
34
|
-
// Also try Input.insertText (IME-style commit) with EditContext
|
|
35
|
-
await cdp.send("Input.insertText", { text: "IT " }, pipSid!);
|
|
36
|
-
await sleep(300);
|
|
37
|
-
R.insertTextEditContext = await ev(`({ line2: ${E}.getModel().getLineContent(2), pass: ${E}.getModel().getLineContent(2).includes('IT ') })`);
|
|
38
|
-
|
|
39
|
-
// Switch to textarea input and type again
|
|
40
|
-
R.switchToTextarea = await ev(`(async () => { ${E}.updateOptions({ editContext: false }); await new Promise(r => setTimeout(r, 300)); return { editContextOpt: ${E}.getOption(window.monaco.editor.EditorOption.editContext), textarea: !!${W}.querySelector('.monaco-editor textarea'), nec: !!${W}.querySelector('.native-edit-context') }; })()`);
|
|
41
|
-
await ev(`${E}.setPosition({ lineNumber: 2, column: 1 }); 'p'`);
|
|
42
|
-
await cdp.eval(pipSid!, `document.querySelector('.monaco-editor textarea').focus(); document.activeElement.className`);
|
|
43
|
-
await cdp.typeText(pipSid!, "TA ");
|
|
44
|
-
await sleep(300);
|
|
45
|
-
R.typingTextarea = await ev(`({ line2: ${E}.getModel().getLineContent(2), pass: ${E}.getModel().getLineContent(2).startsWith('TA ') })`);
|
|
46
|
-
await h.pipShot(pipSid, "spike-02c-editor-in-pip-typed.png");
|
|
47
|
-
|
|
48
|
-
// Suggest widget placement (textarea mode): type "spi" on a new line then Ctrl+Space
|
|
49
|
-
await ev(`${E}.setPosition({ lineNumber: 8, column: 1 }); 'p'`);
|
|
50
|
-
await cdp.eval(pipSid!, `document.querySelector('.monaco-editor textarea').focus(); 'f'`);
|
|
51
|
-
await cdp.pressKey(pipSid!, "Enter", "Enter", 13, "\r");
|
|
52
|
-
await cdp.typeText(pipSid!, "spi");
|
|
53
|
-
await cdp.pressKey(pipSid!, " ", "Space", 32, undefined, 2); // Ctrl+Space
|
|
54
|
-
await sleep(1200);
|
|
55
|
-
R.suggestWidget = await ev(`(() => { const w = ${W}; const sw = w.querySelector('.suggest-widget'); return { inWrapper: !!sw, visible: sw ? sw.classList.contains('visible') : null, inMainDoc: !!document.querySelector('.suggest-widget'), items: sw ? sw.querySelectorAll('.monaco-list-row').length : 0 }; })()`);
|
|
56
|
-
await h.pipShot(pipSid, "spike-02e-editor-in-pip-suggest.png");
|
|
57
|
-
await cdp.pressKey(pipSid!, "Escape", "Escape", 27);
|
|
58
|
-
|
|
59
|
-
// Resize via resizeTo with the pip 'resize' → editor.layout() glue
|
|
60
|
-
R.resizeGlue = await (async () => {
|
|
61
|
-
const pt = await cdp.eval<any>(pipSid!, `(() => { const b = document.createElement('button'); b.id = 'rz'; b.textContent = 'rz'; b.style.cssText = 'position:fixed;right:4px;bottom:4px;z-index:99999'; b.onclick = () => window.resizeTo(700, 450); document.body.append(b); const r = b.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; })()`);
|
|
62
|
-
await cdp.click(pipSid!, pt.x, pt.y);
|
|
63
|
-
await sleep(600);
|
|
64
|
-
const r = await ev(`({ pipResizes: window.__spike.pipResizes, layout: [${E}.getLayoutInfo().width, ${E}.getLayoutInfo().height], pip: [window.__spike.pip.innerWidth, window.__spike.pip.innerHeight] })`);
|
|
65
|
-
await cdp.eval(pipSid!, `document.getElementById('rz').remove(); 'x'`);
|
|
66
|
-
return r;
|
|
67
|
-
})();
|
|
68
|
-
await h.pipShot(pipSid, "spike-02d-editor-in-pip-resized.png");
|
|
69
|
-
|
|
70
|
-
// Return: explicit layout + undo of pip-typed text
|
|
71
|
-
R.back = await ev(`(async () => { const S = window.__spike; const w = ${W}; const ed = ${E}; const r = S.moveBack(w); await new Promise(res => setTimeout(res, 800));
|
|
72
|
-
const stale = [ed.getLayoutInfo().width, ed.getLayoutInfo().height]; ed.layout(); ed.updateOptions({ editContext: true });
|
|
73
|
-
return { ...r, layoutStaleAfterReturn: stale, layoutAfterExplicit: [ed.getLayoutInfo().width, ed.getLayoutInfo().height], slot: [w.offsetWidth, w.offsetHeight] }; })()`);
|
|
74
|
-
await ev(`window.__spike.pip.close(); 'c'`);
|
|
75
|
-
await sleep(400);
|
|
76
|
-
await ev(`${E}.focus(); 'f'`);
|
|
77
|
-
const undoSteps: string[] = [];
|
|
78
|
-
for (let i = 0; i < 6; i++) { await cdp.pressKey(sid, "z", "KeyZ", 90, undefined, 2); await sleep(150); undoSteps.push(await ev(`${E}.getModel().getLineContent(2) + ' || L8=' + (${E}.getModel().getLineCount() >= 9 ? ${E}.getModel().getLineContent(9) : '')`)); }
|
|
79
|
-
R.undoAfterReturn = { steps: undoSteps, line2Restored: await ev(`${E}.getModel().getLineContent(2) === 'export const spikeLine1 = "one";'`) };
|
|
80
|
-
await cdp.screenshot(sid, "C:/Users/PC/ppm/plans/reports/screenshots/spike-04-editor-after-return.png");
|
|
81
|
-
await saveResults("pip-results-editor-glue.json", R);
|
|
82
|
-
cdp.close();
|