@atlaskit/editor-plugin-autocomplete 8.0.0 → 9.0.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.
Files changed (79) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/dist/cjs/analytics/ufo.js +2 -1
  3. package/dist/cjs/pm-plugins/artifact-loader.js +135 -0
  4. package/dist/cjs/pm-plugins/artifacts-manifest.js +3 -0
  5. package/dist/cjs/pm-plugins/autocomplete-plugin.js +416 -129
  6. package/dist/cjs/pm-plugins/canonical-lm-scoring.js +371 -0
  7. package/dist/cjs/pm-plugins/debug-mode.js +90 -7
  8. package/dist/cjs/pm-plugins/ghost-text-decoration.js +12 -3
  9. package/dist/cjs/pm-plugins/local-slow-lane-client.js +1202 -453
  10. package/dist/cjs/pm-plugins/scoring-pipeline.js +164 -19
  11. package/dist/cjs/pm-plugins/slow-lane-client.js +100 -37
  12. package/dist/cjs/pm-plugins/text-predictor.js +1951 -273
  13. package/dist/es2019/analytics/ufo.js +2 -0
  14. package/dist/es2019/pm-plugins/artifact-loader.js +70 -0
  15. package/dist/es2019/pm-plugins/artifacts-manifest.js +3 -0
  16. package/dist/es2019/pm-plugins/autocomplete-plugin.js +425 -130
  17. package/dist/es2019/pm-plugins/canonical-lm-scoring.js +270 -0
  18. package/dist/es2019/pm-plugins/debug-mode.js +87 -7
  19. package/dist/es2019/pm-plugins/ghost-text-decoration.js +12 -3
  20. package/dist/es2019/pm-plugins/local-slow-lane-client.js +940 -326
  21. package/dist/es2019/pm-plugins/scoring-pipeline.js +137 -13
  22. package/dist/es2019/pm-plugins/slow-lane-client.js +94 -37
  23. package/dist/es2019/pm-plugins/text-predictor.js +1603 -199
  24. package/dist/esm/analytics/ufo.js +2 -1
  25. package/dist/esm/pm-plugins/artifact-loader.js +128 -0
  26. package/dist/esm/pm-plugins/artifacts-manifest.js +3 -0
  27. package/dist/esm/pm-plugins/autocomplete-plugin.js +419 -132
  28. package/dist/esm/pm-plugins/canonical-lm-scoring.js +364 -0
  29. package/dist/esm/pm-plugins/debug-mode.js +89 -6
  30. package/dist/esm/pm-plugins/ghost-text-decoration.js +12 -3
  31. package/dist/esm/pm-plugins/local-slow-lane-client.js +1200 -451
  32. package/dist/esm/pm-plugins/scoring-pipeline.js +163 -18
  33. package/dist/esm/pm-plugins/slow-lane-client.js +100 -37
  34. package/dist/esm/pm-plugins/text-predictor.js +1953 -277
  35. package/dist/types/analytics/ufo.d.ts +1 -0
  36. package/dist/types/pm-plugins/artifact-loader.d.ts +44 -0
  37. package/dist/types/pm-plugins/artifacts-manifest.d.ts +3 -0
  38. package/dist/types/pm-plugins/autocomplete-plugin.d.ts +39 -0
  39. package/dist/types/pm-plugins/canonical-lm-scoring.d.ts +158 -0
  40. package/dist/types/pm-plugins/debug-mode.d.ts +36 -1
  41. package/dist/types/pm-plugins/ghost-text-decoration.d.ts +5 -2
  42. package/dist/types/pm-plugins/local-slow-lane-client.d.ts +87 -54
  43. package/dist/types/pm-plugins/scoring-pipeline.d.ts +33 -1
  44. package/dist/types/pm-plugins/slow-lane-client.d.ts +51 -3
  45. package/dist/types/pm-plugins/text-predictor.d.ts +120 -2
  46. package/package.json +2 -2
  47. package/src/analytics/ufo.ts +5 -0
  48. package/src/pm-plugins/artifact-loader.ts +92 -0
  49. package/src/pm-plugins/artifacts-manifest.ts +3 -0
  50. package/src/pm-plugins/autocomplete-plugin.ts +517 -133
  51. package/src/pm-plugins/canonical-lm-scoring.ts +412 -0
  52. package/src/pm-plugins/debug-mode.ts +109 -7
  53. package/src/pm-plugins/ghost-text-decoration.ts +13 -4
  54. package/src/pm-plugins/local-slow-lane-client.ts +1302 -386
  55. package/src/pm-plugins/scoring-pipeline.ts +167 -17
  56. package/src/pm-plugins/slow-lane-client.ts +147 -62
  57. package/src/pm-plugins/text-predictor.ts +2006 -255
  58. package/CANONICAL_FIX__DO_NOT_USE_ME_A/package.json +0 -8
  59. package/CANONICAL_FIX__DO_NOT_USE_ME_B/package.json +0 -8
  60. package/CANONICAL_FIX__DO_NOT_USE_ME_C/package.json +0 -8
  61. package/dist/cjs/entry-points/src-pm-plugins-autocomplete-plugin.js +0 -18
  62. package/dist/cjs/entry-points/src-pm-plugins-slow-lane-client.js +0 -36
  63. package/dist/cjs/entry-points/src-pm-plugins-text-predictor.js +0 -66
  64. package/dist/es2019/entry-points/src-pm-plugins-autocomplete-plugin.js +0 -2
  65. package/dist/es2019/entry-points/src-pm-plugins-slow-lane-client.js +0 -2
  66. package/dist/es2019/entry-points/src-pm-plugins-text-predictor.js +0 -2
  67. package/dist/esm/entry-points/src-pm-plugins-autocomplete-plugin.js +0 -2
  68. package/dist/esm/entry-points/src-pm-plugins-slow-lane-client.js +0 -2
  69. package/dist/esm/entry-points/src-pm-plugins-text-predictor.js +0 -2
  70. package/dist/types/entry-points/src-pm-plugins-autocomplete-plugin.d.ts +0 -2
  71. package/dist/types/entry-points/src-pm-plugins-slow-lane-client.d.ts +0 -2
  72. package/dist/types/entry-points/src-pm-plugins-text-predictor.d.ts +0 -2
  73. package/scripts/gen_first_token_to_words.py +0 -170
  74. package/src/entry-points/src-pm-plugins-autocomplete-plugin.ts +0 -7
  75. package/src/entry-points/src-pm-plugins-slow-lane-client.ts +0 -13
  76. package/src/entry-points/src-pm-plugins-text-predictor.ts +0 -14
  77. package/src/pm-plugins/autocomplete-plugin/package.json +0 -8
  78. package/src/pm-plugins/slow-lane-client/package.json +0 -8
  79. package/src/pm-plugins/text-predictor/package.json +0 -8
@@ -5,8 +5,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.createAutocompletePlugin = exports.autocompletePluginKey = void 0;
8
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
8
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
10
  var _analytics = require("@atlaskit/editor-common/analytics");
11
11
  var _monitoring = require("@atlaskit/editor-common/monitoring");
