@atlassian/chippy 0.0.1-beta.1 → 0.0.1-beta.2

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 (54) hide show
  1. package/README.md +142 -54
  2. package/bin/chippy.mjs +53 -95
  3. package/bin/pack.mjs +20 -0
  4. package/bin/skill-dir.mjs +15 -0
  5. package/lib/avalanche.js +54 -23
  6. package/lib/avalanche.js.map +2 -2
  7. package/lib/bootstrap.js +20 -1
  8. package/lib/bootstrap.js.map +3 -3
  9. package/lib/extension/avalanche.es.js +173 -34
  10. package/lib/extension/avalanche.es.js.map +1 -1
  11. package/lib/extension/chippy-page-bridge.js +164 -44
  12. package/lib/mcp-skill/README.md +2 -4
  13. package/lib/mcp-skill/SKILL.md +21 -16
  14. package/lib/mcp-skill/extension/armed-reload-startup.js +83 -0
  15. package/lib/mcp-skill/extension/avalanche.es.js +173 -34
  16. package/lib/mcp-skill/extension/avalanche.es.js.map +1 -1
  17. package/lib/mcp-skill/extension/avalanche.iife.js +173 -34
  18. package/lib/mcp-skill/extension/avalanche.iife.js.map +1 -1
  19. package/lib/mcp-skill/extension/background.js +2 -0
  20. package/lib/mcp-skill/extension/chippy-page-bridge.js +164 -44
  21. package/lib/mcp-skill/extension/content-script.js +23 -0
  22. package/lib/mcp-skill/extension/devtools-hook-shim.js +18 -1
  23. package/lib/mcp-skill/extension/early-bootstrap.js +3 -1
  24. package/lib/mcp-skill/extension/manifest.json +1 -1
  25. package/lib/mcp-skill/extension/panel-settings.js +2 -20
  26. package/lib/mcp-skill/extension/startup-handoff.js +30 -0
  27. package/lib/mcp-skill/references/README.md +2 -2
  28. package/lib/mcp-skill/references/avalanche-detector.md +3 -3
  29. package/lib/mcp-skill/references/browser-runtime-api.md +4 -4
  30. package/lib/mcp-skill/references/command-output-formats.md +12 -2
  31. package/lib/mcp-skill/references/command-surface.md +6 -6
  32. package/lib/mcp-skill/references/mode-a-injection.md +43 -9
  33. package/lib/mcp-skill/references/playwright-cli-setup.md +5 -5
  34. package/lib/mcp-skill/references/playwright-probes.md +1 -1
  35. package/lib/mcp-skill/references/recipes.txt +1 -1
  36. package/lib/mcp-skill/references/stability-render.md +4 -4
  37. package/lib/mcp-skill/references/test-mode-playbook.md +2 -1
  38. package/lib/mcp-skill/references/troubleshooting.md +6 -1
  39. package/lib/mcp-skill/scripts/chippy-helper-server.js +116 -58
  40. package/lib/mcp-skill/scripts/chippy.sh +41 -7
  41. package/lib/mcp-skill/scripts/helper-access.js +20 -6
  42. package/lib/mcp-skill/scripts/helper-proxy.js +87 -0
  43. package/lib/mcp-skill/scripts/page-socket-trust.js +81 -0
  44. package/lib/plugin.js.map +2 -2
  45. package/lib/storybook/connection-fallback.jsx +1 -1
  46. package/lib/storybook/manager-owner.js +42 -0
  47. package/lib/storybook/manager.jsx +22 -0
  48. package/lib/storybook/preview.js +53 -18
  49. package/lib/storybook/setup.js +15 -4
  50. package/lib/types/chippy-bridge/fiber-source.d.ts +14 -3
  51. package/lib/types/chippy-bridge/react-renderer.d.ts +30 -5
  52. package/lib/types/chippy-bridge/recorded-source.d.ts +44 -0
  53. package/lib/types/debug-render/core.d.ts +6 -0
  54. package/package.json +3 -1
@@ -161,6 +161,72 @@ this.__AVALANCHE__ = (function() {
161
161
  return null;
162
162
  }
163
163
  }
