@tea-agent/loop-agent 0.43.0-next.16 → 0.43.0-next.18

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 (154) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/dist/application/dag/args.js +8 -0
  3. package/dist/build-stamp.json +3 -3
  4. package/dist/cli/command-definitions.js +2 -0
  5. package/dist/cli/program.js +3 -1
  6. package/dist/cli/update/init-surface-notifier.js +2 -0
  7. package/dist/cli/update/policy.js +2 -0
  8. package/dist/commands/cursor-prompt.js +2 -0
  9. package/dist/commands/dag-approve.js +2 -0
  10. package/dist/commands/dag-final-verification.js +2 -0
  11. package/dist/commands/dag-init-hybrid.js +2 -0
  12. package/dist/commands/dag-reconcile-tasks.js +2 -0
  13. package/dist/commands/dag-reject.js +2 -0
  14. package/dist/commands/dag-report.js +2 -0
  15. package/dist/commands/dag-rerun.js +2 -0
  16. package/dist/commands/dag-resume.js +2 -0
  17. package/dist/commands/dag-workflow-compile.js +2 -0
  18. package/dist/commands/dag-workflow-plan.js +2 -0
  19. package/dist/commands/dag-workflow-validate.js +2 -0
  20. package/dist/commands/delegate.js +2 -0
  21. package/dist/commands/examples.js +2 -0
  22. package/dist/commands/import-prd.js +2 -0
  23. package/dist/commands/init-model-catalog.js +2 -0
  24. package/dist/commands/init.js +6 -4
  25. package/dist/commands/instructions.js +2 -0
  26. package/dist/commands/knowledge.js +2 -0
  27. package/dist/commands/loop-benchmark.js +2 -0
  28. package/dist/commands/pi-prompt.js +2 -0
  29. package/dist/commands/pi-reuse-benchmark.js +2 -0
  30. package/dist/commands/promote-run.js +2 -0
  31. package/dist/commands/stats.js +1 -1
  32. package/dist/commands/study-init.js +2 -0
  33. package/dist/commands/task-advance.js +2 -0
  34. package/dist/commands/task-source-prepare.js +2 -0
  35. package/dist/commands/worktree-create.js +2 -0
  36. package/dist/commands/worktree-remove.js +2 -0
  37. package/dist/executors/dag-pi-executor.js +25 -6
  38. package/dist/executors/shell-verification.js +3 -0
  39. package/dist/governance/exec-plans.js +6 -3
  40. package/dist/infrastructure/console/app-data.js +6 -0
  41. package/dist/shared/artifacts-core.js +2 -0
  42. package/dist/shared/git-progress.js +2 -0
  43. package/dist/shared/one-shot-prompt-args.js +2 -0
  44. package/dist/shared/package-metadata.js +6 -4
  45. package/dist/shared/pi-context-pressure/sift-bridge.js +1 -1
  46. package/dist/shared/reference-context.js +2 -0
  47. package/dist/task/contract/recover.js +6 -0
  48. package/dist/task/source-prepare/artifact-meta.js +9 -2
  49. package/dist/task/source-prepare/fragment-inventory.js +4 -1
  50. package/dist/task/source-prepare/parse-intent.js +36 -11
  51. package/dist/task/task-demand-routing.js +5 -2
  52. package/dist/worker/console/chat/browser-automation.js +468 -308
  53. package/dist/worker/console/chat/browser-routes.js +175 -57
  54. package/dist/worker/console/chat/explore-tools.js +5 -2
  55. package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +115 -20
  56. package/dist/worker/console/chat/pi-runtime.js +9 -1
  57. package/dist/worker/console/chat/routes.js +1 -1
  58. package/dist/worker/console/chat/sdd-data-alignment.js +1 -1
  59. package/dist/worker/console/chat/session-mode.js +1 -1
  60. package/dist/worker/console/chat/tools.js +7 -1
  61. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C4NXyedy.js → abnfDiagram-N423BO3Z-B_UDknhR.js} +1 -1
  62. package/dist/worker/console/static/assets/{arc-NZ3qXvBI.js → arc-D6hU0drN.js} +1 -1
  63. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-COZSRvml.js → architectureDiagram-T3A2C74G-DmVikdRK.js} +1 -1
  64. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Ck0Gxi9C.js → blockDiagram-VBNYF7ZC-DydABCRg.js} +1 -1
  65. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BX5HQ4Ox.js → c4Diagram-5PPSVZJV-DrXKC2Jl.js} +1 -1
  66. package/dist/worker/console/static/assets/channel-Drecd94a.js +1 -0
  67. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-CoviemSL.js → chunk-2GRJ4B5K-D2-qFxr7.js} +1 -1
  68. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DbOdOkbZ.js → chunk-2Q5K7J3B-ChfeF41P.js} +1 -1
  69. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BsG2pmdQ.js → chunk-5RXB4S5H-Drwrz55x.js} +1 -1
  70. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-DGdvrNm8.js → chunk-5VM5RSS4-CAQGErL7.js} +1 -1
  71. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BAy7Yd6y.js → chunk-6Q2QTUOP-DHO38w5U.js} +1 -1
  72. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-D9UA7hUb.js → chunk-GF5L2VYU-EYIN0EOI.js} +1 -1
  73. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-DPz7SZ8V.js → chunk-JWPE2WC7-CrFLKqkT.js} +1 -1
  74. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BmuEOIh7.js → chunk-KBJHAD2P-DMchffoo.js} +1 -1
  75. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CIhBWnd8.js → chunk-RYQCIY6F-DaSvtKQa.js} +1 -1
  76. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CScR6mDD.js → chunk-XXDRQBXY-DcW8W9Qj.js} +1 -1
  77. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-8Udu0t8-.js +1 -0
  78. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-8Udu0t8-.js +1 -0
  79. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BjpfWaUr.js → cose-bilkent-JH36ORCC-BUirrMEi.js} +1 -1
  80. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BFQohJgT.js → cynefin-VYW2F7L2-BXzO8iXR.js} +1 -1
  81. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-D3gzRJnS.js → cynefinDiagram-MW4NZA55-DAtgaxIn.js} +1 -1
  82. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-5eojkhoA.js → dagre-VZM6K2ZE-C1re9Noh.js} +1 -1
  83. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-CpD8LWu_.js → diagram-7IWD3JNH-N8Kj08J9.js} +1 -1
  84. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-B8_4qJ2a.js → diagram-B4RE2ZJO-D6BpSLs3.js} +1 -1
  85. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-HOsXf0eu.js → diagram-LBJQPF4R-C2Vlgnl4.js} +1 -1
  86. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BqwRwiWP.js → diagram-Q27KOJAE-CMbqtVLS.js} +1 -1
  87. package/dist/worker/console/static/assets/{diagram-UB23O5K3-BRVCNZe1.js → diagram-UB23O5K3-A770Eb-0.js} +1 -1
  88. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Cvb1TgGh.js → ebnfDiagram-BXEA7PRR-LV2w_2pT.js} +1 -1
  89. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DS0O0qG9.js → erDiagram-JOGREHBK-bwqf56ah.js} +1 -1
  90. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-BHIRvRr3.js → flowDiagram-UKHOOZJN-BnVtHhZh.js} +1 -1
  91. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DcCJ1JWx.js → ganttDiagram-PKOTCBZU-BGVToEqc.js} +1 -1
  92. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-B9ia5ony.js → gitGraphDiagram-DS77QQ5N-DL2l7Vne.js} +1 -1
  93. package/dist/worker/console/static/assets/{index-wXlQohNs.js → index-B_V4wvXs.js} +44 -44
  94. package/dist/worker/console/static/assets/{index-B9goN3S5.css → index-DcudonhZ.css} +1 -1
  95. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-3ogpgegn.js → infoDiagram-6WML65LV-BWIpubOx.js} +1 -1
  96. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-4tgpQ5SL.js → ishikawaDiagram-WSZJBQD7-DjYBD8vv.js} +1 -1
  97. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DNfgHqFx.js → journeyDiagram-NVQOT4AX-C0_mBaHb.js} +1 -1
  98. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-Dz7ngC8z.js → kanban-definition-27J2QSJJ-Cy71zbX6.js} +1 -1
  99. package/dist/worker/console/static/assets/{linear-DI7Jv62E.js → linear-Dt3_w3Vn.js} +1 -1
  100. package/dist/worker/console/static/assets/{mermaid.core-CQA4Nzmo.js → mermaid.core-DnNOlfEP.js} +5 -5
  101. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-CtsMc8Mf.js → mindmap-definition-FAOFIHXS-DAbTspwq.js} +1 -1
  102. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-ByppE9yH.js → pegDiagram-VL7TDLO6-NNiM141p.js} +1 -1
  103. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-B5PtgFgt.js → pieDiagram-7S7Q4E2Y-CN80Z1Do.js} +1 -1
  104. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-Cq4p0k2K.js → quadrantDiagram-CIZ2JOQS-Bxyfh0JU.js} +1 -1
  105. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-DjfkyljN.js → railroadDiagram-AXF67PYL-BlWnC79M.js} +1 -1
  106. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-DzynNRSl.js → requirementDiagram-LRYGKXZP-BrEu4P_e.js} +1 -1
  107. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cj7TCpTJ.js → sankeyDiagram-W5VNT64P-Bt70igBr.js} +1 -1
  108. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-C73C6ykA.js → sequenceDiagram-SI44F4Z6-C8DQR-r9.js} +1 -1
  109. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-BiNLgN2x.js → sizeCapture-X5ZJPWSS-DEMinJAT.js} +1 -1
  110. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-UwvjS64-.js → stateDiagram-OKZ733FA-DDdDBzQc.js} +1 -1
  111. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-CyCiS0Lt.js +1 -0
  112. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CC7DH98r.js → swimlanes-SLNWSIFB-G2wcBs3T.js} +2 -2
  113. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-U0lhi6N0.js +8 -0
  114. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-LSBXTR70.js → timeline-definition-Z64GVDOM-Dzn4g2gJ.js} +1 -1
  115. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BAuxWwGP.js → vennDiagram-T6HMQDX7-5v2rP9oO.js} +1 -1
  116. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y--E5_gjZx.js → wardleyDiagram-T6FBY63Y-B4EOx7ew.js} +1 -1
  117. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-dJWNmyzF.js → xychartDiagram-ELKLHX3M-CQ1v8eYP.js} +1 -1
  118. package/dist/worker/console/static/index.html +2 -2
  119. package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +15 -5
  120. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +2 -0
  121. package/dist/worker/console/static-src/prd-file-import.js +3 -1
  122. package/dist/worker/console/workspace-context.js +6 -1
  123. package/dist/worker/delivery/git-transaction.js +2 -0
  124. package/dist/worker/feature/fullstack-validate.js +2 -0
  125. package/dist/worker/loop-agent/loop-agent-client.js +8 -2
  126. package/dist/worker/materialize/harness-task-materializer.js +4 -1
  127. package/dist/worker/metrics/projector.js +1 -1
  128. package/dist/worker/observability/event-store.js +4 -1
  129. package/dist/worker/observability/read-model.js +4 -1
  130. package/dist/worker/observe/node-transparency.js +23 -1
  131. package/dist/worker/observe/routes.js +4 -0
  132. package/dist/worker/outcomes/declared-artifacts.js +2 -0
  133. package/dist/worker/preflight.js +3 -0
  134. package/dist/worker/task-spec/validate.js +4 -1
  135. package/dist/workflows/dag/decision-envelope.js +2 -0
  136. package/dist/workflows/dag/dynamic-runtime/shared.js +2 -2
  137. package/dist/workflows/dag/frontend-verification-trace.js +14 -10
  138. package/dist/workflows/dag/init-hybrid.js +105 -11
  139. package/dist/workflows/dag/interrupt-request.js +2 -0
  140. package/dist/workflows/dag/lifecycle.js +4 -0
  141. package/dist/workflows/dag/node-execution.js +2 -0
  142. package/dist/workflows/dag/reconcile-run.js +2 -0
  143. package/dist/workflows/dag/repair-artifact.js +3 -1
  144. package/dist/workflows/dag/report.js +2 -0
  145. package/dist/workflows/dag/rerun-task.js +2 -0
  146. package/dist/workflows/dag/types.js +21 -6
  147. package/dist/workflows/dag/validate.js +4 -0
  148. package/docs/governance/README.md +1 -0
  149. package/package.json +3 -1
  150. package/dist/worker/console/static/assets/channel-BxdTlb_5.js +0 -1
  151. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-_ByA1Nf8.js +0 -1
  152. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-_ByA1Nf8.js +0 -1
  153. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-nLgMZ0D3.js +0 -1
  154. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BcYqTady.js +0 -8