12
12
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
@@ -25,7 +25,8 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
25
25
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
26
26
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
27
27
  var autocompletePluginKey = exports.autocompletePluginKey = new _state.PluginKey('autocomplete');
28
- var DEBOUNCE_MS = 150;
28
+ var PREDICTION_COALESCE_MS = 0;
29
+ var GHOST_DECISION_BUDGET_MS = 100;
29
30
  var NETWORK_SLOW_LANE_DEBOUNCE_MS = 300;
30
31
  var LOCAL_SLOW_LANE_DEBOUNCE_MS = 100;
31
32
  var CONTEXT_REFRESH_THROTTLE_MS = 1000;
@@ -40,11 +41,11 @@ var MAX_INGESTED_CONTEXT_TEXTS = 50;
40
41
  // on every word boundary for the plugin's lifetime.
41
42
  var MAX_CONTEXT_REFRESH_ATTEMPTS = 5;
42
43
  var INLINE_LEAF_TEXT = ' ';
44
+ var slowLaneClientInstanceSequence = 0;
43
45
 
44
- // eslint-disable-next-line require-unicode-regexp
45
- var TRAILING_NON_BOUNDARY_TOKEN_REGEX = /([^\s.,;:!?]*)$/;
46
46
  // eslint-disable-next-line require-unicode-regexp
47
47
  var WORD_BOUNDARY_CHARS_REGEX = /[\s.,;:!?]/;
