@atlassian/chippy 0.0.0-stage → 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 (133) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +276 -2
  3. package/bin/chippy.mjs +92 -0
  4. package/bin/pack.mjs +204 -0
  5. package/bin/skill-dir.mjs +15 -0
  6. package/lib/avalanche.js +2601 -0
  7. package/lib/avalanche.js.map +7 -0
  8. package/lib/bootstrap.d.ts +1 -0
  9. package/lib/bootstrap.js +70 -0
  10. package/lib/bootstrap.js.map +7 -0
  11. package/lib/browser.js +15 -0
  12. package/lib/browser.js.map +7 -0
  13. package/lib/extension/avalanche.es.js +5535 -0
  14. package/lib/extension/avalanche.es.js.map +1 -0
  15. package/lib/extension/chippy-page-bridge.js +1953 -0
  16. package/lib/extension/inspect-react.js +216 -0
  17. package/lib/extension/layout-lab.js +1453 -0
  18. package/lib/extension/panel-dom.js +90 -0
  19. package/lib/extension/resolve-probes.js +342 -0
  20. package/lib/mcp-skill/LICENSE +201 -0
  21. package/lib/mcp-skill/README.md +148 -0
  22. package/lib/mcp-skill/SKILL.md +335 -0
  23. package/lib/mcp-skill/browser-scripts/playwright-probes.js +368 -0
  24. package/lib/mcp-skill/browser-scripts/playwright-session.js +114 -0
  25. package/lib/mcp-skill/extension/armed-reload-startup.js +83 -0
  26. package/lib/mcp-skill/extension/avalanche.es.js +5535 -0
  27. package/lib/mcp-skill/extension/avalanche.es.js.map +1 -0
  28. package/lib/mcp-skill/extension/avalanche.iife.js +5536 -0
  29. package/lib/mcp-skill/extension/avalanche.iife.js.map +1 -0
  30. package/lib/mcp-skill/extension/background.js +325 -0
  31. package/lib/mcp-skill/extension/chippy-page-bridge.js +1953 -0
  32. package/lib/mcp-skill/extension/content-script.js +190 -0
  33. package/lib/mcp-skill/extension/devtools-hook-shim.js +85 -0
  34. package/lib/mcp-skill/extension/early-bootstrap.js +49 -0
  35. package/lib/mcp-skill/extension/icon-128.png +0 -0
  36. package/lib/mcp-skill/extension/icon-16.png +0 -0
  37. package/lib/mcp-skill/extension/icon-32.png +0 -0
  38. package/lib/mcp-skill/extension/icon-48.png +0 -0
  39. package/lib/mcp-skill/extension/inspect-react.js +216 -0
  40. package/lib/mcp-skill/extension/layout-lab.js +1453 -0
  41. package/lib/mcp-skill/extension/logo.svg +14 -0
  42. package/lib/mcp-skill/extension/manifest.json +69 -0
  43. package/lib/mcp-skill/extension/panel-dom.js +90 -0
  44. package/lib/mcp-skill/extension/panel-settings.js +173 -0
  45. package/lib/mcp-skill/extension/popup.html +41 -0
  46. package/lib/mcp-skill/extension/popup.js +80 -0
  47. package/lib/mcp-skill/extension/probe-descriptor.js +241 -0
  48. package/lib/mcp-skill/extension/resolve-probes.js +342 -0
  49. package/lib/mcp-skill/extension/startup-handoff.js +30 -0
  50. package/lib/mcp-skill/package.json +1 -0
  51. package/lib/mcp-skill/references/README.md +56 -0
  52. package/lib/mcp-skill/references/active-stimulus.md +85 -0
  53. package/lib/mcp-skill/references/avalanche-detector.md +731 -0
  54. package/lib/mcp-skill/references/bdd-router.md +310 -0
  55. package/lib/mcp-skill/references/browser-runtime-api.md +193 -0
  56. package/lib/mcp-skill/references/command-output-formats.md +1085 -0
  57. package/lib/mcp-skill/references/command-surface.md +183 -0
  58. package/lib/mcp-skill/references/cynefin.md +99 -0
  59. package/lib/mcp-skill/references/debug-hook.md +161 -0
  60. package/lib/mcp-skill/references/fixing-performance.md +490 -0
  61. package/lib/mcp-skill/references/hook-metrics.md +199 -0
  62. package/lib/mcp-skill/references/hooks-inspection.md +61 -0
  63. package/lib/mcp-skill/references/jira-taxonomy.md +81 -0
  64. package/lib/mcp-skill/references/mcp.md +122 -0
  65. package/lib/mcp-skill/references/mode-a-injection.md +102 -0
  66. package/lib/mcp-skill/references/operating-model.md +128 -0
  67. package/lib/mcp-skill/references/playwright-cli-setup.md +105 -0
  68. package/lib/mcp-skill/references/playwright-probes.md +205 -0
  69. package/lib/mcp-skill/references/procedures.md +545 -0
  70. package/lib/mcp-skill/references/recipes.txt +114 -0
  71. package/lib/mcp-skill/references/stability-render.md +428 -0
  72. package/lib/mcp-skill/references/test-mode-playbook.md +194 -0
  73. package/lib/mcp-skill/references/troubleshooting.md +59 -0
  74. package/lib/mcp-skill/scripts/avalanche-analyze.cjs +495 -0
  75. package/lib/mcp-skill/scripts/build-avalanche-command.js +34 -0
  76. package/lib/mcp-skill/scripts/build-fiber-state-command.js +19 -0
  77. package/lib/mcp-skill/scripts/chippy-helper-server.js +1768 -0
  78. package/lib/mcp-skill/scripts/chippy-mcp.cjs +273 -0
  79. package/lib/mcp-skill/scripts/chippy.sh +1252 -0
  80. package/lib/mcp-skill/scripts/format-probe-result.js +34 -0
  81. package/lib/mcp-skill/scripts/helper-access.js +158 -0
  82. package/lib/mcp-skill/scripts/helper-proxy.js +87 -0
  83. package/lib/mcp-skill/scripts/page-socket-trust.js +81 -0
  84. package/lib/mcp-skill/scripts/probe-annotation-channel.js +116 -0
  85. package/lib/mcp-skill/scripts/search-recipes.js +248 -0
  86. package/lib/mcp-skill/snippets/README.md +89 -0
  87. package/lib/mcp-skill/snippets/count-context-consumers.js +40 -0
  88. package/lib/mcp-skill/snippets/find-context-providers.js +38 -0
  89. package/lib/mcp-skill/snippets/find-legacy-context.js +47 -0
  90. package/lib/mcp-skill/snippets/find-prop.js +83 -0
  91. package/lib/mcp-skill/snippets/hook-metrics-sample.js +69 -0
  92. package/lib/mcp-skill/snippets/hook-metrics.js +60 -0
  93. package/lib/mcp-skill/snippets/hook-tracker.js +198 -0
  94. package/lib/mcp-skill/snippets/stability-nudge.js +101 -0
  95. package/lib/package.json +1 -0
  96. package/lib/plugin.js +119 -0
  97. package/lib/plugin.js.map +7 -0
  98. package/lib/storybook/avalanche-panel-model.js +79 -0
  99. package/lib/storybook/brand.jsx +6 -0
  100. package/lib/storybook/connection-fallback.jsx +47 -0
  101. package/lib/storybook/constants.js +15 -0
  102. package/lib/storybook/context-card.jsx +171 -0
  103. package/lib/storybook/manager-owner.js +42 -0
  104. package/lib/storybook/manager.jsx +425 -0
  105. package/lib/storybook/preset.js +7 -0
  106. package/lib/storybook/preview.js +298 -0
  107. package/lib/storybook/probe-annotation-editor.jsx +52 -0
  108. package/lib/storybook/probe-intent.js +23 -0
  109. package/lib/storybook/setup.js +104 -0
  110. package/lib/types/avalanche/commit-metrics-adapter.d.ts +76 -0
  111. package/lib/types/avalanche/commit-stats-indices.d.ts +41 -0
  112. package/lib/types/avalanche/commit-surface-ownership.d.ts +9 -0
  113. package/lib/types/avalanche/detector.d.ts +183 -0
  114. package/lib/types/avalanche/interaction-capture.d.ts +25 -0
  115. package/lib/types/avalanche/internals.d.ts +189 -0
  116. package/lib/types/avalanche/report-serializer.d.ts +283 -0
  117. package/lib/types/avalanche/reporter.d.ts +610 -0
  118. package/lib/types/chippy-bridge/fiber-source.d.ts +48 -0
  119. package/lib/types/chippy-bridge/react-renderer.d.ts +74 -0
  120. package/lib/types/chippy-bridge/recorded-source.d.ts +44 -0
  121. package/lib/types/chippy-bridge/source-map.d.ts +30 -0
  122. package/lib/types/debug-render/core.d.ts +78 -0
  123. package/lib/types/layout-lab/fiber-boundaries.d.ts +51 -0
  124. package/lib/types/layout-lab/fiber-walk.d.ts +131 -0
  125. package/lib/types/layout-lab/marker-context.d.ts +94 -0
  126. package/lib/types/package/avalanche.d.ts +6 -0
  127. package/lib/types/package/browser.d.ts +10 -0
  128. package/lib/types/package/plugin.d.ts +15 -0
  129. package/lib/types/plugins/atl/commit-metrics-adapter.d.ts +65 -0
  130. package/lib/types/plugins/atl/metrics-slot.d.ts +37 -0
  131. package/lib/types/plugins/index.d.ts +49 -0
  132. package/lib/types/plugins/jira/context-provider.d.ts +36 -0
  133. package/package.json +106 -4
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+
3
+ export const CHIPPY_INSTALL_COMMAND = 'npx skills add atlassian-labs/chippy --skill chippy -g';
4
+
5
+ const unavailableConnectionStates = new Set(['failed', 'reconnecting']);
6
+
7
+ export function shouldShowChippyInstallHint(connState) {
8
+ return unavailableConnectionStates.has(connState);
9
+ }
10
+
11
+ export function ChippyConnectionFallback({ connState }) {
12
+ if (!shouldShowChippyInstallHint(connState)) return null;
13
+
14
+ return (
15
+ <div
16
+ role="status"
17
+ data-testid="chippy-install-hint"
18
+ style={{
19
+ marginBottom: 8,
20
+ padding: '10px 12px',
21
+ border: '1px solid var(--color-warning-border, #b88a00)',
22
+ borderRadius: 8,
23
+ background: 'var(--color-warning-background, color-mix(in srgb, #b88a00 12%, Canvas))',
24
+ color: 'var(--color-default-text, CanvasText)',
25
+ fontSize: 12,
26
+ lineHeight: 1.45,
27
+ }}
28
+ >
29
+ <div style={{ marginBottom: 6 }}>
30
+ Chippy’s local helper isn’t reachable. If Chippy isn’t installed for your agent, run:
31
+ </div>
32
+ <code
33
+ style={{
34
+ display: 'block',
35
+ padding: '7px 8px',
36
+ borderRadius: 6,
37
+ background: 'var(--color-elevated-surface, color-mix(in srgb, Canvas 88%, CanvasText 12%))',
38
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',
39
+ overflowWrap: 'anywhere',
40
+ userSelect: 'all',
41
+ }}
42
+ >
43
+ {CHIPPY_INSTALL_COMMAND}
44
+ </code>
45
+ </div>
46
+ );
47
+ }
@@ -0,0 +1,15 @@
1
+ export const ADDON_ID = 'local/chippy';
2
+ export const CHIPPY_PANEL_ID = `${ADDON_ID}/chippy-panel`;
3
+ export const AVALANCHE_PANEL_ID = `${ADDON_ID}/avalanche-panel`;
4
+
5
+ export const EVENTS = {
6
+ REQUEST_STATE: `${ADDON_ID}/request-state`,
7
+ STATE: `${ADDON_ID}/state`,
8
+ COMMAND: `${ADDON_ID}/command`,
9
+ RESULT: `${ADDON_ID}/result`,
10
+ SET_MODE: `${ADDON_ID}/set-mode`,
11
+ BLOCKED: `${ADDON_ID}/blocked`,
12
+ ERROR: `${ADDON_ID}/error`,
13
+ };
14
+
15
+ export const PREVIEW_MESSAGE_SOURCE = 'local/chippy/storybook-preview-message';
@@ -0,0 +1,171 @@
1
+ import React from 'react';
2
+
3
+ const colors = {
4
+ text: 'var(--color-default-text, CanvasText)',
5
+ muted: 'var(--color-subtle-text, color-mix(in srgb, CanvasText 64%, transparent))',
6
+ border: 'var(--color-medium-border, color-mix(in srgb, CanvasText 18%, transparent))',
7
+ provider: 'var(--color-accent, #5e6c84)',
8
+ error: 'var(--color-negative-text, #ae2e24)',
9
+ suspense: 'var(--color-purple-text, #7c3aed)',
10
+ };
11
+
12
+ function DetailFields({ fields }) {
13
+ const visible = fields.filter(([, value]) => value != null && value !== '');
14
+ if (!visible.length) return null;
15
+ return (
16
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '3px 10px', marginTop: 5, color: colors.muted, fontSize: 11 }}>
17
+ {visible.map(([label, value]) => (
18
+ <span key={label}>
19
+ <span style={{ textTransform: 'lowercase' }}>{label}</span>{' '}
20
+ <strong style={{ color: colors.text }}>{String(value)}</strong>
21
+ </span>
22
+ ))}
23
+ </div>
24
+ );
25
+ }
26
+
27
+ function DistanceBadge({ distance }) {
28
+ if (distance == null) return null;
29
+ const hops = distance === 1 ? '1 hop' : `${distance} hops`;
30
+ return (
31
+ <span
32
+ data-testid="chippy-boundary-distance"
33
+ style={{
34
+ marginLeft: 'auto',
35
+ padding: '1px 6px',
36
+ borderRadius: 999,
37
+ background: 'color-mix(in srgb, CanvasText 12%, transparent)',
38
+ color: colors.muted,
39
+ fontSize: 10,
40
+ fontWeight: 600,
41
+ flexShrink: 0,
42
+ }}
43
+ >
44
+ {hops}
45
+ </span>
46
+ );
47
+ }
48
+
49
+ // A single declarative boundary block. Clickable: reports the boundary + its
50
+ // fiber-hop distance to the Chippy backend so it can be investigated later.
51
+ // This is NOT the React render owner -- it is a collateral-scope boundary.
52
+ function BoundaryBlock({ testId, kind, label, title, accent, distance, fields, onInspect, selected, onSelect }) {
53
+ const clickable = typeof onInspect === 'function';
54
+ const activate = clickable
55
+ ? () => {
56
+ if (onSelect) onSelect(kind);
57
+ onInspect(kind);
58
+ }
59
+ : undefined;
60
+ return (
61
+ <div
62
+ data-testid={testId}
63
+ data-chippy-boundary={kind}
64
+ role={clickable ? 'button' : undefined}
65
+ tabIndex={clickable ? 0 : undefined}
66
+ onClick={activate}
67
+ onKeyDown={
68
+ clickable
69
+ ? (e) => {
70
+ if (e.key === 'Enter' || e.key === ' ') {
71
+ e.preventDefault();
72
+ activate();
73
+ }
74
+ }
75
+ : undefined
76
+ }
77
+ style={{
78
+ borderLeft: `3px solid ${accent}`,
79
+ padding: '6px 8px',
80
+ background: 'color-mix(in srgb, Canvas 94%, CanvasText 6%)',
81
+ cursor: clickable ? 'pointer' : 'default',
82
+ outline: selected ? '2px solid var(--color-default-text, CanvasText)' : 'none',
83
+ outlineOffset: selected ? 1 : 0,
84
+ }}
85
+ data-chippy-boundary-selected={selected ? 'true' : undefined}
86
+ >
87
+ <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, minWidth: 0 }}>
88
+ <span style={{ color: accent, fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '.04em', flexShrink: 0 }}>{label}</span>
89
+ <strong style={{ color: colors.text, fontSize: 12, overflowWrap: 'anywhere' }}>{title}</strong>
90
+ <DistanceBadge distance={distance} />
91
+ </div>
92
+ <DetailFields fields={fields} />
93
+ </div>
94
+ );
95
+ }
96
+
97
+ const EMPTY_DISPLAY = { kinds: [], titles: {}, fields: {}, showError: false };
98
+
99
+ function contextDisplay(context) {
100
+ return context.display || EMPTY_DISPLAY;
101
+ }
102
+
103
+ function toFieldPairs(fields) {
104
+ return (fields || []).map((field) => [field.label, field.value]);
105
+ }
106
+
107
+ /**
108
+ * Renders the marker context: provider boundary kinds first (for example a
109
+ * team ownership marker), then the fiber-native error and suspense boundaries.
110
+ * Without onInspectBoundary the boundary blocks render as static facts.
111
+ * @param {{ context: any, onInspectBoundary?: (kind: string) => void }} props
112
+ */
113
+ export function ContextCard({ context, onInspectBoundary }) {
114
+ const [selectedKind, setSelectedKind] = React.useState(null);
115
+ if (!context) return null;
116
+ const display = contextDisplay(context);
117
+ const boundaries = context.boundaries || {};
118
+ const providerKinds = (display.kinds || []).filter((kind) => boundaries[kind.kind]);
119
+ const error = boundaries.error || null;
120
+ const suspense = boundaries.suspense || null;
121
+ const showError = !!(error || display.showError);
122
+ if (!providerKinds.length && !showError && !suspense) return null;
123
+
124
+ const blockProps = (kind) => ({
125
+ onInspect: onInspectBoundary,
126
+ selected: selectedKind === kind,
127
+ onSelect: setSelectedKind,
128
+ });
129
+
130
+ return (
131
+ <div data-testid="chippy-context" style={{ display: 'grid', gap: 5, marginTop: 8, borderTop: `1px solid ${colors.border}`, paddingTop: 8 }}>
132
+ {providerKinds.map((kind) => (
133
+ <BoundaryBlock
134
+ key={kind.kind}
135
+ testId={`chippy-boundary-${kind.kind}`}
136
+ kind={kind.kind}
137
+ label={kind.label}
138
+ title={display.titles?.[kind.kind] || boundaries[kind.kind]?.componentName || kind.label}
139
+ accent={kind.accent || colors.provider}
140
+ distance={boundaries[kind.kind]?.distance}
141
+ fields={toFieldPairs(display.fields?.[kind.kind])}
142
+ {...blockProps(kind.kind)}
143
+ />
144
+ ))}
145
+ {showError ? (
146
+ <BoundaryBlock
147
+ testId="chippy-boundary-error"
148
+ kind="error"
149
+ label="error boundary"
150
+ title={display.titles?.error || error?.componentName || 'ErrorBoundary'}
151
+ accent={colors.error}
152
+ distance={error?.distance}
153
+ fields={toFieldPairs(display.fields?.error)}
154
+ {...blockProps('error')}
155
+ />
156
+ ) : null}
157
+ {suspense ? (
158
+ <BoundaryBlock
159
+ testId="chippy-boundary-suspense"
160
+ kind="suspense"
161
+ label="suspense boundary"
162
+ title={suspense.componentName || 'Suspense'}
163
+ accent={colors.suspense}
164
+ distance={suspense.distance}
165
+ fields={[]}
166
+ {...blockProps('suspense')}
167
+ />
168
+ ) : null}
169
+ </div>
170
+ );
171
+ }
@@ -0,0 +1,42 @@
1
+ // The addon owns Chippy for the whole Storybook page, not only the preview
2
+ // iframe. The Chippy extension injects into the top frame, which is the
3
+ // Storybook manager, and stands down when a live owner of another integration
4
+ // holds window.__CHIPPY_OWNER__. Claiming the manager window keeps agents on the
5
+ // preview's `storybook` client instead of Storybook's own UI.
6
+ const OWNER_ID = 'storybook-addon-manager';
7
+ const STALE_AFTER_MS = 15_000;
8
+ const HEARTBEAT_MS = 5_000;
9
+
10
+ export const MANAGER_INTEGRATION = Object.freeze({
11
+ kind: 'storybook',
12
+ who: 'Chippy Storybook addon',
13
+ source: '.storybook/chippy-addon/manager-owner.js',
14
+ reinjectsOnReload: true,
15
+ reloadAction: 'The manager window holds no Chippy client; the preview iframe is the inspected page.',
16
+ });
17
+
18
+ export function claimManagerOwner(scope = globalThis) {
19
+ const now = Date.now();
20
+ scope.__CHIPPY_OWNER__ = {
21
+ ownerId: OWNER_ID,
22
+ ownerType: OWNER_ID,
23
+ integration: MANAGER_INTEGRATION,
24
+ staleAfterMs: STALE_AFTER_MS,
25
+ startedAt: now,
26
+ heartbeatAt: now,
27
+ };
28
+ try {
29
+ scope.dispatchEvent(new CustomEvent('chippy-owner-claimed', { detail: JSON.stringify({ ownerId: OWNER_ID }) }));
30
+ } catch (_) {}
31
+ const timer = setInterval(() => {
32
+ if (scope.__CHIPPY_OWNER__?.ownerId === OWNER_ID) scope.__CHIPPY_OWNER__.heartbeatAt = Date.now();
33
+ }, HEARTBEAT_MS);
34
+ return () => clearInterval(timer);
35
+ }
36
+
37
+ // An extension bridge that did not stand down, such as one from an older
38
+ // extension version, is still connected to the helper from this window.
39
+ export function extensionBridgeInManager(scope = globalThis) {
40
+ const state = scope.__CHIPPY?.pageBridge?.getState?.();
41
+ return state?.integration?.kind === 'extension' && state.connState !== 'yielded' ? state : null;
42
+ }