@atlaskit/editor-plugin-collab-edit 13.0.30 → 13.1.0

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.
@@ -0,0 +1,163 @@
1
+ import { getCollabState } from '@atlaskit/prosemirror-collab';
2
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
3
+ // When an agent step lands we cover the top-level block(s) it wrote with a skeleton-loader shimmer
4
+ // (plus a Rovo agent telepointer at the end of the range), then remove it on a timer to reveal the
5
+ // content. Gated behind the `platform_editor_agent_be_streaming` experiment; `durationMs` sets how
6
+ // long the shimmer stays and a 0 duration disables it.
7
+ var agentShimmerIdCounter = 0;
8
+
9
+ // A step is position-neutral when its StepMap changes no range's length — i.e. it shifts no
10
+ // positions. Attribute-only steps (e.g. `localId` assignment) produce an empty StepMap, and
11
+ // same-size replacements preserve lengths, so both are position-neutral. Used to decide whether a
12
+ // rebase over local unconfirmed steps could have invalidated our index-based range math.
13
+ export var isPositionNeutralStep = function isPositionNeutralStep(step) {
14
+ var neutral = true;
15
+ step.getMap().forEach(function (oldStart, oldEnd, newStart, newEnd) {
16
+ if (oldEnd - oldStart !== newEnd - newStart) {
17
+ neutral = false;
18
+ }
19
+ });
20
+ return neutral;
21
+ };
22
+
23
+ /**
24
+ * Derive the shimmer ranges for the agent-authored steps in a received batch, in final-doc
25
+ * coordinates. `agentType` present ⇒ agent-authored (per the NCS↔Editor steps contract). Each
26
+ * emitted range is expanded to the whole top-level block(s) the agent touched, which the plugin
27
+ * covers with the skeleton shimmer. Ranges with no new content (pure deletions) are dropped.
28
+ *
29
+ * Steps whose new content is in the same or directly-adjacent top-level block are coalesced into one
30
+ * range, so an edit that arrives as several steps in a region shimmers as a single unit. Edits
31
+ * separated by an untouched block stay independent.
32
+ *
33
+ * Correctness: the range math assumes `tr` is a linear 1:1 apply of `steps`. Under the native collab
34
+ * plugin, `receiveTransaction` rebases incoming steps over unconfirmed local steps when they exist;
35
+ * that only invalidates our positions if a local step shifted positions, so we skip solely when a
36
+ * rebased local step changed sizes (a rare, safe degrade). Any unexpected error also degrades to no
37
+ * shimmer, so this never throws into the shared remote-step handler.
38
+ */
39
+ export var getAgentShimmerRanges = function getAgentShimmerRanges(json, steps, tr, view, durationMs, telepointerEnabled) {
40
+ var _json$find;
41
+ if (!expValEquals('platform_editor_agent_be_streaming', 'isEnabled', true)) {
42
+ return [];
43
+ }
44
+ // Nothing to reveal if the shimmer is disabled.
45
+ if (durationMs <= 0) {
46
+ return [];
47
+ }
48
+ // Telepointer label = the agent's type upper-cased (e.g. `mcp` → "MCP"), falling back to a generic
49
+ // "Agent"; `undefined` when the telepointer is disabled, so the plugin skips it. `agentType` is the
50
+ // same on every step of an agent batch, so read it from the first agent-authored step.
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ var agentType = (_json$find = json.find(function (step) {
53
+ return typeof (step === null || step === void 0 ? void 0 : step.agentType) === 'string';
54
+ })) === null || _json$find === void 0 ? void 0 : _json$find.agentType;
55
+ var telepointerLabel = telepointerEnabled ? (agentType === null || agentType === void 0 ? void 0 : agentType.toUpperCase()) || 'Agent' : undefined;
56
+ // When the batch was rebased over local unconfirmed steps, our index-based range math is only
57
+ // valid if those local steps shifted no positions. Attribute-only steps (e.g. `localId`) and
58
+ // same-size replacements are position-neutral, so the shimmer stays correct. Skip only when a
59
+ // local step actually changed sizes (a genuine concurrent content edit).
60
+ if (Number(tr.getMeta('rebased')) > 0) {
61
+ var _getCollabState$uncon, _getCollabState;
62
+ var unconfirmed = (_getCollabState$uncon = (_getCollabState = getCollabState(view.state)) === null || _getCollabState === void 0 ? void 0 : _getCollabState.unconfirmed) !== null && _getCollabState$uncon !== void 0 ? _getCollabState$uncon : [];
63
+ if (unconfirmed.some(function (entry) {
64
+ return !isPositionNeutralStep(entry.step);
65
+ })) {
66
+ return [];
67
+ }
68
+ }
69
+ try {
70
+ // Map an inserted range in doc_{i+1} forward through the remaining steps to final-doc coords.
71
+ // (A later step's own inserted content starts at its `from`; only subsequent steps shift it.)
72
+ var mapToFinalDoc = function mapToFinalDoc(pos, stepIndex, bias) {
73
+ var p = pos;
74
+ for (var j = stepIndex + 1; j < steps.length; j++) {
75
+ p = steps[j].getMap().map(p, bias);
76
+ }
77
+ return p;
78
+ };
79
+
80
+ // Derive each agent step's changed ranges from its StepMap — the canonical, step-type-agnostic
81
+ // source of what a step wrote. We only need the NEW extent (the content now in the document), in
82
+ // final-doc coords, since the highlight decorates content that is already present.
83
+
84
+ var infos = [];
85
+ json.forEach(function (rawStep, index) {
86
+ if (typeof (rawStep === null || rawStep === void 0 ? void 0 : rawStep.agentType) !== 'string') {
87
+ return;
88
+ }
89
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
90
+ var pmStep = steps[index];
91
+ if (typeof (pmStep === null || pmStep === void 0 ? void 0 : pmStep.getMap) !== 'function') {
92
+ return;
93
+ }
94
+ pmStep.getMap().forEach(function (_oldStart, _oldEnd, newStart, newEnd) {
95
+ if (newEnd <= newStart) {
96
+ return; // pure deletion / attribute-only — no new content to highlight
97
+ }
98
+ infos.push({
99
+ from: mapToFinalDoc(newStart, index, -1),
100
+ to: mapToFinalDoc(newEnd, index, 1)
101
+ });
102
+ });
103
+ });
104
+ if (!infos.length) {
105
+ return [];
106
+ }
107
+
108
+ // Group the changed ranges by the TOP-LEVEL block they landed in, then highlight each touched
109
+ // block IN FULL. NCS emits a single agent edit as many small replace fragments and often keeps a
110
+ // common prefix/suffix untouched, so the changed sub-ranges cover only part of a block (e.g. half
111
+ // a rewritten heading). Expanding to the whole block's content makes the entire heading/paragraph
112
+ // shimmer as one unit rather than leaving the unchanged half undecorated. Directly-adjacent
113
+ // touched blocks (index n and n+1) merge into one group so a multi-block rewrite reveals together;
114
+ // a genuinely untouched block in between (index gap > 1) splits the run, so far-apart edits stay
115
+ // independent.
116
+ var docSize = tr.doc.content.size;
117
+ var clampPos = function clampPos(pos) {
118
+ return Math.min(Math.max(pos, 1), docSize);
119
+ };
120
+ var blockIndexAt = function blockIndexAt(pos) {
121
+ return tr.doc.resolve(clampPos(pos)).index(0);
122
+ };
123
+ // Start/end of the content of the top-level block containing `pos`, so the whole block is covered.
124
+ var blockContentStart = function blockContentStart(pos) {
125
+ var $pos = tr.doc.resolve(clampPos(pos));
126
+ return $pos.depth >= 1 ? $pos.start(1) : pos;
127
+ };
128
+ var blockContentEnd = function blockContentEnd(pos) {
129
+ var $pos = tr.doc.resolve(clampPos(pos));
130
+ return $pos.depth >= 1 ? $pos.end(1) : pos;
131
+ };
132
+ var sorted = [].concat(infos).sort(function (a, b) {
133
+ return a.from - b.from || a.to - b.to;
134
+ });
135
+ var groups = [];
136
+ sorted.forEach(function (info) {
137
+ var block = blockIndexAt(info.from);
138
+ var current = groups[groups.length - 1];
139
+ if (current && block <= current.maxBlock + 1) {
140
+ current.to = Math.max(current.to, info.to);
141
+ current.maxBlock = Math.max(current.maxBlock, block);
142
+ } else {
143
+ groups.push({
144
+ from: info.from,
145
+ to: info.to,
146
+ maxBlock: block
147
+ });
148
+ }
149
+ });
150
+ return groups.map(function (group) {
151
+ return {
152
+ shimmerId: "agent-shimmer-".concat(agentShimmerIdCounter++),
153
+ from: blockContentStart(group.from),
154
+ to: blockContentEnd(group.to),
155
+ telepointerLabel: telepointerLabel
156
+ };
157
+ });
158
+ } catch (_unused) {
159
+ // Never let shimmer range derivation throw into the shared remote-step handler; degrade to no
160
+ // shimmer.
161
+ return [];
162
+ }
163
+ };
@@ -7,6 +7,8 @@ import { Selection } from '@atlaskit/editor-prosemirror/state';
7
7
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
8
8
  import { Participants } from '../participants';