48
+ var TRAILING_SURFACE_PREFIX_REGEX = /(?:['\x2D0-9A-Z_a-z\xAA\xB2\xB3\xB5\xB9\xBA\xBC-\xBE\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u0660-\u0669\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u0870-\u0887\u0889-\u088F\u08A0-\u08C9\u0904-\u0939\u093D\u0950\u0958-\u0961\u0966-\u096F\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09F9\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AE6-\u0AEF\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0BE6-\u0BF2\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C5C\u0C5D\u0C60\u0C61\u0C66-\u0C6F\u0C78-\u0C7E\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDC-\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D58-\u0D61\u0D66-\u0D78\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DE6-\u0DEF\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F20-\u0F33\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F-\u1049\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1090-\u1099\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1369-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u1711\u171F-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A20-\u1A54\u1A80-\u1A89\u1A90-\u1A99\u1AA7\u1B05-\u1B33\u1B45-\u1B4C\u1B50-\u1B59\u1B83-\u1BA0\u1BAE-\u1BE5\u1C00-\u1C23\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C8A\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2C00-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2CFD\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3192-\u3195\u31A0-\u31BF\u31F0-\u31FF\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u3400-\u4DBF\u4E00-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7DC\uA7F1-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA830-\uA835\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uA9E0-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDE80-\uDE9C\uDEA0-\uDED0\uDEE1-\uDEFB\uDF00-\uDF23\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDD70-\uDD7A\uDD7C-\uDD8A\uDD8C-\uDD92\uDD94\uDD95\uDD97-\uDDA1\uDDA3-\uDDB1\uDDB3-\uDDB9\uDDBB\uDDBC\uDDC0-\uDDF3\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC58-\uDC76\uDC79-\uDC9E\uDCA7-\uDCAF\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDD1B\uDD20-\uDD39\uDD40-\uDD59\uDD80-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE40-\uDE48\uDE60-\uDE7E\uDE80-\uDE9F\uDEC0-\uDEC7\uDEC9-\uDEE4\uDEEB-\uDEEF\uDF00-\uDF35\uDF40-\uDF55\uDF58-\uDF72\uDF78-\uDF91\uDFA9-\uDFAF]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDD23\uDD30-\uDD39\uDD40-\uDD65\uDD6F-\uDD85\uDE60-\uDE7E\uDE80-\uDEA9\uDEB0\uDEB1\uDEC2-\uDEC7\uDF00-\uDF27\uDF30-\uDF45\uDF51-\uDF54\uDF70-\uDF81\uDFB0-\uDFCB\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC52-\uDC6F\uDC71\uDC72\uDC75\uDC83-\uDCAF\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD03-\uDD26\uDD36-\uDD3F\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDD0-\uDDDA\uDDDC\uDDE1-\uDDF4\uDE00-\uDE11\uDE13-\uDE2B\uDE3F\uDE40\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDEF0-\uDEF9\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61\uDF80-\uDF89\uDF8B\uDF8E\uDF90-\uDFB5\uDFB7\uDFD1\uDFD3]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC50-\uDC59\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE50-\uDE59\uDE80-\uDEAA\uDEB8\uDEC0-\uDEC9\uDED0-\uDEE3\uDF00-\uDF1A\uDF30-\uDF3B\uDF40-\uDF46]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCF2\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDD50-\uDD59\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEB0-\uDEF8\uDFC0-\uDFE0\uDFF0-\uDFF9]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC50-\uDC6C\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDDA0-\uDDA9\uDDB0-\uDDDB\uDDE0-\uDDE9\uDEE0-\uDEF2\uDF02\uDF04-\uDF10\uDF12-\uDF33\uDF50-\uDF59\uDFB0\uDFC0-\uDFD4]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|\uD80B[\uDF90-\uDFF0]|[\uD80C\uD80E\uD80F\uD81C-\uD822\uD840-\uD868\uD86A-\uD86D\uD86F-\uD872\uD874-\uD879\uD880-\uD883\uD885-\uD88C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2F\uDC41-\uDC46\uDC60-\uDFFF]|\uD810[\uDC00-\uDFFA]|\uD811[\uDC00-\uDE46]|\uD818[\uDD00-\uDD1D\uDD30-\uDD39]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDE70-\uDEBE\uDEC0-\uDEC9\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDD40-\uDD6C\uDD70-\uDD79\uDE40-\uDE96\uDEA0-\uDEB8\uDEBB-\uDED3\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3\uDFF2-\uDFF6]|\uD823[\uDC00-\uDCD5\uDCFF-\uDD1E\uDD80-\uDDF2]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD82C[\uDC00-\uDD22\uDD32\uDD50-\uDD52\uDD55\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD833[\uDCF0-\uDCF9]|\uD834[\uDEC0-\uDED3\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD837[\uDF00-\uDF1E\uDF25-\uDF2A]|\uD838[\uDC30-\uDC6D\uDD00-\uDD2C\uDD37-\uDD3D\uDD40-\uDD49\uDD4E\uDE90-\uDEAD\uDEC0-\uDEEB\uDEF0-\uDEF9]|\uD839[\uDCD0-\uDCEB\uDCF0-\uDCF9\uDDD0-\uDDED\uDDF0-\uDDFA\uDEC0-\uDEDE\uDEE0-\uDEE2\uDEE4\uDEE5\uDEE7-\uDEED\uDEF0-\uDEF4\uDEFE\uDEFF\uDFE0-\uDFE6\uDFE8-\uDFEB\uDFED\uDFEE\uDFF0-\uDFFE]|\uD83A[\uDC00-\uDCC4\uDCC7-\uDCCF\uDD00-\uDD43\uDD4B\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDD01-\uDD2D\uDD2F-\uDD3D\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD00-\uDD0C]|\uD83E[\uDFF0-\uDFF9]|\uD869[\uDC00-\uDEDF\uDF00-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEAD\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0\uDFF0-\uDFFF]|\uD87B[\uDC00-\uDE5D]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A\uDF50-\uDFFF]|\uD88D[\uDC00-\uDC79])+$/;
48
49
  var hasDestroy = function hasDestroy(client) {
49
50
  return 'destroy' in client && typeof client.destroy === 'function';
50
51
  };
@@ -52,9 +53,70 @@ var createInitialState = function createInitialState() {
52
53
  return {
53
54
  ghostText: '',
54
55
  ghostPosition: -1,
55
- decorationSet: _view.DecorationSet.empty
56
+ decorationSet: _view.DecorationSet.empty,
57
+ suggestion: null
56
58
  };
57
59
  };
60
+ var clearGhostState = function clearGhostState(pluginState) {
61
+ return _objectSpread(_objectSpread({}, pluginState), {}, {
62
+ ghostText: '',
63
+ ghostPosition: -1,
64
+ decorationSet: _view.DecorationSet.empty,
65
+ suggestion: null
66
+ });
67
+ };
68
+
69
+ /**
70
+ * Keep a displayed ghost alive when the user types the character it already
71
+ * predicted.
72
+ *
73
+ * Clearing on every document change throws away a suggestion the keystroke just
74
+ * confirmed, and the replacement decision has to re-earn it from an empty state
75
+ * inside the budget — which it often misses, so the ghost blinks out mid-word.
76
+ * It is worse for multi-word surfaces: typing the space in `machine learning`
77
+ * empties the current word, and the display gate refuses to show anything again
78
+ * until three characters of `learning` exist.
79
+ *
80
+ * A confirming keystroke is not new information about the prediction, so the
81
+ * ghost simply advances by one character and the still-running decision is free
82
+ * to replace it with something better. Anything else — a different character,
83
+ * a paste, a deletion, an edit elsewhere — clears as before.
84
+ */
85
+ var advanceGhostThroughTypedCharacter = function advanceGhostThroughTypedCharacter(tr, pluginState) {
86
+ var ghostPosition = pluginState.ghostPosition,
87
+ ghostText = pluginState.ghostText,
88
+ suggestion = pluginState.suggestion;
89
+ if (ghostText.length < 2 || ghostPosition < 0 || !suggestion) {
90
+ // A one-character tail leaves nothing to show after advancing.
91
+ return null;
92
+ }
93
+
94
+ // Exactly one character longer, with the cursor sitting just past the ghost
95
+ // anchor: together these identify a single insertion made at the anchor
96
+ // rather than a paste or an edit elsewhere in the document.
97
+ if (tr.doc.content.size - tr.before.content.size !== 1) {
98
+ return null;
99
+ }
100
+ if (!tr.selection.empty || tr.selection.from !== ghostPosition + 1) {
101
+ return null;
102
+ }
103
+ if (tr.doc.textBetween(ghostPosition, ghostPosition + 1) !== ghostText[0]) {
104
+ return null;
105
+ }
106
+ var remaining = ghostText.slice(1);
107
+ var nextPosition = ghostPosition + 1;
108
+ return _objectSpread(_objectSpread({}, pluginState), {}, {
109
+ ghostText: remaining,
110
+ ghostPosition: nextPosition,
111
+ decorationSet: (0, _ghostTextDecoration.createGhostTextDecorationSet)(tr.doc, nextPosition, remaining),
112
+ // `surface` stays the full candidate so cooldown and analytics still
113
+ // describe the suggestion that was originally committed.
114
+ suggestion: _objectSpread(_objectSpread({}, suggestion), {}, {
115
+ ghostText: remaining,
116
+ position: nextPosition
117
+ })
118
+ });
119
+ };
58
120
 
59
121
  /**
60
122
  * Extract text content before the cursor from the current document.
@@ -86,6 +148,10 @@ var getTextBeforeCursor = function getTextBeforeCursor(state) {
86
148
  }
87
149
  return fullText.slice(-maxChars);
88
150
  };
151
+ var getTrailingSurfacePrefixLength = function getTrailingSurfacePrefixLength(text) {
152
+ var _text$trimEnd$match$, _text$trimEnd$match;
153
+ return (_text$trimEnd$match$ = (_text$trimEnd$match = text.trimEnd().match(TRAILING_SURFACE_PREFIX_REGEX)) === null || _text$trimEnd$match === void 0 ? void 0 : _text$trimEnd$match[0].length) !== null && _text$trimEnd$match$ !== void 0 ? _text$trimEnd$match$ : 0;
154
+ };
89
155
 
90
156
  /**
91
157
  * Set the autocomplete state via a transaction metadata.
@@ -98,21 +164,39 @@ var setAutocompleteMeta = function setAutocompleteMeta(tr, meta) {
98
164
  * Apply a ghost text suggestion to the editor state.
99
165
  */
100
166
  var lastShownGhostText = '';
101
- var showGhostText = function showGhostText(view, text, position) {
167
+ var showGhostText = function showGhostText(view, prediction, position, revision, decisionStartedAt) {
102
168
  try {
103
169
  var state = view.state,
104
170
  dispatch = view.dispatch;
105
- var decorationSet = (0, _ghostTextDecoration.createGhostTextDecorationSet)(state, position, text);
171
+ var suggestion = {
172
+ decisionLatencyMs: performance.now() - decisionStartedAt,
173
+ evidenceTier: prediction.evidenceTier,
174
+ ghostText: prediction.text,
175
+ meanTokenLogProbability: prediction.meanTokenLogProbability,
176
+ poolHeldExtension: prediction.poolHeldExtension,
177
+ position: position,
178
+ posterior: prediction.posterior,
179
+ rankScore: prediction.rankScore,
180
+ revision: revision,
181
+ shortlistSize: prediction.shortlistSize,
182
+ surface: prediction.surface,
183
+ termType: prediction.termType,
184
+ winnerMargin: prediction.winnerMargin
185
+ };
186
+ var decorationSet = (0, _ghostTextDecoration.createGhostTextDecorationSet)(state.doc, position, prediction.text);
106
187
  var tr = setAutocompleteMeta(state.tr, {
107
- ghostText: text,
188
+ ghostText: prediction.text,
108
189
  ghostPosition: position,
109
- decorationSet: decorationSet
190
+ decorationSet: decorationSet,
191
+ suggestion: suggestion
110
192
  });
111
193
  dispatch(tr);
194
+ return suggestion;
112
195
  } catch (error) {
113
196
  (0, _monitoring.logException)(error, {
114
197
  location: 'editor-plugin-autocomplete/showGhostText'
115
198
  });
199
+ return null;
116
200
  }
117
201
  };
118
202
 
@@ -129,7 +213,8 @@ var clearGhostText = function clearGhostText(state, dispatch) {
129
213
  var tr = setAutocompleteMeta(state.tr, {
130
214
  ghostText: '',
131
215
  ghostPosition: -1,
132
- decorationSet: _view.DecorationSet.empty
216
+ decorationSet: _view.DecorationSet.empty,
217
+ suggestion: null
133
218
  });
134
219
  dispatch(tr);
135
220
  } catch (error) {
@@ -147,38 +232,41 @@ var clearGhostText = function clearGhostText(state, dispatch) {
147
232
  */
148
233
  var acceptGhostText = function acceptGhostText(state, dispatch) {
149
234
  var pluginState = autocompletePluginKey.getState(state);
150
- if (!pluginState || !pluginState.ghostText) {
151
- return false;
235
+ if (!(pluginState !== null && pluginState !== void 0 && pluginState.suggestion) || !pluginState.ghostText) {
236
+ return null;
152
237
  }
153
238
  if (dispatch) {
154
239
  try {
155
240
  var ghostText = pluginState.ghostText,
156
- ghostPosition = pluginState.ghostPosition;
241
+ ghostPosition = pluginState.ghostPosition,
242
+ suggestion = pluginState.suggestion;
157
243
  var tr = state.tr.insertText(ghostText, ghostPosition);
158
244
  tr = setAutocompleteMeta(tr, {
159
245
  ghostText: '',
160
246
  ghostPosition: -1,
161
- decorationSet: _view.DecorationSet.empty
247
+ decorationSet: _view.DecorationSet.empty,
248
+ suggestion: null
162
249
  });
163
250
  dispatch(tr);
251
+ return suggestion;
164
252
  } catch (error) {
165
253
  (0, _monitoring.logException)(error, {
166
254
  location: 'editor-plugin-autocomplete/acceptGhostText'
167
255
  });
168
- return false;
256
+ return null;
169
257
  }
170
258
  }
171
- return true;
259
+ return pluginState.suggestion;
172
260
  };
173
261
  var acceptGhostTextWithAnalytics = function acceptGhostTextWithAnalytics(state, dispatch, onAccepted) {
174
- var _pluginState$ghostTex;
175
- var pluginState = autocompletePluginKey.getState(state);
176
- var ghostText = (_pluginState$ghostTex = pluginState === null || pluginState === void 0 ? void 0 : pluginState.ghostText) !== null && _pluginState$ghostTex !== void 0 ? _pluginState$ghostTex : '';
177
- var accepted = acceptGhostText(state, dispatch);
178
- if (accepted) {
179
- onAccepted(ghostText);
262
+ var acceptedSuggestion = acceptGhostText(state, dispatch);
263
+ if (acceptedSuggestion) {
264
+ // Start the post-accept cooldown so the just-accepted unit isn't immediately
265
+ // re-offered (QI-2 echo, e.g. `end to end` → `end to end to end`).
266
+ (0, _textPredictor.noteSuggestionAccepted)(acceptedSuggestion.surface);
267
+ onAccepted(acceptedSuggestion);
180
268
  }
181
- return accepted;
269
+ return acceptedSuggestion !== null;
182
270
  };
183
271
 
184
272
  /**
@@ -240,14 +328,6 @@ var getLeadingTextCharacter = function getLeadingTextCharacter(text) {
240
328
  }
241
329
  return String.fromCodePoint(firstCodePoint);
242
330
  };
243
- var getTypedLengthForPrediction = function getTypedLengthForPrediction(textBefore) {
244
- var _textBefore$match$, _textBefore$match;
245
- if ((0, _slowLaneClient.isWordBoundary)(textBefore)) {
246
- return 0;
247
- }
248
- var trailingToken = (_textBefore$match$ = (_textBefore$match = textBefore.match(TRAILING_NON_BOUNDARY_TOKEN_REGEX)) === null || _textBefore$match === void 0 ? void 0 : _textBefore$match[1]) !== null && _textBefore$match$ !== void 0 ? _textBefore$match$ : '';
249
- return trailingToken.length;
250
- };
251
331
  var isEnglishLocale = function isEnglishLocale(locale) {
252
332
  if (!locale) {
253
333
  return false;
@@ -255,11 +335,12 @@ var isEnglishLocale = function isEnglishLocale(locale) {
255
335
  return locale.toLowerCase().startsWith('en');
256
336
  };
257
337
  var createAutocompletePlugin = exports.createAutocompletePlugin = function createAutocompletePlugin(options, api) {
258
- var _options$surface, _options$locale;
338
+ var _options$surface, _options$locale, _registeredSlowLaneSt;
259
339
  var surface = (_options$surface = options === null || options === void 0 ? void 0 : options.surface) !== null && _options$surface !== void 0 ? _options$surface : 'editor';
260
340
  var locale = (_options$locale = options === null || options === void 0 ? void 0 : options.locale) !== null && _options$locale !== void 0 ? _options$locale : typeof navigator !== 'undefined' ? navigator.language : undefined;
261
341
  var isAutocompleteEnabled = isEnglishLocale(locale);
262
342
  var debounceTimer = null;
343
+ var decisionDeadlineTimer = null;
263
344
  var hasIngestedPage = false;
264
345
  var resolvedContext;
265
346
  /**
@@ -269,6 +350,10 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
269
350
  */
270
351
  var currentView = null;
271
352
  var unsubscribeFromContextUpdates;
353
+ // "Prime, don't ask-and-read": semantic, Tier-A, and Tier-B results land
354
+ // asynchronously, often with no following keystroke. Re-run prediction when
355
+ // they arrive so the caches are consumed immediately.
356
+ var reschedulePredictionOnSlowLaneResult = null;
272
357
  /**
273
358
  * Set after accepting a suggestion so the next doc-change update
274
359
  * skips scheduling a new prediction for the just-inserted text.
@@ -282,8 +367,8 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
282
367
  * re-showing the same suggestion. Resets to null as soon as the text changes.
283
368
  */
284
369
  var dismissedContext = null;
285
- var lastSuggestionTypedLength = 0;
286
- var lastSuggestionLength = 0;
370
+ var decisionRevision = 0;
371
+ var activeDecision;
287
372
 
288
373
  /**
289
374
  * cold → no slow-lane vector received yet; frequency-only trie scoring
@@ -348,10 +433,10 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
348
433
  }
349
434
  });
350
435
  };
351
- var fireSuggestionInsertedAnalytics = function fireSuggestionInsertedAnalytics(ghostText) {
436
+ var fireSuggestionInsertedAnalytics = function fireSuggestionInsertedAnalytics(suggestion) {
352
437
  var _api$analytics4;
353
- var typedLength = lastSuggestionTypedLength;
354
- var suggestionLength = lastSuggestionLength || typedLength + ghostText.length;
438
+ var typedLength = Math.max(0, suggestion.surface.length - suggestion.ghostText.length);
439
+ var suggestionLength = suggestion.surface.length;
355
440
  var kssDelta = suggestionLength - typedLength;
356
441
  api === null || api === void 0 || (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 || _api$analytics4.actions.fireAnalyticsEvent({
357
442
  action: _analytics.ACTION.SUGGESTION_INSERTED,
@@ -370,13 +455,59 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
370
455
  debounceMs: LOCAL_SLOW_LANE_DEBOUNCE_MS,
371
456
  onLoadSuccess: fireLocalModelLoadedAnalytics,
372
457
  onLoadError: fireLocalModelLoadFailedAnalytics,
458
+ // Re-run prediction for each independently scheduled model result.
459
+ onUpdate: function onUpdate() {
460
+ var _reschedulePrediction;
461
+ return (_reschedulePrediction = reschedulePredictionOnSlowLaneResult) === null || _reschedulePrediction === void 0 ? void 0 : _reschedulePrediction({
462
+ kind: 'semantic'
463
+ });
464
+ },
465
+ onBoundaryLmUpdate: function onBoundaryLmUpdate(_ref) {
466
+ var _reschedulePrediction2;
467
+ var contextKey = _ref.contextKey,
468
+ familyKey = _ref.familyKey,
469
+ latencyMs = _ref.latencyMs;
470
+ return (_reschedulePrediction2 = reschedulePredictionOnSlowLaneResult) === null || _reschedulePrediction2 === void 0 ? void 0 : _reschedulePrediction2({
471
+ contextKey: contextKey,
472
+ familyKey: familyKey,
473
+ kind: 'boundary',
474
+ latencyMs: latencyMs
475
+ });
476
+ },
477
+ onSurfaceScoreUpdate: function onSurfaceScoreUpdate(_ref2) {
478
+ var _reschedulePrediction3;
479
+ var contextKey = _ref2.contextKey,
480
+ familyKey = _ref2.familyKey,
481
+ latencyMs = _ref2.latencyMs;
482
+ return (_reschedulePrediction3 = reschedulePredictionOnSlowLaneResult) === null || _reschedulePrediction3 === void 0 ? void 0 : _reschedulePrediction3({
483
+ contextKey: contextKey,
484
+ familyKey: familyKey,
485
+ kind: 'surface',
486
+ latencyMs: latencyMs
487
+ });
488
+ },
373
489
  surface: surface
374
490
  }) : (0, _slowLaneClient.createSlowLaneClient)({
375
491
  baseUrl: '',
376
492
  debounceMs: NETWORK_SLOW_LANE_DEBOUNCE_MS,
493
+ // Re-run prediction when the BE semantic vector / LM logits land so
494
+ // warm-mode unigram ranking applies without waiting for a keystroke.
495
+ onUpdate: function onUpdate() {
496
+ var _reschedulePrediction4;
497
+ return (_reschedulePrediction4 = reschedulePredictionOnSlowLaneResult) === null || _reschedulePrediction4 === void 0 ? void 0 : _reschedulePrediction4({
498
+ kind: 'semantic'
499
+ });
500
+ },
377
501
  surface: surface
378
502
  });
379
- (0, _slowLaneClient.setDefaultSlowLaneClient)(slowLaneClient);
503
+ var slowLaneClientKind = options !== null && options !== void 0 && options.useLocalModel ? 'localLlm' : 'server';
504
+ var slowLaneClientId = "".concat(surface, ":").concat(slowLaneClientKind, ":").concat(++slowLaneClientInstanceSequence);
505
+ (0, _slowLaneClient.setDefaultSlowLaneClient)(slowLaneClient, {
506
+ clientId: slowLaneClientId,
507
+ kind: slowLaneClientKind
508
+ });
509
+ var registeredSlowLaneStatus = (0, _slowLaneClient.getDefaultSlowLaneClientStatus)();
510
+ (0, _debugMode.ctcTag)('init', "slow lane registered \xB7 id=".concat(slowLaneClientId, " \xB7 selected=").concat(slowLaneClientKind, " \xB7 canonical=").concat(registeredSlowLaneStatus.canonicalScoringSupported ? 'yes' : 'no', " \xB7 ready=").concat((_registeredSlowLaneSt = registeredSlowLaneStatus.localModelReady) !== null && _registeredSlowLaneSt !== void 0 ? _registeredSlowLaneSt : 'n/a'), slowLaneClientKind === 'localLlm' ? _debugMode.CTC_STYLES.good : _debugMode.CTC_STYLES.warn);
380
511
  var contextRequestInFlight = false;
381
512
  var lastContextRefreshAt = 0;
382
513
  // Bounds the word-boundary retry loop so it terminates even when the editor is
@@ -393,7 +524,7 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
393
524
  }
394
525
 
395
526
  // eslint-disable-next-line no-console
396
- console.log('%c[Autocomplete] %cgetContext resolved', 'color: #00b8d9; font-weight: bold;', 'color: inherit;', {
527
+ console.log('%c[CTC:signal]%c getContext resolved', _debugMode.CTC_STYLES.brand, _debugMode.CTC_STYLES.body, {
397
528
  source: source,
398
529
  hasParentComment: !!(context !== null && context !== void 0 && context.parentCommentContent),
399
530
  parentCommentPreview: context === null || context === void 0 || (_context$parentCommen = context.parentCommentContent) === null || _context$parentCommen === void 0 ? void 0 : _context$parentCommen.slice(0, 80),
@@ -408,9 +539,9 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
408
539
  // fullPageContent, so replacing would drop previously resolved context.
409
540
  // Strip undefined values first so a field explicitly set to undefined by
410
541
  // getContext doesn't overwrite a previously resolved value.
411
- var definedContext = Object.fromEntries(Object.entries(context).filter(function (_ref) {
412
- var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
413
- value = _ref2[1];
542
+ var definedContext = Object.fromEntries(Object.entries(context).filter(function (_ref3) {
543
+ var _ref4 = (0, _slicedToArray2.default)(_ref3, 2),
544
+ value = _ref4[1];
414
545
  return value !== undefined;
415
546
  }));
416
547
  resolvedContext = _objectSpread(_objectSpread({}, resolvedContext), definedContext);
@@ -456,10 +587,10 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
456
587
  * (no getContext, a request already in flight, or throttled). Callers that
457
588
  * track a retry budget should only count attempts where this returns true.
458
589
  */
459
- var refreshContext = function refreshContext(_ref3) {
460
- var source = _ref3.source,
461
- _ref3$allowThrottle = _ref3.allowThrottle,
462
- allowThrottle = _ref3$allowThrottle === void 0 ? true : _ref3$allowThrottle;
590
+ var refreshContext = function refreshContext(_ref5) {
591
+ var source = _ref5.source,
592
+ _ref5$allowThrottle = _ref5.allowThrottle,
593
+ allowThrottle = _ref5$allowThrottle === void 0 ? true : _ref5$allowThrottle;
463
594
  if (!(options !== null && options !== void 0 && options.getContext) || contextRequestInFlight) {
464
595
  return false;
465
596
  }
@@ -490,73 +621,230 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
490
621
  });
491
622
  return true;
492
623
  };
493
-
494
- /**
495
- * Schedule a prediction after a short debounce.
496
- * Tier 1 predictions are synchronous (<0.1ms) but we still debounce
497
- * to avoid unnecessary work on rapid keystrokes.
498
- */
499
- var schedulePrediction = function schedulePrediction(view) {
624
+ var clearDecisionTimers = function clearDecisionTimers() {
500
625
  if (debounceTimer) {
501
626
  clearTimeout(debounceTimer);
627
+ debounceTimer = null;
502
628
  }
503
- debounceTimer = setTimeout(function () {
504
- try {
505
- var state = view.state;
506
- var selection = state.selection;
507
- if (!selection.empty) {
508
- return;
509
- }
629
+ if (decisionDeadlineTimer) {
630
+ clearTimeout(decisionDeadlineTimer);
631
+ decisionDeadlineTimer = null;
632
+ }
633
+ };
634
+ var cancelActiveDecision = function cancelActiveDecision() {
635
+ clearDecisionTimers();
636
+ activeDecision = undefined;
637
+ };
638
+ var isDecisionSnapshotCurrent = function isDecisionSnapshotCurrent(view, decision) {
639
+ var state = view.state;
640
+ return state.selection.empty && state.selection.from === decision.position && getTextBeforeCursor(state) === decision.textBefore;
641
+ };
642
+ var isDecisionCurrent = function isDecisionCurrent(view, decision) {
643
+ var _activeDecision;
644
+ return ((_activeDecision = activeDecision) === null || _activeDecision === void 0 ? void 0 : _activeDecision.revision) === decision.revision && isDecisionSnapshotCurrent(view, decision);
645
+ };
646
+ var expireActiveDecision = function expireActiveDecision(decision) {
647
+ var _activeDecision2;
648
+ if (((_activeDecision2 = activeDecision) === null || _activeDecision2 === void 0 ? void 0 : _activeDecision2.revision) !== decision.revision) {
649
+ return;
650
+ }
651
+ cancelActiveDecision();
652
+ };
653
+ var evaluateActiveDecision = function evaluateActiveDecision(view, revision) {
654
+ var decision = activeDecision;
655
+ if (!decision || decision.revision !== revision || !isDecisionCurrent(view, decision)) {
656
+ return;
657
+ }
658
+ if (performance.now() > decision.deadlineAt) {
659
+ expireActiveDecision(decision);
660
+ return;
661
+ }
662
+ decision.evaluations++;
663
+ try {
664
+ var state = view.state;
665
+ var selection = state.selection;
510
666
 
511
- // Suppress suggestions when the cursor is mid-word — only offer
512
- // completions when the cursor is at the trailing edge of a token.
513
- // nodeAfter correctly handles inline atoms (mentions, emojis) where
514
- // parentOffset and textContent indices diverge.
515
- var nodeAfter = selection.$from.nodeAfter;
516
- var charAfterCursor = nodeAfter !== null && nodeAfter !== void 0 && nodeAfter.isText ? getLeadingTextCharacter(nodeAfter.text) : undefined;
517
- // Only suppress for Unicode letters, digits, and underscore — hyphens,
518
- // apostrophes, and similar punctuation are valid left-edge boundaries
519
- // and should not block suggestions (e.g. cursor before '-' in compound-word).
520
- if (charAfterCursor && isMidWordCharacter(charAfterCursor)) {
521
- return;
522
- }
523
- var textBefore = getTextBeforeCursor(state);
667
+ // Suppress suggestions when the cursor is mid-word — only offer
668
+ // completions when the cursor is at the trailing edge of a token.
669
+ var nodeAfter = selection.$from.nodeAfter;
670
+ var charAfterCursor = nodeAfter !== null && nodeAfter !== void 0 && nodeAfter.isText ? getLeadingTextCharacter(nodeAfter.text) : undefined;
671
+ if (charAfterCursor && isMidWordCharacter(charAfterCursor)) {
672
+ cancelActiveDecision();
673
+ return;
674
+ }
675
+ if (decision.textBefore === dismissedContext) {
676
+ cancelActiveDecision();
677
+ return;
678
+ }
679
+ dismissedContext = null;
524
680
 
525
- // Suppress re-showing the same suggestion the user just dismissed.
526
- // Once the text context changes (user types or deletes), this clears automatically.
527
- if (textBefore === dismissedContext) {
528
- return;
529
- }
530
- dismissedContext = null;
531
- if (textBefore.trim().length < 3) {
532
- return;
681
+ // Two characters are enough to prefetch the canonical shortlist. The
682
+ // predictor itself withholds display until the three-character gate.
683
+ if (decision.textBefore.trim().length < 2) {
684
+ cancelActiveDecision();
685
+ return;
686
+ }
687
+ var prediction = (0, _textPredictor.predict)(decision.textBefore);
688
+ if (!prediction || prediction.text.length === 0) {
689
+ // Remain in `collecting` until an async signal arrives or the hard
690
+ // deadline expires. We never display a provisional fallback.
691
+ return;
692
+ }
693
+ var readyAtMs = performance.now() - decision.startedAt;
694
+ if (readyAtMs > GHOST_DECISION_BUDGET_MS) {
695
+ cancelActiveDecision();
696
+ if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
697
+ // eslint-disable-next-line no-console
698
+ console.log('%c[CTC:budget]%c fully gated after render deadline (render suppressed)', _debugMode.CTC_STYLES.section, _debugMode.CTC_STYLES.body, {
699
+ revision: decision.revision,
700
+ readyAtMs: readyAtMs,
701
+ surface: prediction.surface
702
+ });
533
703
  }
534
- var prediction = (0, _textPredictor.predict)(textBefore);
535
- if (prediction && prediction.length > 0) {
536
- var typedLength = getTypedLengthForPrediction(textBefore);
537
- lastSuggestionTypedLength = typedLength;
538
- lastSuggestionLength = typedLength + prediction.length;
539
- showGhostText(view, prediction, selection.from);
540
- if (prediction !== lastShownGhostText) {
541
- var _api$analytics5;
542
- lastShownGhostText = prediction;
543
- api === null || api === void 0 || (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 || _api$analytics5.actions.fireAnalyticsEvent({
544
- action: _analytics.ACTION.SUGGESTION_VIEWED,
545
- actionSubject: _analytics.ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
546
- eventType: _analytics.EVENT_TYPE.TRACK,
547
- attributes: {
548
- completionSource: getCompletionSource(),
549
- surface: surface
550
- }
551
- });
704
+ return;
705
+ }
706
+ var suggestion = showGhostText(view, prediction, decision.position, decision.revision, decision.startedAt);
707
+ if (!suggestion) {
708
+ cancelActiveDecision();
709
+ return;
710
+ }
711
+ cancelActiveDecision();
712
+ if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
713
+ // eslint-disable-next-line no-console
714
+ console.log('%c[CTC:decision]%c committed immutable ghost', _debugMode.CTC_STYLES.brand, _debugMode.CTC_STYLES.body, {
715
+ revision: suggestion.revision,
716
+ surface: suggestion.surface,
717
+ ghostText: suggestion.ghostText,
718
+ evidenceTier: suggestion.evidenceTier,
719
+ rankScore: suggestion.rankScore,
720
+ winnerMargin: suggestion.winnerMargin,
721
+ decisionLatencyMs: suggestion.decisionLatencyMs,
722
+ budgetMs: GHOST_DECISION_BUDGET_MS,
723
+ typedPrefixLength: getTrailingSurfacePrefixLength(decision.textBefore),
724
+ evaluations: decision.evaluations,
725
+ asyncSignals: decision.asyncSignals,
726
+ readyWithinBudget: suggestion.decisionLatencyMs <= GHOST_DECISION_BUDGET_MS
727
+ });
728
+ }
729
+ if (suggestion.ghostText !== lastShownGhostText) {
730
+ var _api$analytics5;
731
+ lastShownGhostText = suggestion.ghostText;
732
+ api === null || api === void 0 || (_api$analytics5 = api.analytics) === null || _api$analytics5 === void 0 || _api$analytics5.actions.fireAnalyticsEvent({
733
+ action: _analytics.ACTION.SUGGESTION_VIEWED,
734
+ actionSubject: _analytics.ACTION_SUBJECT.CONTEXTUAL_TYPEAHEAD,
735
+ eventType: _analytics.EVENT_TYPE.TRACK,
736
+ attributes: {
737
+ completionSource: getCompletionSource(),
738
+ surface: surface
552
739
  }
553
- }
554
- } catch (error) {
555
- (0, _monitoring.logException)(error, {
556
- location: 'editor-plugin-autocomplete/schedulePrediction'
557
740
  });
558
741
  }
559
- }, DEBOUNCE_MS);
742
+ } catch (error) {
743
+ cancelActiveDecision();
744
+ (0, _monitoring.logException)(error, {
745
+ location: 'editor-plugin-autocomplete/evaluateActiveDecision'
746
+ });
747
+ }
748
+ };
749
+ var beginPredictionDecision = function beginPredictionDecision(view) {
750
+ cancelActiveDecision();
751
+ var state = view.state;
752
+ if (!state.selection.empty) {
753
+ return;
754
+ }
755
+ var startedAt = performance.now();
756
+ var textBefore = getTextBeforeCursor(state);
757
+ var revision = ++decisionRevision;
758
+ activeDecision = {
759
+ asyncSignals: 0,
760
+ deadlineAt: startedAt + GHOST_DECISION_BUDGET_MS,
761
+ evaluations: 0,
762
+ position: state.selection.from,
763
+ revision: revision,
764
+ startedAt: startedAt,
765
+ textBefore: textBefore
766
+ };
767
+ if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
768
+ // eslint-disable-next-line no-console
769
+ console.log('%c[CTC:decision]%c collecting', _debugMode.CTC_STYLES.brand, _debugMode.CTC_STYLES.body, {
770
+ revision: revision,
771
+ budgetMs: GHOST_DECISION_BUDGET_MS,
772
+ coalesceMs: PREDICTION_COALESCE_MS,
773
+ typedPrefixLength: getTrailingSurfacePrefixLength(activeDecision.textBefore),
774
+ textBefore: activeDecision.textBefore.slice(-80)
775
+ });
776
+ }
777
+ debounceTimer = setTimeout(function () {
778
+ debounceTimer = null;
779
+ evaluateActiveDecision(view, revision);
780
+ }, PREDICTION_COALESCE_MS);
781
+ decisionDeadlineTimer = setTimeout(function () {
782
+ var _activeDecision3;
783
+ decisionDeadlineTimer = null;
784
+ if (((_activeDecision3 = activeDecision) === null || _activeDecision3 === void 0 ? void 0 : _activeDecision3.revision) === revision) {
785
+ var expiredDecision = activeDecision;
786
+ if ((0, _debugMode.isAutocompleteDebugEnabled)()) {
787
+ var elapsedMs = performance.now() - expiredDecision.startedAt;
788
+ var predictionDebug = (0, _textPredictor.getLastPredictionDebug)();
789
+ var matchingPredictionDebug = (predictionDebug === null || predictionDebug === void 0 ? void 0 : predictionDebug.textBefore) === expiredDecision.textBefore ? predictionDebug : null;
790
+ var abstentionPrefix = '— abstain: ';
791
+ var predictorDecision = matchingPredictionDebug === null || matchingPredictionDebug === void 0 ? void 0 : matchingPredictionDebug.decision;
792
+ var predictorReason = predictorDecision !== null && predictorDecision !== void 0 && predictorDecision.startsWith(abstentionPrefix) ? predictorDecision.slice(abstentionPrefix.length) : predictorDecision;
793
+ var decisionMessage = predictorReason && !(matchingPredictionDebug !== null && matchingPredictionDebug !== void 0 && matchingPredictionDebug.awaitingAsyncEvidence) ? "abstain: ".concat(predictorReason) : "abstain: ".concat(GHOST_DECISION_BUDGET_MS, "ms decision budget expired").concat(predictorReason ? " \xB7 ".concat(predictorReason) : '');
794
+ // eslint-disable-next-line no-console
795
+ console.log("%c[CTC:decision]%c ".concat(decisionMessage), _debugMode.CTC_STYLES.brand, _debugMode.CTC_STYLES.body, {
796
+ revision: revision,
797
+ budgetMs: GHOST_DECISION_BUDGET_MS,
798
+ elapsedMs: elapsedMs,
799
+ typedPrefixLength: getTrailingSurfacePrefixLength(expiredDecision.textBefore),
800
+ evaluations: expiredDecision.evaluations,
801
+ asyncSignals: expiredDecision.asyncSignals,
802
+ textBefore: expiredDecision.textBefore.slice(-80),
803
+ predictorDecision: predictorReason !== null && predictorReason !== void 0 ? predictorReason : null
804
+ });
805
+ }
806
+ expireActiveDecision(expiredDecision);
807
+ }
808
+ }, GHOST_DECISION_BUDGET_MS);
809
+ };
810
+
811
+ // Async semantic/canonical results may complete the active decision, but they
812
+ // never create a new decision or replace an already committed ghost.
813
+ reschedulePredictionOnSlowLaneResult = function reschedulePredictionOnSlowLaneResult(signal) {
814
+ if (destroyed || !currentView) {
815
+ return;
816
+ }
817
+ if (!activeDecision) {
818
+ return;
819
+ }
820
+ var revision = activeDecision.revision;
821
+ var elapsedMs = performance.now() - activeDecision.startedAt;
822
+ var remainingMs = activeDecision.deadlineAt - performance.now();
823
+ if (remainingMs < 0) {
824
+ var expiredDecision = activeDecision;
825
+ expireActiveDecision(expiredDecision);
826
+ return;
827
+ }
828
+ activeDecision.asyncSignals++;
829
+ if ((0, _debugMode.isAutocompleteDebugVerbose)()) {
830
+ // eslint-disable-next-line no-console
831
+ console.log('%c[CTC:readiness]%c async evidence signal', _debugMode.CTC_STYLES.section, _debugMode.CTC_STYLES.body, _objectSpread(_objectSpread({}, signal), {}, {
832
+ revision: revision,
833
+ elapsedMs: elapsedMs,
834
+ remainingMs: Math.max(0, remainingMs),
835
+ typedPrefixLength: getTrailingSurfacePrefixLength(activeDecision.textBefore),
836
+ withinBudget: remainingMs >= 0
837
+ }));
838
+ }
839
+ if (debounceTimer) {
840
+ clearTimeout(debounceTimer);
841
+ }
842
+ debounceTimer = setTimeout(function () {
843
+ debounceTimer = null;
844
+ if (currentView) {
845
+ evaluateActiveDecision(currentView, revision);
846
+ }
847
+ }, 0);
560
848
  };
561
849
  var maybeUpdateSessionFrequency = function maybeUpdateSessionFrequency(view, prevState) {
562
850
  var newText = getTextBeforeCursor(view.state);
@@ -594,20 +882,14 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
594
882
  return _objectSpread(_objectSpread({}, pluginState), meta);
595
883
  }
596
884
 
597
- // A new prediction is scheduled from view.update.
885
+ // A new prediction is scheduled from view.update either way; the
886
+ // surviving ghost only covers the gap until it commits.
598
887
  if (tr.docChanged) {
599
- return _objectSpread(_objectSpread({}, pluginState), {}, {
600
- ghostText: '',
601
- ghostPosition: -1,
602
- decorationSet: _view.DecorationSet.empty
603
- });
888
+ var _advanceGhostThroughT;
889
+ return (_advanceGhostThroughT = advanceGhostThroughTypedCharacter(tr, pluginState)) !== null && _advanceGhostThroughT !== void 0 ? _advanceGhostThroughT : clearGhostState(pluginState);
604
890
  }
605
891
  if (tr.selectionSet && pluginState.ghostText) {
606
- return _objectSpread(_objectSpread({}, pluginState), {}, {
607
- ghostText: '',
608
- ghostPosition: -1,
609
- decorationSet: _view.DecorationSet.empty
610
- });
892
+ return clearGhostState(pluginState);
611
893
  }
612
894
  return pluginState;
613
895
  }
@@ -620,22 +902,25 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
620
902
  },
621
903
  handleKeyDown: (0, _keymap.keydownHandler)({
622
904
  Tab: function Tab(state, dispatch) {
623
- return acceptGhostTextWithAnalytics(state, dispatch, function (ghostText) {
905
+ return acceptGhostTextWithAnalytics(state, dispatch, function (suggestion) {
624
906
  justAccepted = true;
625
907
  lastShownGhostText = '';
626
- fireSuggestionInsertedAnalytics(ghostText);
908
+ cancelActiveDecision();
909
+ fireSuggestionInsertedAnalytics(suggestion);
627
910
  });
628
911
  },
629
912
  ArrowRight: function ArrowRight(state, dispatch) {
630
- return acceptGhostTextWithAnalytics(state, dispatch, function (ghostText) {
913
+ return acceptGhostTextWithAnalytics(state, dispatch, function (suggestion) {
631
914
  justAccepted = true;
632
915
  lastShownGhostText = '';
633
- fireSuggestionInsertedAnalytics(ghostText);
916
+ cancelActiveDecision();
917
+ fireSuggestionInsertedAnalytics(suggestion);
634
918
  });
635
919
  },
636
920
  Escape: function Escape(state, dispatch) {
637
921
  var didClear = clearGhostText(state, dispatch);
638
922
  if (didClear) {
923
+ cancelActiveDecision();
639
924
  dismissedContext = getTextBeforeCursor(state);
640
925
  fireSuggestionDismissedAnalytics('escape');
641
926
  }
@@ -650,6 +935,7 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
650
935
  var pluginState = autocompletePluginKey.getState(view.state);
651
936
  if (pluginState !== null && pluginState !== void 0 && pluginState.ghostText) {
652
937
  clearGhostText(view.state, view.dispatch);
938
+ cancelActiveDecision();
653
939
  fireSuggestionDismissedAnalytics('blur');
654
940
  }
655
941
  return false;
@@ -661,6 +947,7 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
661
947
  if (!event.target.closest('[data-autocomplete-ghost="true"]')) {
662
948
  var didClear = clearGhostText(view.state, view.dispatch);
663
949
  if (didClear) {
950
+ cancelActiveDecision();
664
951
  dismissedContext = getTextBeforeCursor(view.state);
665
952
  lastShownGhostText = '';
666
953
  fireSuggestionDismissedAnalytics('click');
@@ -668,10 +955,11 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
668
955
  return false;
669
956
  }
670
957
  event.preventDefault();
671
- var accepted = acceptGhostTextWithAnalytics(view.state, view.dispatch, function (ghostText) {
958
+ var accepted = acceptGhostTextWithAnalytics(view.state, view.dispatch, function (suggestion) {
672
959
  justAccepted = true;
673
960
  lastShownGhostText = '';
674
- fireSuggestionInsertedAnalytics(ghostText);
961
+ cancelActiveDecision();
962
+ fireSuggestionInsertedAnalytics(suggestion);
675
963
  });
676
964
  if (accepted) {
677
965
  view.focus();
@@ -746,9 +1034,7 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
746
1034
  // Snapshot the post-acceptance text so follow-up transactions hit
747
1035
  // the dismissedContext guard and abort until the user types again.
748
1036
  dismissedContext = getTextBeforeCursor(view.state);
749
- if (debounceTimer) {
750
- clearTimeout(debounceTimer);
751
- }
1037
+ cancelActiveDecision();
752
1038
  return;
753
1039
  }
754
1040
  maybeUpdateSessionFrequency(view, prevState);
@@ -773,7 +1059,9 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
773
1059
  }
774
1060
  }
775
1061
  }
776
- schedulePrediction(view);
1062
+ beginPredictionDecision(view);
1063
+ } else if (!prevState.selection.eq(view.state.selection)) {
1064
+ cancelActiveDecision();
777
1065
  }
778
1066
  },
779
1067
  destroy: function destroy() {
@@ -782,14 +1070,13 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
782
1070
  currentView = null;
783
1071
  (_unsubscribeFromConte = unsubscribeFromContextUpdates) === null || _unsubscribeFromConte === void 0 || _unsubscribeFromConte();
784
1072
  unsubscribeFromContextUpdates = undefined;
785
- if (debounceTimer) {
786
- clearTimeout(debounceTimer);
787
- }
1073
+ cancelActiveDecision();
1074
+ var releasedDefaultClient = (0, _slowLaneClient.clearDefaultSlowLaneClient)(slowLaneClient);
1075
+ (0, _debugMode.ctcTag)('init', "slow lane teardown \xB7 id=".concat(slowLaneClientId, " \xB7 default=").concat(releasedDefaultClient ? 'released' : 'retained newer owner'), releasedDefaultClient ? _debugMode.CTC_STYLES.dim : _debugMode.CTC_STYLES.warn);
788
1076
  if (hasDestroy(slowLaneClient)) {
789
1077
  slowLaneClient.destroy();
790
1078
  }
791
1079
  ingestedContextTexts.clear();
792
- (0, _slowLaneClient.setDefaultSlowLaneClient)(null);
793
1080
  }
794
1081
  };
795
1082
  }