@@ -70,6 +70,12 @@ export async function recoverTaskContract(input) {
70
70
  };
71
71
  }
72
72
  const txId = input.txId ?? unfinished[0];
73
+ if (txId === undefined) {
74
+ return {
75
+ action: "manual-required",
76
+ message: "no unfinished transactions to recover",
77
+ };
78
+ }
73
79
  if (!unfinished.includes(txId)) {
74
80
  return {
75
81
  action: "manual-required",
@@ -17,7 +17,10 @@ function parseSimpleFrontmatter(block) {
17
17
  const match = /^([A-Za-z0-9_-]+)\s*:\s*(.+?)\s*$/u.exec(line);
18
18
  if (!match)
19
19
  continue;
20
- out[match[1]] = parseYamlishScalar(match[2]);
20
+ const [, key, value] = match;
21
+ if (key === undefined || value === undefined)
22
+ continue;
23
+ out[key] = parseYamlishScalar(value);
21
24
  }
22
25
  return out;
23
26
  }
@@ -46,7 +49,11 @@ export function detectProductArtifactMeta(markdown) {
46
49
  if (!match) {
47
50
  return { artifactType: "unknown", recognized: false };
48
51
  }
49
- const fields = parseSimpleFrontmatter(match[1]);
52
+ const [, frontmatter] = match;
53
+ if (frontmatter === undefined) {
54
+ return { artifactType: "unknown", recognized: false };
55
+ }
56
+ const fields = parseSimpleFrontmatter(frontmatter);
50
57
  const artifactType = normalizeArtifactType(fields.artifact_type);
51
58
  const recognized = artifactType !== "unknown" || Boolean(fields.artifact_version);
52
59
  return {
@@ -122,7 +122,10 @@ function isAtxHeading(line) {
122
122
  const match = /^(#{1,6})\s+(.+?)\s*$/u.exec(line);
123
123
  if (!match)
124
124
  return null;
125
- return { level: match[1].length, text: match[2].trim() };
125
+ const [, hashes, text] = match;
126
+ if (hashes === undefined || text === undefined)
127
+ return null;
128
+ return { level: hashes.length, text: text.trim() };
126
129
  }
127
130
  function isListItem(line) {
128
131
  return /^\s*(?:[-*+]|\d+[.)])\s+(?:\[(?: |x|X)\]\s+)?/.test(line);
@@ -59,11 +59,21 @@ function stripFencedAndComments(text) {
59
59
  .replace(/<!--[\s\S]*?-->/g, "\n");
60
60
  }
61
61
  function normalizeAcceptanceId(raw) {
62
- return raw
62
+ return (raw
63
63
  .trim()
64
64
  .toUpperCase()
65
65
  .replace(/_/g, "-")
66
- .replace(/^(AC)(FE|BE|UI|API)(?=-|\d)/u, "$1-$2");
66
+ .replace(/^(AC)(FE|BE|UI|API)(?=-|\d)/u, "$1-$2")
67
+ // A PRD writes `AC1` as naturally as `AC-1` or `AC_1`. Only the two earlier
68
+ // rules canonicalized a separator, so a bare `AC1` escaped verbatim — and the
69
+ // generated DAG's requirement-id schema requires a hyphen after the prefix
70
+ // (`/^(?:REQ|BR|AC)-[A-Z0-9]+(?:-[A-Z0-9]+)*$/`). Other consumers already
71
+ // assume `AC-...` (e.g. the frontend-test checklist demands `AC-FE-001`).
72
+ // The result was a meaningless split: the same PRD style generated fine under
73
+ // `taskKind: standard` and failed DAG generation under
74
+ // `taskKind: frontend-implementation`. Canonicalize here, once, so every
75
+ // workflow reads the same ids.
76
+ .replace(/^AC(?=\d)/u, "AC-"));
67
77
  }
68
78
  function parseEmbeddedAcHeading(headingText) {
69
79
  const normalized = headingText
@@ -77,7 +87,10 @@ function parseEmbeddedAcHeading(headingText) {
77
87
  const match = EMBEDDED_AC_HEADING.exec(normalized);
78
88
  if (!match)
79
89
  return null;
80
- const id = normalizeAcceptanceId(match[1]);
90
+ const [, rawId] = match;
91
+ if (rawId === undefined)
92
+ return null;
93
+ const id = normalizeAcceptanceId(rawId);
81
94
  // Bold-wrapped ids leave their closing marker inside the captured text
82
95
  // ("**AC-FE-INS-001**:xxx" captures "**:xxx"); strip emphasis remnants
83
96
  // and leading separators so the bound text is clean prose.
@@ -154,13 +167,17 @@ function isAtxHeading(line) {
154
167
  const match = /^(#{1,6})\s+(.+?)\s*$/u.exec(line);
155
168
  if (!match)
156
169
  return null;
157
- return { level: match[1].length, text: match[2] };
170
+ const [, hashes, text] = match;
171
+ if (hashes === undefined || text === undefined)
172
+ return null;
173
+ return { level: hashes.length, text };
158
174
  }
159
175
  function parseListItem(line) {
160
176
  const match = /^\s*(?:[-*+]|\d+[.)])\s+(?:\[(?: |x|X)\]\s+)?(.+?)\s*$/u.exec(line);
161
177
  if (!match)
162
178
  return null;
163
- return match[1].trim();
179
+ const [, item] = match;
180
+ return item === undefined ? null : item.trim();
164
181
  }
165
182
  function parseAcceptanceLine(line, nextId) {
166
183
  const checklist = /^\s*[-*+]\s+\[(?: |x|X)\]\s+(.+?)\s*$/u.exec(line);
@@ -173,14 +190,20 @@ function parseAcceptanceLine(line, nextId) {
173
190
  return embedded;
174
191
  const withId = /^(AC[-_]?\d+)\s*[::]\s*(.+)$/iu.exec(body);
175
192
  if (withId) {
176
- return { id: normalizeAcceptanceId(withId[1]), text: withId[2].trim() };
193
+ const [, rawId, rawText] = withId;
194
+ if (rawId !== undefined && rawText !== undefined) {
195
+ return { id: normalizeAcceptanceId(rawId), text: rawText.trim() };
196
+ }
177
197
  }
178
198
  const bareAc = /^(AC[-_]?\d+)\s+(.+)$/iu.exec(body);
179
199
  if (bareAc) {
180
- return {
181
- id: normalizeAcceptanceId(bareAc[1]),
182
- text: bareAc[2].trim(),
183
- };
200
+ const [, rawId, rawText] = bareAc;
201
+ if (rawId !== undefined && rawText !== undefined) {
202
+ return {
203
+ id: normalizeAcceptanceId(rawId),
204
+ text: rawText.trim(),
205
+ };
206
+ }
184
207
  }
185
208
  return { id: nextId(), text: body };
186
209
  }
@@ -395,7 +418,9 @@ export function mergeAcceptanceCriteria(parts) {
395
418
  for (const id of order) {
396
419
  const texts = [...(byId.get(id) ?? [])];
397
420
  if (texts.length === 1) {
398
- items.push({ id, text: texts[0] });
421
+ const [onlyText] = texts;
422
+ if (onlyText !== undefined)
423
+ items.push({ id, text: onlyText });
399
424
  }
400
425
  else if (texts.length > 1) {
401
426
  conflicts.push({ id, texts });
@@ -102,11 +102,14 @@ function stripOutOfScopeSections(markdown) {
102
102
  for (const line of markdown.split(/\r?\n/)) {
103
103
  const heading = /^(#{1,6})\s+(.+?)\s*$/.exec(line.trim());
104
104
  if (heading) {
105
- const level = heading[1].length;
105
+ const [, hashes, title] = heading;
106
+ if (hashes === undefined || title === undefined)
107
+ continue;
108
+ const level = hashes.length;
106
109
  if (skippedHeadingLevel !== null && level <= skippedHeadingLevel) {
107
110
  skippedHeadingLevel = null;
108
111
  }
109
- if (OUT_OF_SCOPE_HEADING.test(heading[2].trim())) {
112
+ if (OUT_OF_SCOPE_HEADING.test(title.trim())) {
110
113
  skippedHeadingLevel = level;
111
114
  continue;
112
115
  }