@atlassian/chippy 0.0.0-stage → 0.0.1-beta.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.
- package/LICENSE +201 -0
- package/README.md +188 -2
- package/bin/chippy.mjs +134 -0
- package/bin/pack.mjs +184 -0
- package/lib/avalanche.js +2570 -0
- package/lib/avalanche.js.map +7 -0
- package/lib/bootstrap.d.ts +1 -0
- package/lib/bootstrap.js +51 -0
- package/lib/bootstrap.js.map +7 -0
- package/lib/browser.js +15 -0
- package/lib/browser.js.map +7 -0
- package/lib/extension/avalanche.es.js +5396 -0
- package/lib/extension/avalanche.es.js.map +1 -0
- package/lib/extension/chippy-page-bridge.js +1833 -0
- package/lib/extension/inspect-react.js +216 -0
- package/lib/extension/layout-lab.js +1453 -0
- package/lib/extension/panel-dom.js +90 -0
- package/lib/extension/resolve-probes.js +342 -0
- package/lib/mcp-skill/LICENSE +201 -0
- package/lib/mcp-skill/README.md +150 -0
- package/lib/mcp-skill/SKILL.md +330 -0
- package/lib/mcp-skill/browser-scripts/playwright-probes.js +368 -0
- package/lib/mcp-skill/browser-scripts/playwright-session.js +114 -0
- package/lib/mcp-skill/extension/avalanche.es.js +5396 -0
- package/lib/mcp-skill/extension/avalanche.es.js.map +1 -0
- package/lib/mcp-skill/extension/avalanche.iife.js +5397 -0
- package/lib/mcp-skill/extension/avalanche.iife.js.map +1 -0
- package/lib/mcp-skill/extension/background.js +323 -0
- package/lib/mcp-skill/extension/chippy-page-bridge.js +1833 -0
- package/lib/mcp-skill/extension/content-script.js +167 -0
- package/lib/mcp-skill/extension/devtools-hook-shim.js +68 -0
- package/lib/mcp-skill/extension/early-bootstrap.js +47 -0
- package/lib/mcp-skill/extension/icon-128.png +0 -0
- package/lib/mcp-skill/extension/icon-16.png +0 -0
- package/lib/mcp-skill/extension/icon-32.png +0 -0
- package/lib/mcp-skill/extension/icon-48.png +0 -0
- package/lib/mcp-skill/extension/inspect-react.js +216 -0
- package/lib/mcp-skill/extension/layout-lab.js +1453 -0
- package/lib/mcp-skill/extension/logo.svg +14 -0
- package/lib/mcp-skill/extension/manifest.json +69 -0
- package/lib/mcp-skill/extension/panel-dom.js +90 -0
- package/lib/mcp-skill/extension/panel-settings.js +191 -0
- package/lib/mcp-skill/extension/popup.html +41 -0
- package/lib/mcp-skill/extension/popup.js +80 -0
- package/lib/mcp-skill/extension/probe-descriptor.js +241 -0
- package/lib/mcp-skill/extension/resolve-probes.js +342 -0
- package/lib/mcp-skill/package.json +1 -0
- package/lib/mcp-skill/references/README.md +56 -0
- package/lib/mcp-skill/references/active-stimulus.md +85 -0
- package/lib/mcp-skill/references/avalanche-detector.md +731 -0
- package/lib/mcp-skill/references/bdd-router.md +310 -0
- package/lib/mcp-skill/references/browser-runtime-api.md +193 -0
- package/lib/mcp-skill/references/command-output-formats.md +1075 -0
- package/lib/mcp-skill/references/command-surface.md +183 -0
- package/lib/mcp-skill/references/cynefin.md +99 -0
- package/lib/mcp-skill/references/debug-hook.md +161 -0
- package/lib/mcp-skill/references/fixing-performance.md +490 -0
- package/lib/mcp-skill/references/hook-metrics.md +199 -0
- package/lib/mcp-skill/references/hooks-inspection.md +61 -0
- package/lib/mcp-skill/references/jira-taxonomy.md +81 -0
- package/lib/mcp-skill/references/mcp.md +122 -0
- package/lib/mcp-skill/references/mode-a-injection.md +68 -0
- package/lib/mcp-skill/references/operating-model.md +128 -0
- package/lib/mcp-skill/references/playwright-cli-setup.md +105 -0
- package/lib/mcp-skill/references/playwright-probes.md +205 -0
- package/lib/mcp-skill/references/procedures.md +545 -0
- package/lib/mcp-skill/references/recipes.txt +114 -0
- package/lib/mcp-skill/references/stability-render.md +428 -0
- package/lib/mcp-skill/references/test-mode-playbook.md +193 -0
- package/lib/mcp-skill/references/troubleshooting.md +54 -0
- package/lib/mcp-skill/scripts/avalanche-analyze.cjs +495 -0
- package/lib/mcp-skill/scripts/build-avalanche-command.js +34 -0
- package/lib/mcp-skill/scripts/build-fiber-state-command.js +19 -0
- package/lib/mcp-skill/scripts/chippy-helper-server.js +1710 -0
- package/lib/mcp-skill/scripts/chippy-mcp.cjs +273 -0
- package/lib/mcp-skill/scripts/chippy.sh +1218 -0
- package/lib/mcp-skill/scripts/format-probe-result.js +34 -0
- package/lib/mcp-skill/scripts/helper-access.js +144 -0
- package/lib/mcp-skill/scripts/probe-annotation-channel.js +116 -0
- package/lib/mcp-skill/scripts/search-recipes.js +248 -0
- package/lib/mcp-skill/snippets/README.md +89 -0
- package/lib/mcp-skill/snippets/count-context-consumers.js +40 -0
- package/lib/mcp-skill/snippets/find-context-providers.js +38 -0
- package/lib/mcp-skill/snippets/find-legacy-context.js +47 -0
- package/lib/mcp-skill/snippets/find-prop.js +83 -0
- package/lib/mcp-skill/snippets/hook-metrics-sample.js +69 -0
- package/lib/mcp-skill/snippets/hook-metrics.js +60 -0
- package/lib/mcp-skill/snippets/hook-tracker.js +198 -0
- package/lib/mcp-skill/snippets/stability-nudge.js +101 -0
- package/lib/package.json +1 -0
- package/lib/plugin.js +119 -0
- package/lib/plugin.js.map +7 -0
- package/lib/storybook/avalanche-panel-model.js +79 -0
- package/lib/storybook/brand.jsx +6 -0
- package/lib/storybook/connection-fallback.jsx +47 -0
- package/lib/storybook/constants.js +15 -0
- package/lib/storybook/context-card.jsx +171 -0
- package/lib/storybook/manager.jsx +403 -0
- package/lib/storybook/preset.js +7 -0
- package/lib/storybook/preview.js +263 -0
- package/lib/storybook/probe-annotation-editor.jsx +52 -0
- package/lib/storybook/probe-intent.js +23 -0
- package/lib/storybook/setup.js +93 -0
- package/lib/types/avalanche/commit-metrics-adapter.d.ts +76 -0
- package/lib/types/avalanche/commit-stats-indices.d.ts +41 -0
- package/lib/types/avalanche/commit-surface-ownership.d.ts +9 -0
- package/lib/types/avalanche/detector.d.ts +183 -0
- package/lib/types/avalanche/interaction-capture.d.ts +25 -0
- package/lib/types/avalanche/internals.d.ts +189 -0
- package/lib/types/avalanche/report-serializer.d.ts +283 -0
- package/lib/types/avalanche/reporter.d.ts +610 -0
- package/lib/types/chippy-bridge/fiber-source.d.ts +37 -0
- package/lib/types/chippy-bridge/react-renderer.d.ts +49 -0
- package/lib/types/chippy-bridge/source-map.d.ts +30 -0
- package/lib/types/debug-render/core.d.ts +72 -0
- package/lib/types/layout-lab/fiber-boundaries.d.ts +51 -0
- package/lib/types/layout-lab/fiber-walk.d.ts +131 -0
- package/lib/types/layout-lab/marker-context.d.ts +94 -0
- package/lib/types/package/avalanche.d.ts +6 -0
- package/lib/types/package/browser.d.ts +10 -0
- package/lib/types/package/plugin.d.ts +15 -0
- package/lib/types/plugins/atl/commit-metrics-adapter.d.ts +65 -0
- package/lib/types/plugins/atl/metrics-slot.d.ts +37 -0
- package/lib/types/plugins/index.d.ts +49 -0
- package/lib/types/plugins/jira/context-provider.d.ts +36 -0
- package/package.json +104 -4
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small, dependency-free Source Map v3 reader.
|
|
3
|
+
*
|
|
4
|
+
* Chippy only needs the generated-position lookup used by React 19's
|
|
5
|
+
* `_debugStack` source path, so it deliberately omits names and source contents.
|
|
6
|
+
*/
|
|
7
|
+
type Segment = {
|
|
8
|
+
generatedColumn: number;
|
|
9
|
+
sourceIndex: number | null;
|
|
10
|
+
originalLine: number | null;
|
|
11
|
+
originalColumn: number | null;
|
|
12
|
+
};
|
|
13
|
+
export type SourceMap = {
|
|
14
|
+
sources: readonly string[];
|
|
15
|
+
lines: readonly (readonly Segment[])[];
|
|
16
|
+
offset: {
|
|
17
|
+
line: number;
|
|
18
|
+
column: number;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export type OriginalPosition = {
|
|
22
|
+
source: string;
|
|
23
|
+
line: number;
|
|
24
|
+
column: number;
|
|
25
|
+
};
|
|
26
|
+
export declare function parseSourceMap(text: string): SourceMap[];
|
|
27
|
+
export declare function originalPositionFor(maps: readonly SourceMap[], line: number, column: number): OriginalPosition | null;
|
|
28
|
+
export declare function sourceMappingUrlOf(code: string): string | null;
|
|
29
|
+
export declare function inlineSourceMapOf(url: string): string | null;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug-render module.
|
|
3
|
+
*
|
|
4
|
+
* Single responsibility: capture per-render hook events for components, and
|
|
5
|
+
* expose them losslessly to higher layers (the detector projects them).
|
|
6
|
+
*
|
|
7
|
+
* Capture strategy: dispatcher interception via the DevTools global hook.
|
|
8
|
+
*
|
|
9
|
+
* React 18 routes every hook call through `ReactCurrentDispatcher.current`,
|
|
10
|
+
* which is swapped per render phase by react-dom. We do NOT patch
|
|
11
|
+
* `React.useX` (those are facades to the dispatcher) and we do NOT import
|
|
12
|
+
* React here — this module must not pin a React identity.
|
|
13
|
+
*
|
|
14
|
+
* We discover the *page's* `ReactCurrentDispatcher` ref via the React DevTools
|
|
15
|
+
* global hook contract:
|
|
16
|
+
*
|
|
17
|
+
* __REACT_DEVTOOLS_GLOBAL_HOOK__.renderers.get(id).currentDispatcherRef
|
|
18
|
+
*
|
|
19
|
+
* That ref is page-React-owned and lives where react-dom actually writes.
|
|
20
|
+
* Bootstrap requirement: a DevTools hook shim must already be installed when
|
|
21
|
+
* react-dom evaluates so it calls `hook.inject(internals)`. That bootstrap is
|
|
22
|
+
* Chippy's responsibility (handled by the extension content-script / helper
|
|
23
|
+
* inject path); this module only consumes the result.
|
|
24
|
+
*
|
|
25
|
+
* Capture is intentionally lossless: raw stack + parsed frames are stored.
|
|
26
|
+
* Projection (component name, custom-hook path, loc) is done downstream so
|
|
27
|
+
* the original evidence can be re-projected without re-capturing.
|
|
28
|
+
*/
|
|
29
|
+
export type StackFrame = {
|
|
30
|
+
name: string;
|
|
31
|
+
loc: string;
|
|
32
|
+
};
|
|
33
|
+
export type HookCallEvent = {
|
|
34
|
+
primitive: string;
|
|
35
|
+
stack: string;
|
|
36
|
+
frames: StackFrame[];
|
|
37
|
+
componentName: string;
|
|
38
|
+
args: unknown[];
|
|
39
|
+
};
|
|
40
|
+
export type CaptureEngineStatus = {
|
|
41
|
+
ok: boolean;
|
|
42
|
+
installed: boolean;
|
|
43
|
+
hasDevtoolsHook: boolean;
|
|
44
|
+
rendererCount: number;
|
|
45
|
+
hasDispatcherRef: boolean;
|
|
46
|
+
totalCapturedComponents: number;
|
|
47
|
+
totalCapturedEvents: number;
|
|
48
|
+
reason?: string;
|
|
49
|
+
hint?: string;
|
|
50
|
+
};
|
|
51
|
+
export type DebugRenderModule = {
|
|
52
|
+
install(): {
|
|
53
|
+
ok: boolean;
|
|
54
|
+
reason?: string;
|
|
55
|
+
};
|
|
56
|
+
uninstall(): void;
|
|
57
|
+
reset(): void;
|
|
58
|
+
isInstalled(): boolean;
|
|
59
|
+
dispatcherRef(): DispatcherRef | null;
|
|
60
|
+
rawEvents(componentName: string): HookCallEvent[];
|
|
61
|
+
allComponents(): string[];
|
|
62
|
+
status(): CaptureEngineStatus;
|
|
63
|
+
recordEventForTest?(event: HookCallEvent): void;
|
|
64
|
+
};
|
|
65
|
+
export declare function parseStackFrames(stack: string): StackFrame[];
|
|
66
|
+
type DispatcherRef = {
|
|
67
|
+
current: unknown;
|
|
68
|
+
};
|
|
69
|
+
export declare function createDebugRender(options?: {
|
|
70
|
+
maxEventsPerComponent?: number;
|
|
71
|
+
}): DebugRenderModule;
|
|
72
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fiber-native declarative boundaries.
|
|
3
|
+
*
|
|
4
|
+
* Error boundaries and Suspense are React primitives — they exist on every
|
|
5
|
+
* React page. This module detects them generically from the fiber tree,
|
|
6
|
+
* independent of any product. App-specific enrichment (ownership markers,
|
|
7
|
+
* error-boundary props) is layered on top by context providers registered
|
|
8
|
+
* with ./marker-context.
|
|
9
|
+
*
|
|
10
|
+
* "Distance" is the signal: how many fiber hops above the probed fiber the
|
|
11
|
+
* boundary sits. Together, the nearest error + suspense boundaries define the
|
|
12
|
+
* collateral scope around a probe.
|
|
13
|
+
*/
|
|
14
|
+
import { type Fiber } from './fiber-walk.js';
|
|
15
|
+
export type ErrorBoundaryInfo = {
|
|
16
|
+
componentName: string;
|
|
17
|
+
/** How the boundary was identified — lifecycle proof vs. name heuristic. */
|
|
18
|
+
detectedBy: 'lifecycle' | 'name';
|
|
19
|
+
};
|
|
20
|
+
export type SuspenseBoundaryInfo = {
|
|
21
|
+
componentName: string;
|
|
22
|
+
};
|
|
23
|
+
/** A boundary plus its fiber-hop distance from the probed fiber. */
|
|
24
|
+
export type BoundaryRef<T> = T & {
|
|
25
|
+
distance: number;
|
|
26
|
+
};
|
|
27
|
+
export type FiberBoundaries = {
|
|
28
|
+
error: BoundaryRef<ErrorBoundaryInfo> | null;
|
|
29
|
+
suspense: BoundaryRef<SuspenseBoundaryInfo> | null;
|
|
30
|
+
};
|
|
31
|
+
export declare const MAX_BOUNDARY_FIBERS = 400;
|
|
32
|
+
/**
|
|
33
|
+
* Generic error-boundary detection. An error boundary is a class component that
|
|
34
|
+
* implements getDerivedStateFromError and/or componentDidCatch. That lifecycle
|
|
35
|
+
* check is the React-native definition and works on any React app. As a
|
|
36
|
+
* fallback for minified/edge builds where the constructor is not introspectable,
|
|
37
|
+
* a display name ending in "ErrorBoundary" is accepted.
|
|
38
|
+
*/
|
|
39
|
+
export declare function describeErrorBoundary(fiber: Fiber): ErrorBoundaryInfo | null;
|
|
40
|
+
/**
|
|
41
|
+
* Generic Suspense detection. React marks a Suspense fiber with tag 13; we also
|
|
42
|
+
* accept a display name resolving to Suspense/SuspenseList for builds where the
|
|
43
|
+
* tag is unavailable.
|
|
44
|
+
*/
|
|
45
|
+
export declare function describeSuspenseBoundary(fiber: Fiber): SuspenseBoundaryInfo | null;
|
|
46
|
+
/**
|
|
47
|
+
* Walk an ordered ancestry list and return the nearest error + suspense
|
|
48
|
+
* boundaries with their distances. The list is expected to be ordered from the
|
|
49
|
+
* probed fiber outward, so the index is the fiber-hop distance.
|
|
50
|
+
*/
|
|
51
|
+
export declare function collectFiberBoundaries(fibers: Fiber[]): FiberBoundaries;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure fiber-walk helpers extracted from layout-lab.js.
|
|
3
|
+
* No DOM writes, no side effects — read-only introspection of React fiber trees.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Minimal duck-typed Fiber shape.
|
|
7
|
+
* Only fields used by these helpers are typed; rest may exist but are not read.
|
|
8
|
+
*/
|
|
9
|
+
export type Fiber = {
|
|
10
|
+
type?: unknown;
|
|
11
|
+
elementType?: unknown;
|
|
12
|
+
key?: string | null;
|
|
13
|
+
memoizedState?: unknown;
|
|
14
|
+
memoizedProps?: Record<string, unknown> | null;
|
|
15
|
+
stateNode?: Element | null;
|
|
16
|
+
return?: Fiber | null;
|
|
17
|
+
child?: Fiber | null;
|
|
18
|
+
sibling?: Fiber | null;
|
|
19
|
+
_debugOwner?: Fiber | null;
|
|
20
|
+
_debugSource?: SourceLocation | null;
|
|
21
|
+
_debugStack?: unknown;
|
|
22
|
+
};
|
|
23
|
+
export type SourceLocation = {
|
|
24
|
+
fileName?: string | null;
|
|
25
|
+
lineNumber?: number | null;
|
|
26
|
+
columnNumber?: number | null;
|
|
27
|
+
};
|
|
28
|
+
export type DescribedSource = {
|
|
29
|
+
fileName: string | null;
|
|
30
|
+
lineNumber: number | null;
|
|
31
|
+
columnNumber: number | null;
|
|
32
|
+
};
|
|
33
|
+
export type HookSummary = {
|
|
34
|
+
hookCount: number;
|
|
35
|
+
hookCountTruncated: boolean;
|
|
36
|
+
hookCountMax: number;
|
|
37
|
+
};
|
|
38
|
+
export type OwnerEntry = {
|
|
39
|
+
name: string | null;
|
|
40
|
+
key: string | null;
|
|
41
|
+
props: string[];
|
|
42
|
+
} & HookSummary & {
|
|
43
|
+
source: DescribedSource | null;
|
|
44
|
+
};
|
|
45
|
+
export type FiberTarget = {
|
|
46
|
+
domTag: string | null;
|
|
47
|
+
domText: string;
|
|
48
|
+
fiberType: string | null;
|
|
49
|
+
source: DescribedSource | null;
|
|
50
|
+
};
|
|
51
|
+
export type ComponentDescription = {
|
|
52
|
+
name: string | null;
|
|
53
|
+
key: string | null;
|
|
54
|
+
props: Record<string, unknown>;
|
|
55
|
+
source: DescribedSource | null;
|
|
56
|
+
stateNode: string | null;
|
|
57
|
+
owners: OwnerEntry[];
|
|
58
|
+
parents: OwnerEntry[];
|
|
59
|
+
} & HookSummary;
|
|
60
|
+
/**
|
|
61
|
+
* Find the React fiber key in a DOM node's own properties.
|
|
62
|
+
* Returns the property name (e.g. '__reactFiber$abc123') or null.
|
|
63
|
+
*/
|
|
64
|
+
export declare function getFiberKey(node: Node | Element | null | undefined): string | null;
|
|
65
|
+
/**
|
|
66
|
+
* Get the React fiber attached to a DOM node, or null if not a React host node.
|
|
67
|
+
*/
|
|
68
|
+
export declare function getFiber(node: Node | Element | null | undefined): Fiber | null;
|
|
69
|
+
/**
|
|
70
|
+
* Extract display name from a React type (class, function, or string).
|
|
71
|
+
* Returns displayName > name > null for functions; 'string' for primitives.
|
|
72
|
+
*/
|
|
73
|
+
export declare function getDisplayName(type: unknown): string | null;
|
|
74
|
+
/**
|
|
75
|
+
* True if fiber is a user-defined component (not a DOM string, not a hook-internal wrapper).
|
|
76
|
+
*/
|
|
77
|
+
export declare function isUserComponent(fiber: Fiber | null | undefined): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Walk DOM parents to find the nearest fiber-attached element.
|
|
80
|
+
*/
|
|
81
|
+
export declare function getNearestFiber(domNode: Node | Element | null | undefined): Fiber | null;
|
|
82
|
+
/**
|
|
83
|
+
* Walk DOM parents, then walk fiber return chain, to find the nearest user component.
|
|
84
|
+
*/
|
|
85
|
+
export declare function getNearestComponent(domNode: Node | Element | null | undefined): Fiber | null;
|
|
86
|
+
/**
|
|
87
|
+
* Count hooks in fiber.memoizedState linked list; detect cycle.
|
|
88
|
+
*/
|
|
89
|
+
export declare function getHookSummary(fiber: Fiber | null | undefined): HookSummary;
|
|
90
|
+
/**
|
|
91
|
+
* Walk fiber._debugOwner chain; collect all user components with metadata.
|
|
92
|
+
* Returns empty array if fiber or owner chain is null.
|
|
93
|
+
*/
|
|
94
|
+
export declare function getOwnerChain(fiber: Fiber | null | undefined): OwnerEntry[];
|
|
95
|
+
/**
|
|
96
|
+
* Walk fiber._debugOwner chain; return raw fiber nodes (for navigation).
|
|
97
|
+
*/
|
|
98
|
+
export declare function getOwnerFibers(fiber: Fiber | null | undefined): Fiber[];
|
|
99
|
+
/**
|
|
100
|
+
* Recursively walk fiber.child/sibling to find the first host DOM element rendered by this subtree.
|
|
101
|
+
*/
|
|
102
|
+
export declare function getFiberDomNode(fiber: Fiber | null | undefined): Element | null;
|
|
103
|
+
/**
|
|
104
|
+
* Walk fiber.return chain; collect all user component parents with metadata.
|
|
105
|
+
*/
|
|
106
|
+
export declare function getReturnComponentChain(fiber: Fiber | null | undefined): OwnerEntry[];
|
|
107
|
+
/**
|
|
108
|
+
* Walk fiber.return chain; return raw fiber nodes (for navigation).
|
|
109
|
+
*/
|
|
110
|
+
export declare function getReturnComponentFibers(fiber: Fiber | null | undefined): Fiber[];
|
|
111
|
+
/**
|
|
112
|
+
* Normalize source location object to canonical shape.
|
|
113
|
+
*/
|
|
114
|
+
export declare function describeSource(source: SourceLocation | null | undefined): DescribedSource | null;
|
|
115
|
+
/**
|
|
116
|
+
* Read a fiber source across React versions.
|
|
117
|
+
*
|
|
118
|
+
* React <=18 exposes `_debugSource`. React 19 exposes `_debugStack`; its first
|
|
119
|
+
* non-vendor frame is returned synchronously and may later be upgraded from the
|
|
120
|
+
* bundle position to the original source position by `resolveFiberSource`.
|
|
121
|
+
*/
|
|
122
|
+
export declare function describeFiberSource(fiber: Fiber | null | undefined): DescribedSource | null;
|
|
123
|
+
export declare function resolveFiberSource(fiber: Fiber | null | undefined): Promise<DescribedSource | null>;
|
|
124
|
+
/**
|
|
125
|
+
* Describe a fiber + DOM node pair; used for inspection UI.
|
|
126
|
+
*/
|
|
127
|
+
export declare function describeFiberTarget(fiber: Fiber | null | undefined, domNode: Element | null | undefined): FiberTarget | null;
|
|
128
|
+
/**
|
|
129
|
+
* Full component description: name, props, hook summary, source, owners, parents.
|
|
130
|
+
*/
|
|
131
|
+
export declare function describeComponent(fiber: Fiber | null | undefined): ComponentDescription | null;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Product-neutral marker context: the declarative boundaries around a probed
|
|
3
|
+
* fiber, plus whatever registered context providers add on top.
|
|
4
|
+
*
|
|
5
|
+
* The core detects Error and Suspense boundaries from fiber-native signals
|
|
6
|
+
* (./fiber-boundaries). A context provider is a plugin that recognizes
|
|
7
|
+
* app-specific conventions (for example an ownership marker component) and
|
|
8
|
+
* contributes named boundary kinds, error-boundary enrichment, and display
|
|
9
|
+
* hints. Providers never become a prerequisite for inspection: with none
|
|
10
|
+
* registered, a context still reports Error and Suspense boundaries.
|
|
11
|
+
*/
|
|
12
|
+
import type { Fiber } from './fiber-walk.js';
|
|
13
|
+
import { type BoundaryRef, type ErrorBoundaryInfo, type SuspenseBoundaryInfo } from './fiber-boundaries.js';
|
|
14
|
+
/** A boundary kind a provider adds next to the core `error` and `suspense`. */
|
|
15
|
+
export type ContextBoundaryKind = {
|
|
16
|
+
kind: string;
|
|
17
|
+
/** Short lozenge label shown in the probe UI, e.g. `owner`. */
|
|
18
|
+
label: string;
|
|
19
|
+
/** CSS color for the lozenge; UIs fall back to a neutral color. */
|
|
20
|
+
accent?: string;
|
|
21
|
+
};
|
|
22
|
+
export type ContextField = {
|
|
23
|
+
label: string;
|
|
24
|
+
value: string;
|
|
25
|
+
};
|
|
26
|
+
/** What one provider found for one probed fiber. Every part is optional. */
|
|
27
|
+
export type ContextContribution = {
|
|
28
|
+
/** Boundaries of this provider's declared kinds; `null` records "looked, not found". */
|
|
29
|
+
boundaries?: Record<string, BoundaryRef<Record<string, unknown>> | null>;
|
|
30
|
+
/** Fields merged onto the generic error boundary when one was found. */
|
|
31
|
+
errorEnrichment?: Record<string, unknown> | null;
|
|
32
|
+
/** Display title per boundary kind (core or provider kind). */
|
|
33
|
+
titles?: Record<string, string>;
|
|
34
|
+
/** Display fields per boundary kind (core or provider kind). */
|
|
35
|
+
fields?: Record<string, ContextField[]>;
|
|
36
|
+
/** Show the error row even when no error boundary fiber was found. */
|
|
37
|
+
showError?: boolean;
|
|
38
|
+
/** Extra top-level fields on the context, kept for provider-specific consumers. */
|
|
39
|
+
extra?: Record<string, unknown>;
|
|
40
|
+
};
|
|
41
|
+
export type ContextProvider = {
|
|
42
|
+
id: string;
|
|
43
|
+
kinds?: ContextBoundaryKind[];
|
|
44
|
+
/** Inspect the probed fiber's ancestry (nearest first). */
|
|
45
|
+
describe(fibers: Fiber[]): ContextContribution | null;
|
|
46
|
+
/** Return the provider kind this fiber is a boundary of, or null. Used for DOM highlighting. */
|
|
47
|
+
matchBoundary?(fiber: Fiber): string | null;
|
|
48
|
+
};
|
|
49
|
+
export type ContextDisplay = {
|
|
50
|
+
/** Provider kinds that have a boundary on this context, in registration order. */
|
|
51
|
+
kinds: ContextBoundaryKind[];
|
|
52
|
+
titles: Record<string, string>;
|
|
53
|
+
fields: Record<string, ContextField[]>;
|
|
54
|
+
showError: boolean;
|
|
55
|
+
};
|
|
56
|
+
export type MarkerContext = {
|
|
57
|
+
boundaries: {
|
|
58
|
+
error: BoundaryRef<ErrorBoundaryInfo & Record<string, unknown>> | null;
|
|
59
|
+
suspense: BoundaryRef<SuspenseBoundaryInfo> | null;
|
|
60
|
+
[kind: string]: BoundaryRef<Record<string, unknown>> | null;
|
|
61
|
+
};
|
|
62
|
+
display: ContextDisplay;
|
|
63
|
+
/** Ids of the providers that contributed to this context. */
|
|
64
|
+
providers: string[];
|
|
65
|
+
[extra: string]: unknown;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Register a context provider. Registering an id again replaces the earlier
|
|
69
|
+
* provider, so a re-injected bundle cannot double-count. Returns an unregister
|
|
70
|
+
* function.
|
|
71
|
+
*/
|
|
72
|
+
export declare function registerContextProvider(provider: ContextProvider): () => void;
|
|
73
|
+
export declare function getContextProviders(): Array<{
|
|
74
|
+
id: string;
|
|
75
|
+
kinds: ContextBoundaryKind[];
|
|
76
|
+
}>;
|
|
77
|
+
/**
|
|
78
|
+
* Collect the selected fiber first, then its rendered parent path, then its
|
|
79
|
+
* debug-owner path. Production builds often lack `_debugOwner`, while
|
|
80
|
+
* development builds benefit from both signals.
|
|
81
|
+
*/
|
|
82
|
+
export declare function collectContextFibers(fiber: Fiber | null | undefined): Fiber[];
|
|
83
|
+
/**
|
|
84
|
+
* Describe the boundaries around a probed fiber. Returns null when neither the
|
|
85
|
+
* core nor any provider found anything, so non-matching trees pay only one
|
|
86
|
+
* bounded ancestry walk.
|
|
87
|
+
*/
|
|
88
|
+
export declare function describeContext(fiber: Fiber | null | undefined): MarkerContext | null;
|
|
89
|
+
/**
|
|
90
|
+
* Locate the actual boundary FIBERS (not serialized descriptors) for every
|
|
91
|
+
* known kind around a probed fiber. Used in-page to resolve a boundary's DOM
|
|
92
|
+
* node for highlighting; it is not part of the serialized snapshot.
|
|
93
|
+
*/
|
|
94
|
+
export declare function findBoundaryFibers(fiber: Fiber | null | undefined): Record<string, Fiber | null>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Standalone commit detector. Install the bootstrap before React DOM loads. */
|
|
2
|
+
export { createAvalancheDetector, DETECTION_LEVEL } from '../avalanche/detector.js';
|
|
3
|
+
export type { DetectorOptions, Report, ReportOptions, SortBy } from '../avalanche/reporter.js';
|
|
4
|
+
export { type CommitMetricsAdapter, type IntegrationMode, registerCommitMetricsAdapter, } from '../avalanche/commit-metrics-adapter.js';
|
|
5
|
+
/** Opt-in adapter for hosts whose react-dom writes `__ATL_REACT_METRICS`. */
|
|
6
|
+
export { atlCommitMetricsAdapter, createATLCommitMetricsAdapter, } from '../plugins/atl/commit-metrics-adapter.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface BrowserConnection {
|
|
2
|
+
chippy: unknown;
|
|
3
|
+
avalanche: unknown;
|
|
4
|
+
connState: string | null;
|
|
5
|
+
integration: unknown;
|
|
6
|
+
activated: boolean | null;
|
|
7
|
+
probesActive: boolean | null;
|
|
8
|
+
}
|
|
9
|
+
/** Connect this document through a running Chippy helper. Reconnect after navigation. */
|
|
10
|
+
export declare function connectChippy(helperUrl?: string): Promise<BrowserConnection>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types and helpers for writing a Chippy plugin. `chippy pack` bundles a
|
|
3
|
+
* plugin module's default export into a custom skill and extension build.
|
|
4
|
+
*/
|
|
5
|
+
import type { ChippyPlugin } from '../plugins/index.js';
|
|
6
|
+
export type { ChippyPlugin, PluginStatus } from '../plugins/index.js';
|
|
7
|
+
export type { ContextBoundaryKind, ContextContribution, ContextField, ContextProvider, } from '../layout-lab/marker-context.js';
|
|
8
|
+
export type { Fiber } from '../layout-lab/fiber-walk.js';
|
|
9
|
+
export type { CommitMetricsAdapter, CommitMetricsDelta, CommitMetricsMeasurement, CommitMetricsRoot, CommitMetricsSnapshot, } from '../avalanche/commit-metrics-adapter.js';
|
|
10
|
+
/** Display name of a fiber's `type`: function, class, memo, or forwardRef. */
|
|
11
|
+
export { getDisplayName } from '../layout-lab/fiber-walk.js';
|
|
12
|
+
/** Fiber name helpers that commit metrics adapters use for hook ancestry. */
|
|
13
|
+
export { getComponentName, isComponentFiber } from '../avalanche/internals.js';
|
|
14
|
+
/** Identity helper that type-checks a plugin definition. */
|
|
15
|
+
export declare function definePlugin(plugin: ChippyPlugin): ChippyPlugin;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ATL commit metrics adapter: reads the render counters that Atlassian's
|
|
3
|
+
* patched react-dom writes into `__ATL_REACT_METRICS` and routes that slot's
|
|
4
|
+
* `onCommitFiberRoot` callback to the detector.
|
|
5
|
+
*
|
|
6
|
+
* The slot name is configurable, so a renamed slot needs no core change.
|
|
7
|
+
*/
|
|
8
|
+
import type { CommitMetricsAdapter, CommitMetricsSnapshot } from '../../avalanche/commit-metrics-adapter.js';
|
|
9
|
+
/**
|
|
10
|
+
* Per-commit ATL delta - work done in a single commit.
|
|
11
|
+
* Enables full reconciliation: ATL work counts ↔ Avalanche component counts.
|
|
12
|
+
*
|
|
13
|
+
* Key relationship (should hold for any commit):
|
|
14
|
+
* componentRenderWithHooksCount + finishClassComponentCount === collateral + sources
|
|
15
|
+
*/
|
|
16
|
+
export type ATLCommitDelta = {
|
|
17
|
+
/** Function components mounted this commit (should be 0 during pure updates!) */
|
|
18
|
+
mountWorkCount: number;
|
|
19
|
+
/** Fiber update work this commit */
|
|
20
|
+
updateWorkCount: number;
|
|
21
|
+
/** Work that reached commit phase */
|
|
22
|
+
commitWorkCount: number;
|
|
23
|
+
performedWorkCount: number;
|
|
24
|
+
/** Work interrupted (priority change) */
|
|
25
|
+
interruptedWorkCount: number;
|
|
26
|
+
/** Component fiber work (class + function) */
|
|
27
|
+
componentWorkCount: number;
|
|
28
|
+
/** Components mounted (should be 0 during pure updates!) */
|
|
29
|
+
componentMountWorkCount: number;
|
|
30
|
+
/** Components updated */
|
|
31
|
+
componentUpdateWorkCount: number;
|
|
32
|
+
/** DOM work (host fibers) */
|
|
33
|
+
domWorkCount: number;
|
|
34
|
+
ticksCount: number;
|
|
35
|
+
/** Context propagation waves */
|
|
36
|
+
contextUpdateCount: number;
|
|
37
|
+
/** Legacy context propagations (tech debt indicator) */
|
|
38
|
+
legacyContextUpdateCount: number;
|
|
39
|
+
/** ALL function components rendered (including hookless) */
|
|
40
|
+
componentRenderWithHooksCount: number;
|
|
41
|
+
/** Class components rendered */
|
|
42
|
+
finishClassComponentCount: number;
|
|
43
|
+
/** useSES-triggered restarts (store mutation detected after concurrent render) */
|
|
44
|
+
externalStoreRestartCount?: number;
|
|
45
|
+
/** Work abandoned due to priority preemption (fibers unwound in prepareFreshStack) */
|
|
46
|
+
priorityInterruptedWorkCount?: number;
|
|
47
|
+
/** Number of sync renderRoot passes in this commit window */
|
|
48
|
+
renderRootSyncCount?: number;
|
|
49
|
+
/** Number of concurrent renderRoot passes in this commit window */
|
|
50
|
+
renderRootConcurrentCount?: number;
|
|
51
|
+
/** useState/useReducer dispatches during this commit (react-dom patch; optional) */
|
|
52
|
+
setStateCount?: number;
|
|
53
|
+
};
|
|
54
|
+
export declare const ATL_DISPATCHER_FRAME = "atlDispatcherHook";
|
|
55
|
+
/** Counter delta between two ATL snapshots. */
|
|
56
|
+
export declare function calculateATLDelta(before: CommitMetricsSnapshot, after: CommitMetricsSnapshot): ATLCommitDelta;
|
|
57
|
+
export type ATLCommitMetricsAdapterOptions = {
|
|
58
|
+
/** Global slot the patched react-dom writes. Default `__ATL_REACT_METRICS`. */
|
|
59
|
+
slotName?: string;
|
|
60
|
+
/** Object that holds the slot. Default `globalThis`. */
|
|
61
|
+
target?: Record<string, unknown>;
|
|
62
|
+
};
|
|
63
|
+
export declare function createATLCommitMetricsAdapter(options?: ATLCommitMetricsAdapterOptions): CommitMetricsAdapter;
|
|
64
|
+
/** The adapter the shipped bundle registers. */
|
|
65
|
+
export declare const atlCommitMetricsAdapter: CommitMetricsAdapter;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seed, protect, and guard a host metrics slot such as `__ATL_REACT_METRICS`.
|
|
3
|
+
*
|
|
4
|
+
* The host page owns the slot. Its instrumented react-dom reads the slot before
|
|
5
|
+
* it calls `onCommitFiberRoot`, and its runtime may zero-fill or delete the slot
|
|
6
|
+
* during hydration cleanup. These helpers never lock the slot: every descriptor
|
|
7
|
+
* they write stays `configurable: true`, and a slot the host already locked is
|
|
8
|
+
* left alone.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_METRICS_SLOT = "__ATL_REACT_METRICS";
|
|
11
|
+
/** Counters a zeroed slot starts with. */
|
|
12
|
+
export declare const METRICS_COUNTER_KEYS: readonly ["mountWorkCount", "updateWorkCount", "commitWorkCount", "interruptedWorkCount", "priorityInterruptedWorkCount", "externalStoreRestartCount", "renderRootSyncCount", "renderRootConcurrentCount", "componentWorkCount", "componentMountWorkCount", "componentUpdateWorkCount", "componentRenderWithHooksCount", "finishClassComponentCount", "domWorkCount", "totalTickCount", "totalCommitCount", "contextUpdateCount", "legacyContextUpdateCount"];
|
|
13
|
+
type SlotTarget = Record<string, unknown>;
|
|
14
|
+
export type MetricsSlotValue = Record<string, unknown>;
|
|
15
|
+
export declare function createZeroMetrics(): MetricsSlotValue;
|
|
16
|
+
/** True when the host owns the slot: non-configurable, or an accessor. */
|
|
17
|
+
export declare function isSlotHostLocked(target: SlotTarget, slotName?: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Write `metrics` as a plain, deletable data property. Honors a host lock
|
|
20
|
+
* (configurable: false). Falls back to plain assignment.
|
|
21
|
+
*/
|
|
22
|
+
export declare function protectMetricsSlot(target: SlotTarget, metrics: MetricsSlotValue, slotName?: string): void;
|
|
23
|
+
/** Seed a fresh zeroed slot. Returns the new metrics object. */
|
|
24
|
+
export declare function seedMetricsSlot(target: SlotTarget, slotName?: string): MetricsSlotValue;
|
|
25
|
+
/**
|
|
26
|
+
* Install a configurable accessor on the slot before React evaluates.
|
|
27
|
+
*
|
|
28
|
+
* - `configurable: true`, so a host `delete` succeeds without a TypeError.
|
|
29
|
+
* After a delete the slot is gone until the next detector install re-seeds it.
|
|
30
|
+
* - `set()` ignores null, undefined, and all-zero writes, so host hydration
|
|
31
|
+
* cleanup that zero-fills the slot cannot orphan the live metrics object.
|
|
32
|
+
* - A slot the host already locked is left alone.
|
|
33
|
+
*
|
|
34
|
+
* Returns true when the accessor was installed.
|
|
35
|
+
*/
|
|
36
|
+
export declare function installMetricsAccessor(target: SlotTarget, slotName?: string): boolean;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chippy plugin registry. The core runtime has no product knowledge; plugins
|
|
3
|
+
* add it through the context provider and commit metrics adapter seams.
|
|
4
|
+
*
|
|
5
|
+
* The bundle ships the built-in Jira and ATL plugins, and a packed build
|
|
6
|
+
* (`chippy pack`) appends more through `__AVALANCHE__.registerPlugin()`. A
|
|
7
|
+
* plugin runs only once it is both registered and enabled. A page enables
|
|
8
|
+
* plugins through the startup config (`plugins: ['jira', 'atl']`), the
|
|
9
|
+
* `__CHIPPY_PLUGINS` global, or `__AVALANCHE__.enablePlugins()`; a packed
|
|
10
|
+
* build can name defaults for pages that do neither.
|
|
11
|
+
*/
|
|
12
|
+
import { type CommitMetricsAdapter } from '../avalanche/commit-metrics-adapter.js';
|
|
13
|
+
import { type ContextProvider } from '../layout-lab/marker-context.js';
|
|
14
|
+
export type ChippyPlugin = {
|
|
15
|
+
/** Stable id used to enable the plugin, e.g. `'jira'`. */
|
|
16
|
+
id: string;
|
|
17
|
+
/** Short name shown in the extension's plugin settings. */
|
|
18
|
+
label?: string;
|
|
19
|
+
contextProvider?: ContextProvider;
|
|
20
|
+
commitMetricsAdapter?: CommitMetricsAdapter;
|
|
21
|
+
};
|
|
22
|
+
export type PluginStatus = {
|
|
23
|
+
id: string;
|
|
24
|
+
label: string;
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
};
|
|
27
|
+
export declare const BUILTIN_PLUGINS: readonly ChippyPlugin[];
|
|
28
|
+
/**
|
|
29
|
+
* Register a plugin. It starts at once if its id was already enabled.
|
|
30
|
+
* Registering the same id again replaces the earlier plugin.
|
|
31
|
+
*/
|
|
32
|
+
export declare function registerPlugin(plugin: ChippyPlugin): () => void;
|
|
33
|
+
/**
|
|
34
|
+
* Enable plugins by id. An id that is not registered yet starts when its
|
|
35
|
+
* plugin registers; non-string ids are ignored. Returns the running ids.
|
|
36
|
+
*/
|
|
37
|
+
export declare function enablePlugins(ids: unknown): string[];
|
|
38
|
+
/**
|
|
39
|
+
* Record the page's own plugin selection. Once a page has chosen, build
|
|
40
|
+
* defaults no longer apply, so a user who turned a default off keeps it off.
|
|
41
|
+
*/
|
|
42
|
+
export declare function selectPlugins(ids: unknown): string[];
|
|
43
|
+
/** Enable a packed build's default plugins unless the page made its own selection. */
|
|
44
|
+
export declare function enableDefaultPlugins(ids: unknown): string[];
|
|
45
|
+
export declare function listPlugins(): PluginStatus[];
|
|
46
|
+
/** Register the built-in plugins. Returns a function that removes them. */
|
|
47
|
+
export declare function registerBuiltinPlugins(): () => void;
|
|
48
|
+
/** Stop every plugin and forget all registrations and selections. Test helper. */
|
|
49
|
+
export declare function resetPlugins(): void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jira context provider: recognizes Jira's OwnerMark/OwnershipMark ownership
|
|
3
|
+
* markers and JSErrorBoundary props, and layers them onto the generic marker
|
|
4
|
+
* context as an `owner` boundary kind and error-boundary enrichment.
|
|
5
|
+
*
|
|
6
|
+
* Registered by the bundle's composition root; the core marker context works
|
|
7
|
+
* without it.
|
|
8
|
+
*/
|
|
9
|
+
import { type Fiber } from '../../layout-lab/fiber-walk.js';
|
|
10
|
+
import { type ContextContribution, type ContextProvider, type MarkerContext } from '../../layout-lab/marker-context.js';
|
|
11
|
+
export type JiraOwnership = {
|
|
12
|
+
markerName: string;
|
|
13
|
+
type: string | null;
|
|
14
|
+
name: string | null;
|
|
15
|
+
packageName: string | null;
|
|
16
|
+
teamName: string | null;
|
|
17
|
+
variant: string | null;
|
|
18
|
+
source: 'display-name' | 'props';
|
|
19
|
+
};
|
|
20
|
+
export type JiraErrorBoundary = {
|
|
21
|
+
componentName: string;
|
|
22
|
+
id: string | null;
|
|
23
|
+
packageName: string | null;
|
|
24
|
+
fallback: string | null;
|
|
25
|
+
teamName: string | null;
|
|
26
|
+
};
|
|
27
|
+
export declare function parseOwnerMarkDisplayName(displayName: string | null | undefined): JiraOwnership | null;
|
|
28
|
+
export declare function describeOwnership(fiber: Fiber): JiraOwnership | null;
|
|
29
|
+
/**
|
|
30
|
+
* Scan the probed ancestry for OwnerMark ownership, the nearest JSErrorBoundary,
|
|
31
|
+
* and Jira's ErrorComponent fallback marker.
|
|
32
|
+
*/
|
|
33
|
+
export declare function describeJiraContribution(fibers: Fiber[]): ContextContribution | null;
|
|
34
|
+
export declare const jiraContextProvider: ContextProvider;
|
|
35
|
+
/** The marker context with the Jira fields always present. */
|
|
36
|
+
export declare function describeJiraContext(fiber: Fiber | null | undefined): MarkerContext | null;
|