164
+ function recordedLiteralPosition(code, source) {
165
+ const column = source.columnNumber === null ? "" : `,\\s*columnNumber:\\s*${source.columnNumber}`;
166
+ const literal = new RegExp(`lineNumber:\\s*${source.lineNumber}${column}(?!\\d)`, "g");
167
+ const first = literal.exec(code);
168
+ if (first === null || literal.exec(code) !== null) return null;
169
+ const before = code.slice(0, first.index);
170
+ const lineStart = before.lastIndexOf("\n");
171
+ return { line: before.split("\n").length, column: first.index - lineStart };
172
+ }
173
+ function decodedPath(pathname) {
174
+ try {
175
+ return decodeURIComponent(pathname);
176
+ } catch {
177
+ return pathname;
178
+ }
179
+ }
180
+ function slashPath(fileName) {
181
+ return fileName.replace(/\\/g, "/");
182
+ }
183
+ function servedModuleUrls(fileName, page) {
184
+ const file = slashPath(fileName);
185
+ const matches = /* @__PURE__ */ new Map();
186
+ for (const raw of page.resourceUrls) {
187
+ let url;
188
+ try {
189
+ url = new URL(raw, page.origin);
190
+ } catch {
191
+ continue;
192
+ }
193
+ if (url.origin !== page.origin) continue;
194
+ const path = decodedPath(url.pathname).replace(/^\/@fs(?=\/)/, "");
195
+ const tail = /^\/[A-Za-z]:\//.test(path) && /^[A-Za-z]:\//.test(file) ? path.slice(1) : path;
196
+ if (tail.length < 2 || !file.endsWith(tail)) continue;
197
+ matches.set(tail, { url: url.href, length: tail.length });
198
+ }
199
+ const ranked = [...matches.values()].sort((a, b) => b.length - a.length).map((entry) => entry.url);
200
+ if (page.vite && (file.startsWith("/") || /^[A-Za-z]:\//.test(file))) {
201
+ const fsUrl = new URL(`/@fs${file.startsWith("/") ? "" : "/"}${file}`, page.origin).href;
202
+ if (!ranked.includes(fsUrl)) ranked.push(fsUrl);
203
+ }
204
+ return ranked;
205
+ }
206
+ function readPageModules() {
207
+ var _a2, _b2, _c2, _d2;
208
+ const scope = globalThis;
209
+ const origin = (_a2 = scope.location) == null ? void 0 : _a2.origin;
210
+ if (!origin || origin === "null") return null;
211
+ const resourceUrls = [];
212
+ for (const script of Array.from(((_b2 = scope.document) == null ? void 0 : _b2.scripts) ?? [])) {
213
+ if (script.src) resourceUrls.push(script.src);
214
+ }
215
+ try {
216
+ for (const entry of ((_d2 = (_c2 = scope.performance) == null ? void 0 : _c2.getEntriesByType) == null ? void 0 : _d2.call(_c2, "resource")) ?? []) resourceUrls.push(entry.name);
217
+ } catch {
218
+ }
219
+ const vite = resourceUrls.some((url) => url.includes("/@vite/client"));
220
+ return { origin, resourceUrls, vite };
221
+ }
222
+ function pageModuleUrls(fileName) {
223
+ const page = readPageModules();
224
+ return page ? servedModuleUrls(fileName, page) : [];
225
+ }
226
+ function baseName(path) {
227
+ const clean = slashPath(path).replace(/[?#].*$/, "");
228
+ return clean.slice(clean.lastIndexOf("/") + 1);
229
+ }
164
230
  const V8_FRAME = /^\s*at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?$/;
165
231
  const AT_FRAME = /^\s*(?:(.*?)@)(.+?):(\d+):(\d+)$/;
166
232
  const MAX_CALL_SITE_FRAMES = 4;
@@ -223,9 +289,10 @@ this.__AVALANCHE__ = (function() {
223
289
  const parsed = parseUrl(resolved);
224
290
  return parsed ? parsed.pathname.replace(/^\/+/, "") : resolved;
225
291
  }
226
- function createCallSiteResolver(fetchModule) {
292
+ function createCallSiteResolver(fetchModule, moduleUrlsFor = () => []) {
227
293
  const maps = /* @__PURE__ */ new Map();
228
294
  const sites = /* @__PURE__ */ new Map();
295
+ const recordedSites = /* @__PURE__ */ new Map();
229
296
  const stats = { modules: 0, sites: 0, located: 0 };
230
297
  async function mapsFor(url) {
231
298
  const cached = maps.get(url);
@@ -238,10 +305,10 @@ this.__AVALANCHE__ = (function() {
238
305
  const annotation = sourceMappingUrlOf(code);
239
306
  if (annotation === null) return null;
240
307
  const inline = inlineSourceMapOf(annotation);
241
- if (inline !== null) return { maps: parseSourceMap(inline), sourceBaseUrl: url };
308
+ if (inline !== null) return { code, maps: parseSourceMap(inline), sourceBaseUrl: url };
242
309
  const mapUrl = ((_a2 = parseUrl(annotation, url)) == null ? void 0 : _a2.href) ?? null;
243
310
  const text = mapUrl === null ? null : await fetchModule(mapUrl);
244
- return text === null || mapUrl === null ? null : { maps: parseSourceMap(text), sourceBaseUrl: mapUrl };
311
+ return text === null || mapUrl === null ? null : { code, maps: parseSourceMap(text), sourceBaseUrl: mapUrl };
245
312
  })();
246
313
  maps.set(url, pending);
247
314
  return pending;
@@ -276,7 +343,28 @@ this.__AVALANCHE__ = (function() {
276
343
  }
277
344
  return null;
278
345
  }
279
- return { locate, stats };
346
+ async function correctRecorded(source) {
347
+ for (const url of moduleUrlsFor(source.fileName)) {
348
+ const parsed = await mapsFor(url);
349
+ if (!parsed || parsed.maps.length === 0) continue;
350
+ const served = recordedLiteralPosition(parsed.code, source);
351
+ if (served === null) continue;
352
+ const original = originalPositionFor(parsed.maps, served.line, served.column);
353
+ if (!original || baseName(original.source) !== baseName(source.fileName)) continue;
354
+ return { fileName: source.fileName, lineNumber: original.line, columnNumber: original.column };
355
+ }
356
+ return source;
357
+ }
358
+ function locateRecorded(source) {
359
+ const key = `${source.fileName}:${source.lineNumber}:${source.columnNumber}`;
360
+ let answer = recordedSites.get(key);
361
+ if (!answer) {
362
+ answer = correctRecorded(source).catch(() => source);
363
+ recordedSites.set(key, answer);
364
+ }
365
+ return answer;
366
+ }
367
+ return { locate, locateRecorded, stats };
280
368
  }
281
369
  function debugSourceOf(value) {
282
370
  if (!value || typeof value !== "object") return null;
@@ -314,8 +402,6 @@ this.__AVALANCHE__ = (function() {
314
402
  }
315
403
  function getFiberSource$2(fiber) {
316
404
  if (!fiber) return null;
317
- const recorded = recordedSource(fiber);
318
- if (recorded) return recorded;
319
405
  const cached = resolvedFiberSources.get(fiber);
320
406
  if (cached !== void 0) return cached;
321
407
  return getFiberSourceCandidate(fiber);
@@ -338,15 +424,22 @@ this.__AVALANCHE__ = (function() {
338
424
  }
339
425
  }
340
426
  function pageResolver() {
341
- if (!defaultResolver) defaultResolver = createCallSiteResolver(fetchModuleFromPage);
427
+ if (!defaultResolver) defaultResolver = createCallSiteResolver(fetchModuleFromPage, pageModuleUrls);
342
428
  return defaultResolver;
343
429
  }
344
430
  function resolveFiberSource$1(fiber, resolver = pageResolver()) {
345
431
  if (!fiber) return Promise.resolve(null);
346
- const recorded = recordedSource(fiber);
347
- if (recorded) return Promise.resolve(recorded);
348
432
  const cached = pendingFiberSources.get(fiber);
349
433
  if (cached) return cached;
434
+ const recorded = recordedSource(fiber);
435
+ if (recorded) {
436
+ const pending2 = resolver.locateRecorded(recorded).then((located) => {
437
+ resolvedFiberSources.set(fiber, located);
438
+ return located;
439
+ });
440
+ pendingFiberSources.set(fiber, pending2);
441
+ return pending2;
442
+ }
350
443
  const frames = getFiberStackFrames(fiber);
351
444
  const fallback = writerLocationOf(frames, () => null);
352
445
  const pending = resolver.locate(frames).catch(() => null).then((source) => {
@@ -910,13 +1003,42 @@ this.__AVALANCHE__ = (function() {
910
1003
  }
911
1004
  return out;
912
1005
  }
913
- function getDispatcherRef(scope = globalThis) {
1006
+ function dispatcherSlotOf(injected) {
1007
+ if (!injected || typeof injected !== "object") return null;
1008
+ const owner = injected;
1009
+ if (typeof owner.H !== "undefined") return { owner, key: "H" };
1010
+ if ("current" in owner) return { owner, key: "current" };
1011
+ return null;
1012
+ }
1013
+ function getDispatcherSlot(scope = globalThis) {
914
1014
  for (const renderer of getReactRenderers(scope)) {
915
- const ref = renderer.currentDispatcherRef;
916
- if (ref && typeof ref === "object") return ref;
1015
+ const slot = dispatcherSlotOf(renderer.currentDispatcherRef);
1016
+ if (slot) return slot;
917
1017
  }
918
1018
  return null;
919
1019
  }
1020
+ const modernRefs = /* @__PURE__ */ new WeakMap();
1021
+ function dispatcherRefOf(slot) {
1022
+ if (slot.key === "current") return slot.owner;
1023
+ let ref = modernRefs.get(slot.owner);
1024
+ if (!ref) {
1025
+ const { owner } = slot;
1026
+ ref = {
1027
+ get current() {
1028
+ return owner.H;
1029
+ },
1030
+ set current(value) {
1031
+ owner.H = value;
1032
+ }
1033
+ };
1034
+ modernRefs.set(owner, ref);
1035
+ }
1036
+ return ref;
1037
+ }
1038
+ function getDispatcherRef(scope = globalThis) {
1039
+ const slot = getDispatcherSlot(scope);
1040
+ return slot ? dispatcherRefOf(slot) : null;
1041
+ }
920
1042
  function getScheduleUpdate(scope = globalThis) {
921
1043
  for (const renderer of getReactRenderers(scope)) {
922
1044
  if (typeof renderer.scheduleUpdate === "function") return renderer.scheduleUpdate;
@@ -975,11 +1097,14 @@ this.__AVALANCHE__ = (function() {
975
1097
  function isReactInternalFrameName(name) {
976
1098
  return name === "atlDispatcherHook" || name === "record" || name.startsWith("Object.") || name === "renderWithHooks" || name === "updateFunctionComponent" || name === "mountIndeterminateComponent" || name === "beginWork" || /^beginWork\$/.test(name) || name === "performUnitOfWork" || name === "workLoopSync" || name === "renderRootSync" || name === "performConcurrentWorkOnRoot" || name === "workLoop" || name === "flushWork";
977
1099
  }
1100
+ function isHookFrameName(name) {
1101
+ return /^use[A-Z0-9_]/.test(name.slice(name.lastIndexOf(".") + 1));
1102
+ }
978
1103
  function deriveComponentName(frames) {
979
1104
  for (const { name } of frames) {
980
1105
  if (!name) continue;
981
1106
  if (isReactInternalFrameName(name)) continue;
982
- if (/^use[A-Z0-9_]/.test(name)) continue;
1107
+ if (isHookFrameName(name)) continue;
983
1108
  return name;
984
1109
  }
985
1110
  return "Unknown";
@@ -990,7 +1115,7 @@ this.__AVALANCHE__ = (function() {
990
1115
  const patchedDispatchers = /* @__PURE__ */ new WeakMap();
991
1116
  let installed2 = false;
992
1117
  let originalDescriptor = void 0;
993
- let dispatcherRef = null;
1118
+ let dispatcherSlot = null;
994
1119
  let lastSeenDispatcher = null;
995
1120
  function record(primitive, args) {
996
1121
  const stack = new Error().stack || "";
@@ -1042,15 +1167,16 @@ this.__AVALANCHE__ = (function() {
1042
1167
  }
1043
1168
  function install() {
1044
1169
  if (installed2) return { ok: true };
1045
- const ref = getDispatcherRef();
1046
- if (!ref) return { ok: false, reason: "ReactCurrentDispatcher not found" };
1047
- dispatcherRef = ref;
1048
- patchDispatcher(ref.current);
1049
- lastSeenDispatcher = ref.current;
1050
- originalDescriptor = Object.getOwnPropertyDescriptor(ref, "current") || null;
1051
- let stored = ref.current;
1170
+ const slot = getDispatcherSlot();
1171
+ if (!slot) return { ok: false, reason: "ReactCurrentDispatcher not found" };
1172
+ dispatcherSlot = slot;
1173
+ const { owner, key } = slot;
1174
+ patchDispatcher(owner[key]);
1175
+ lastSeenDispatcher = owner[key];
1176
+ originalDescriptor = Object.getOwnPropertyDescriptor(owner, key) || null;
1177
+ let stored = owner[key];
1052
1178
  try {
1053
- Object.defineProperty(ref, "current", {
1179
+ Object.defineProperty(owner, key, {
1054
1180
  configurable: true,
1055
1181
  get() {
1056
1182
  return stored;
@@ -1064,7 +1190,7 @@ this.__AVALANCHE__ = (function() {
1064
1190
  }
1065
1191
  });
1066
1192
  } catch (e) {
1067
- dispatcherRef = null;
1193
+ dispatcherSlot = null;
1068
1194
  return { ok: false, reason: "cannot define property on ReactCurrentDispatcher" };
1069
1195
  }
1070
1196
  installed2 = true;
@@ -1072,12 +1198,13 @@ this.__AVALANCHE__ = (function() {
1072
1198
  }
1073
1199
  function uninstall() {
1074
1200
  if (!installed2) return;
1075
- if (dispatcherRef) {
1201
+ if (dispatcherSlot) {
1202
+ const { owner, key } = dispatcherSlot;
1076
1203
  try {
1077
1204
  if (originalDescriptor) {
1078
- Object.defineProperty(dispatcherRef, "current", originalDescriptor);
1205
+ Object.defineProperty(owner, key, originalDescriptor);
1079
1206
  } else {
1080
- Object.defineProperty(dispatcherRef, "current", {
1207
+ Object.defineProperty(owner, key, {
1081
1208
  configurable: true,
1082
1209
  writable: true,
1083
1210
  enumerable: true,
@@ -1089,7 +1216,7 @@ this.__AVALANCHE__ = (function() {
1089
1216
  }
1090
1217
  unpatchDispatcher(lastSeenDispatcher);
1091
1218
  installed2 = false;
1092
- dispatcherRef = null;
1219
+ dispatcherSlot = null;
1093
1220
  originalDescriptor = void 0;
1094
1221
  lastSeenDispatcher = null;
1095
1222
  }
@@ -1106,8 +1233,7 @@ this.__AVALANCHE__ = (function() {
1106
1233
  const g = globalThis;
1107
1234
  const hasDevtoolsHook = !!g.__REACT_DEVTOOLS_GLOBAL_HOOK__;
1108
1235
  const rendererCount = getReactRenderers().length;
1109
- const ref = dispatcherRef || getDispatcherRef();
1110
- const hasDispatcherRef = !!ref;
1236
+ const hasDispatcherRef = !!(dispatcherSlot || getDispatcherSlot());
1111
1237
  let totalCapturedEvents = 0;
1112
1238
  for (const list of eventsByComponent.values()) totalCapturedEvents += list.length;
1113
1239
  let reason;
@@ -1146,7 +1272,7 @@ this.__AVALANCHE__ = (function() {
1146
1272
  uninstall,
1147
1273
  reset,
1148
1274
  isInstalled: () => installed2,
1149
- dispatcherRef: () => dispatcherRef || getDispatcherRef(),
1275
+ dispatcherRef: () => dispatcherSlot ? dispatcherRefOf(dispatcherSlot) : getDispatcherRef(),
1150
1276
  rawEvents,
1151
1277
  allComponents,
1152
1278
  status,
@@ -2955,7 +3081,7 @@ this.__AVALANCHE__ = (function() {
2955
3081
  const out = [];
2956
3082
  for (let i = relevant.length - 1; i >= 0; i--) {
2957
3083
  const { name, loc } = relevant[i];
2958
- if (/^use[A-Z0-9_]/.test(name) && !PRIMITIVE_HOOK_NAMES.has(name)) {
3084
+ if (isHookFrameName(name) && !PRIMITIVE_HOOK_NAMES.has(name.slice(name.lastIndexOf(".") + 1))) {
2959
3085
  const parent = i + 1 < parentLookup.length ? parentLookup[i + 1] : null;
2960
3086
  out.push({ name, loc: parent ? parent.loc : loc });
2961
3087
  }
@@ -4373,6 +4499,17 @@ this.__AVALANCHE__ = (function() {
4373
4499
  }, { limit: 2e5 });
4374
4500
  return { count: matches.length, items: matches };
4375
4501
  }
4502
+ async function resolveFindFiberSources(items, getFiber2, resolve) {
4503
+ await Promise.all(items.map(async (item) => {
4504
+ const fiber = item.fiberId == null ? null : getFiber2(String(item.fiberId));
4505
+ if (!fiber) return;
4506
+ try {
4507
+ const source = await resolve(fiber);
4508
+ if (source) item.source = source;
4509
+ } catch {
4510
+ }
4511
+ }));
4512
+ }
4376
4513
  function safeJson(value, depth = 6, seen = /* @__PURE__ */ new WeakSet()) {
4377
4514
  if (value == null) return value;
4378
4515
  const t = typeof value;
@@ -5186,6 +5323,7 @@ this.__AVALANCHE__ = (function() {
5186
5323
  };
5187
5324
  }
5188
5325
  const runtime = globalThis;
5326
+ const publishedApi = runtime.__AVALANCHE__;
5189
5327
  registerBuiltinPlugins();
5190
5328
  {
5191
5329
  const fromConfig = (_a = runtime.__CHIPPY_STARTUP_CONFIG) == null ? void 0 : _a.plugins;
@@ -5360,6 +5498,7 @@ this.__AVALANCHE__ = (function() {
5360
5498
  evalFiberProps,
5361
5499
  evalFiberPropValue,
5362
5500
  evalFindFibers,
5501
+ resolveFindFiberSources,
5363
5502
  safeJson,
5364
5503
  resolveOwnerFiber,
5365
5504
  findFiberByName,
@@ -5379,8 +5518,7 @@ this.__AVALANCHE__ = (function() {
5379
5518
  if (__auto) {
5380
5519
  try {
5381
5520
  const requested2 = ((_c = startupConfig == null ? void 0 : startupConfig.avalanche) == null ? void 0 : _c.options) || {};
5382
- const existingApi = runtime.__AVALANCHE__;
5383
- const targetApi = existingApi && typeof existingApi.install === "function" ? existingApi : api;
5521
+ const targetApi = publishedApi && typeof publishedApi.install === "function" ? publishedApi : api;
5384
5522
  const alreadyInstalled = !!(targetApi.status && targetApi.status().installed);
5385
5523
  if (!alreadyInstalled) {
5386
5524
  targetApi.install({
@@ -5392,6 +5530,7 @@ this.__AVALANCHE__ = (function() {
5392
5530
  } catch (e) {
5393
5531
  }
5394
5532
  }
5395
- return api;
5533
+ const iife = publishedApi ?? api;
5534
+ return iife;
5396
5535
  })();
5397
5536
  //# sourceMappingURL=avalanche.iife.js.map