9
9
  import { createTelepointers, findPointers, getPositionOfTelepointer, isReplaceStep, hasExistingNudge } from '../utils';
10
+ import { ADD_AGENT_SHIMMER_META, buildAgentShimmerDecorations, reduceAgentShimmers, REMOVE_AGENT_SHIMMER_META } from './agent-shimmer-decorations';
11
+
10
12
  /**
11
13
  * Returns position where it's possible to place a decoration.
12
14
  */
@@ -26,7 +28,10 @@ export var PluginState = /*#__PURE__*/function () {
26
28
  var collabInitalised = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
27
29
  var onError = arguments.length > 4 ? arguments[4] : undefined;
28
30
  var nudgeAnimations = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : new Map();
31
+ var agentShimmers = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : [];
29
32
  _classCallCheck(this, PluginState);
33
+ // Active agent-edit shimmer ranges (pure data). Replaced with a fresh array of fresh
34
+ // objects whenever it changes — never mutated in place.
30
35
  // eslint-disable-next-line no-console
31
36
  _defineProperty(this, "onError", function (error) {
32
37
  return console.error(error);
@@ -37,6 +42,7 @@ export var PluginState = /*#__PURE__*/function () {
37
42
  this.isReady = collabInitalised;
38
43
  this.onError = onError || this.onError;
39
44
  this.nudgeAnimations = nudgeAnimations;
45
+ this.agentShimmers = agentShimmers;
40
46
  }
41
47
  return _createClass(PluginState, [{
42
48
  key: "decorations",
@@ -83,6 +89,8 @@ export var PluginState = /*#__PURE__*/function () {
83
89
  var presenceData = tr.getMeta('presence');
84
90
  var telepointerData = tr.getMeta('telepointer');
85
91
  var nudgeTelepointerData = tr.getMeta('nudgeTelepointer');
92
+ var agentShimmerData = tr.getMeta(ADD_AGENT_SHIMMER_META);
93
+ var removeAgentShimmerId = tr.getMeta(REMOVE_AGENT_SHIMMER_META);
86
94
  var sessionIdData = tr.getMeta('sessionId');
87
95
  var collabInitialised = tr.getMeta('collabInitialised');
88
96
  if (typeof collabInitialised !== 'boolean') {
@@ -170,6 +178,11 @@ export var PluginState = /*#__PURE__*/function () {
170
178
  // Ignored via go/ees005
171
179
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
172
180
  this.decorationSet.find().forEach(function (deco) {
181
+ var _deco$spec;
182
+ // Never let telepointer dim/side logic touch agent-shimmer decorations.
183
+ if ((_deco$spec = deco.spec) !== null && _deco$spec !== void 0 && _deco$spec.isAgentShimmer) {
184
+ return;
185
+ }
173
186
  if (deco.type.toDOM) {
174
187
  var hasTelepointerDimClass = deco.type.toDOM.classList.contains(TELEPOINTER_DIM_CLASS);
175
188
  var browser = getBrowserInfo();
@@ -198,8 +211,12 @@ export var PluginState = /*#__PURE__*/function () {
198
211
  // Ignored via go/ees005
199
212
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
200
213
  this.decorationSet.find().forEach(function (deco) {
201
- var _deco$spec, _deco$spec2;
202
- if (deco.type.toDOM && participants.get(nudgeSessionId) && ((_deco$spec = deco.spec) === null || _deco$spec === void 0 || (_deco$spec = _deco$spec.pointer) === null || _deco$spec === void 0 ? void 0 : _deco$spec.sessionId) === nudgeSessionId && ((_deco$spec2 = deco.spec) === null || _deco$spec2 === void 0 ? void 0 : _deco$spec2.key) === "telepointer-".concat(nudgeSessionId)) {
214
+ var _deco$spec2, _deco$spec3, _deco$spec4;
215
+ // Never let telepointer nudge logic touch agent-shimmer decorations.
216
+ if ((_deco$spec2 = deco.spec) !== null && _deco$spec2 !== void 0 && _deco$spec2.isAgentShimmer) {
217
+ return;
218
+ }
219
+ if (deco.type.toDOM && participants.get(nudgeSessionId) && ((_deco$spec3 = deco.spec) === null || _deco$spec3 === void 0 || (_deco$spec3 = _deco$spec3.pointer) === null || _deco$spec3 === void 0 ? void 0 : _deco$spec3.sessionId) === nudgeSessionId && ((_deco$spec4 = deco.spec) === null || _deco$spec4 === void 0 ? void 0 : _deco$spec4.key) === "telepointer-".concat(nudgeSessionId)) {
203
220
  // Restart animation by removing and re-adding the class
204
221
  deco.type.toDOM.classList.remove(TELEPOINTER_PULSE_DURING_TR_CLASS);
205
222
  deco.type.toDOM.classList.remove(TELEPOINTER_PULSE_CLASS);
@@ -209,6 +226,41 @@ export var PluginState = /*#__PURE__*/function () {
209
226
  }
210
227
  });
211
228
  }
229
+
230
+ // Register / keep-aligned / remove the agent-edit purple highlight
231
+ // decorations. Fully fault-isolated — it works on local copies and only merges into the shared
232
+ // `add`/`remove` (and commits `this.agentShimmers`) after the whole block succeeds, so a fault
233
+ // here can never corrupt telepointer decorations or the shared decoration set. Never mutates
234
+ // shimmer entries in place: each change produces a fresh array of fresh objects.
235
+ try {
236
+ var _reduceAgentShimmers = reduceAgentShimmers(this.agentShimmers, tr, agentShimmerData, removeAgentShimmerId),
237
+ changed = _reduceAgentShimmers.changed,
238
+ next = _reduceAgentShimmers.next;
239
+ if (changed) {
240
+ // Build into local arrays; only merge into the shared add/remove once the block succeeds.
241
+ var agentRemove = this.decorationSet.find(undefined, undefined, function (spec) {
242
+ return spec.isAgentShimmer;
243
+ });
244
+ var agentAdd = buildAgentShimmerDecorations(tr, next, getValidPos, this.onError);
245
+
246
+ // Commit only after the whole block succeeded.
247
+ remove = remove.concat(agentRemove);
248
+ add = add.concat(agentAdd);
249
+ this.agentShimmers = next;
250
+ }
251
+ } catch (err) {
252
+ this.onError(err);
253
+ // Degrade to no shimmer without corrupting telepointer decorations: drop all agent
254
+ // decorations and clear agent state, leaving the telepointer `add`/`remove` untouched.
255
+ this.agentShimmers = [];
256
+ try {
257
+ remove = remove.concat(this.decorationSet.find(undefined, undefined, function (spec) {
258
+ return spec.isAgentShimmer;
259
+ }));
260
+ } catch (_unused) {
261
+ // Teardown must not re-throw.
262
+ }
263
+ }
212
264
  if (remove.length) {
213
265
  this.decorationSet = this.decorationSet.remove(remove);
214
266
  }
@@ -227,7 +279,7 @@ export var PluginState = /*#__PURE__*/function () {
227
279
  }
228
280
  }
229
281
  }
230
- var nextState = new PluginState(this.decorationSet, participants, sid, collabInitialised, this.onError, this.nudgeAnimations);
282
+ var nextState = new PluginState(this.decorationSet, participants, sid, collabInitialised, this.onError, this.nudgeAnimations, this.agentShimmers);
231
283
  return PluginState.eq(nextState, this) ? this : nextState;
232
284
  }
233
285
  }], [{
@@ -10,8 +10,12 @@ import { Decoration } from '@atlaskit/editor-prosemirror/view';
10
10
  import { getParticipantColor } from '@atlaskit/editor-shared-styles';
11
11
  import { preserveNodeIdentity } from './preserve-node-identity';
12
12
  export var findPointers = function findPointers(id, decorations) {
13
- return decorations.find().reduce(function (arr, deco) {
14
- return deco.spec.pointer.presenceId === id ? arr.concat(deco) : arr;
13
+ return decorations.find().reduce(
14
+ // `pointer` is absent on non-telepointer decorations (e.g. the agent-shimmer
15
+ // sweep decorations), so guard against it to avoid crashing this shared helper.
16
+ function (arr, deco) {
17
+ var _deco$spec$pointer;
18
+ return ((_deco$spec$pointer = deco.spec.pointer) === null || _deco$spec$pointer === void 0 ? void 0 : _deco$spec$pointer.presenceId) === id ? arr.concat(deco) : arr;
15
19
  }, []);
16
20
  };
17
21
  function style(options) {
@@ -0,0 +1,31 @@
1
+ import type { ReadonlyTransaction } from '@atlaskit/editor-prosemirror/state';
2
+ import { Decoration } from '@atlaskit/editor-prosemirror/view';
3
+ /** Default time the skeleton shimmer stays on the agent-authored content (ms). */
4
+ export declare const AGENT_SHIMMER_DEFAULT_DURATION_MS = 3000;
5
+ export declare const AGENT_SHIMMER_CLASS = "collab-agent-shimmer";
6
+ export declare const ROVO_AGENT_TELEPOINTER_CLASS = "ai-in-editor-telepointer";
7
+ export declare const ROVO_AGENT_TELEPOINTER_LABEL_CLASS = "ai-in-editor-telepointer-label";
8
+ export declare const ADD_AGENT_SHIMMER_META = "addAgentShimmer";
9
+ export declare const REMOVE_AGENT_SHIMMER_META = "removeAgentShimmer";
10
+ export type AgentShimmerRange = {
11
+ from: number;
12
+ shimmerId: string;
13
+ telepointerLabel?: string;
14
+ to: number;
15
+ };
16
+ /**
17
+ * Pure reducer for the active shimmer ranges from a transaction's changes. Maps existing ranges
18
+ * forward as the doc changes, replaces them wholesale when a new agent batch lands (a new batch
19
+ * supersedes any still-in-flight shimmer), and drops a range when its removal timer fires. Returns a
20
+ * fresh array (never mutates in place) plus whether anything changed.
21
+ */
22
+ export declare const reduceAgentShimmers: (current: AgentShimmerRange[], tr: ReadonlyTransaction, added: AgentShimmerRange[] | undefined, removedShimmerId: string | undefined) => {
23
+ changed: boolean;
24
+ next: AgentShimmerRange[];
25
+ };
26
+ /**
27
+ * Builds the inline skeleton-bar + trailing telepointer decorations for the active shimmer ranges.
28
+ * `getValidPos` clamps a raw position to a valid decoration position (owned by `plugin-state`).
29
+ * One bad range is isolated via `onError` so it can't kill the others.
30
+ */
31
+ export declare const buildAgentShimmerDecorations: (tr: ReadonlyTransaction, shimmers: AgentShimmerRange[], getValidPos: (tr: ReadonlyTransaction, pos: number) => number, onError: (err: Error) => void) => Decoration[];
@@ -0,0 +1,22 @@
1
+ import type { Transaction } from '@atlaskit/editor-prosemirror/state';
2
+ import type { Step } from '@atlaskit/editor-prosemirror/transform';
3
+ import type { EditorView } from '@atlaskit/editor-prosemirror/view';
4
+ import type { AgentShimmerRange } from './agent-shimmer-decorations';
5
+ export declare const isPositionNeutralStep: (step: Step) => boolean;
6
+ /**
7
+ * Derive the shimmer ranges for the agent-authored steps in a received batch, in final-doc
8
+ * coordinates. `agentType` present ⇒ agent-authored (per the NCS↔Editor steps contract). Each
9
+ * emitted range is expanded to the whole top-level block(s) the agent touched, which the plugin
10
+ * covers with the skeleton shimmer. Ranges with no new content (pure deletions) are dropped.
11
+ *
12
+ * Steps whose new content is in the same or directly-adjacent top-level block are coalesced into one
13
+ * range, so an edit that arrives as several steps in a region shimmers as a single unit. Edits
14
+ * separated by an untouched block stay independent.
15
+ *
16
+ * Correctness: the range math assumes `tr` is a linear 1:1 apply of `steps`. Under the native collab
17
+ * plugin, `receiveTransaction` rebases incoming steps over unconfirmed local steps when they exist;
18
+ * that only invalidates our positions if a local step shifted positions, so we skip solely when a
19
+ * rebased local step changed sizes (a rare, safe degrade). Any unexpected error also degrades to no
20
+ * shimmer, so this never throws into the shared remote-step handler.
21
+ */
22
+ export declare const getAgentShimmerRanges: (json: any[], steps: Step[], tr: Transaction, view: EditorView, durationMs: number, telepointerEnabled: boolean) => AgentShimmerRange[];
@@ -3,6 +3,7 @@ import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
3
3
  import type { ReadOnlyParticipants } from '../../types';
4
4
  import { Participants } from '../participants';
5
5
  import type { NudgeAnimationsMap } from '../utils';
6
+ import { type AgentShimmerRange } from './agent-shimmer-decorations';
6
7
  /**
7
8
  * Returns position where it's possible to place a decoration.
8
9
  */
@@ -11,13 +12,14 @@ export declare class PluginState {
11
12
  private decorationSet;
12
13
  private participants;
13
14
  private nudgeAnimations;
15
+ private agentShimmers;
14
16
  private onError;
15
17
  private sid?;
16
18
  isReady: boolean;
17
19
  get decorations(): DecorationSet;
18
20
  get activeParticipants(): ReadOnlyParticipants;
19
21
  get sessionId(): string | undefined;
20
- constructor(decorations: DecorationSet, participants: Participants, sessionId?: string, collabInitalised?: boolean, onError?: (err: Error) => void, nudgeAnimations?: NudgeAnimationsMap);
22
+ constructor(decorations: DecorationSet, participants: Participants, sessionId?: string, collabInitalised?: boolean, onError?: (err: Error) => void, nudgeAnimations?: NudgeAnimationsMap, agentShimmers?: AgentShimmerRange[]);
21
23
  getFullName(sessionId: string): string;
22
24
  getInitial(sessionId: string): string;
23
25
  getPresenceId(sessionId: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-collab-edit",
3
- "version": "13.0.30",
3
+ "version": "13.1.0",
4
4
  "description": "Collab Edit plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -31,13 +31,13 @@
31
31
  "@atlaskit/frontend-utilities": "^4.1.0",
32
32
  "@atlaskit/platform-feature-flags": "^2.1.0",
33
33
  "@atlaskit/prosemirror-collab": "^1.0.0",
34
- "@atlaskit/tmp-editor-statsig": "^132.0.0",
35
- "@atlaskit/tokens": "^16.2.0",
34
+ "@atlaskit/tmp-editor-statsig": "^132.3.0",
35
+ "@atlaskit/tokens": "^16.3.0",
36
36
  "@babel/runtime": "^7.0.0",
37
37
  "memoize-one": "^6.0.0"
38
38
  },
39
39
  "peerDependencies": {
40
- "@atlaskit/editor-common": "^116.35.0",
40
+ "@atlaskit/editor-common": "^116.36.0",
41
41
  "react": "^18.2.0",
42
42
  "react-dom": "^18.2.0"
43
43
  },
@@ -86,6 +86,9 @@
86
86
  "platform-feature-flags": {
87
87
  "platform_editor_collab_organic_change_reporting": {
88
88
  "type": "boolean"
89
+ },
90
+ "platform_editor_agent_be_streaming": {
91
+ "type": "experiment"
89
92
  }
90
93
  }
91
94
  }