@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.
Files changed (44) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +81 -23
  3. package/assets/skills/ppm/SKILL.md +1 -1
  4. package/assets/skills/ppm/references/http-api.md +1 -1
  5. package/package.json +1 -1
  6. package/.spike/cdp-client.ts +0 -116
  7. package/.spike/cleanup-ppm-workspace.mjs +0 -44
  8. package/.spike/group-protected-probe.ts +0 -21
  9. package/.spike/pip-eval.ts +0 -17
  10. package/.spike/pip-page-helpers.js +0 -119
  11. package/.spike/pip-results-editor-glue.json +0 -105
  12. package/.spike/pip-results-editor.json +0 -158
  13. package/.spike/pip-results-input-isolation.json +0 -28
  14. package/.spike/pip-results-key-probe.json +0 -58
  15. package/.spike/pip-results-listener-survival.json +0 -98
  16. package/.spike/pip-results-listeners.json +0 -36
  17. package/.spike/pip-results-pagehide.json +0 -92
  18. package/.spike/pip-results-resize.json +0 -104
  19. package/.spike/pip-results-terminal-debug.json +0 -99
  20. package/.spike/pip-results-terminal-v2.json +0 -191
  21. package/.spike/pip-results-terminal.json +0 -220
  22. package/.spike/pip-results-xterm-trace.json +0 -73
  23. package/.spike/pip-spike-common.ts +0 -83
  24. package/.spike/pip-spike-editor-glue.ts +0 -82
  25. package/.spike/pip-spike-editor.ts +0 -129
  26. package/.spike/pip-spike-input-isolation.ts +0 -38
  27. package/.spike/pip-spike-key-probe.ts +0 -34
  28. package/.spike/pip-spike-listener-survival.ts +0 -54
  29. package/.spike/pip-spike-listeners.ts +0 -19
  30. package/.spike/pip-spike-pagehide.ts +0 -59
  31. package/.spike/pip-spike-resize.ts +0 -42
  32. package/.spike/pip-spike-setup.ts +0 -63
  33. package/.spike/pip-spike-terminal-debug.ts +0 -81
  34. package/.spike/pip-spike-terminal-v2.ts +0 -139
  35. package/.spike/pip-spike-terminal.ts +0 -169
  36. package/.spike/pip-spike-xterm-trace.ts +0 -36
  37. package/.spike/probe-drag-memo-error.mjs +0 -67
  38. package/.spike/read-dev-db.ts +0 -15
  39. package/.spike/s.err +0 -63
  40. package/.spike/scratch-editor-target.ts +0 -7
  41. package/.spike/smoke-unified-chrome-pip.mjs +0 -353
  42. package/.spike/tunnel.err +0 -63
  43. package/.spike/vite-restart.err +0 -663
  44. 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();