@pluno/product-agent-web 0.1.211 → 0.1.213
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/product-agent-runtime.cjs +1 -1
- package/dist/product-agent-runtime.js +192 -175
- package/dist/product-agent-sdk.js +85 -68
- package/dist/product-agent-widget.js +1963 -1909
- package/dist/runtimeClient.d.ts +1 -0
- package/dist/uiInvariants.d.ts +4 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
function h(
|
|
1
|
+
function h(i) {
|
|
2
2
|
return {
|
|
3
|
-
key:
|
|
3
|
+
key: i,
|
|
4
4
|
status: "not_requested",
|
|
5
5
|
data: null,
|
|
6
6
|
error: null,
|
|
@@ -9,8 +9,8 @@ function h(s) {
|
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
11
|
class b {
|
|
12
|
-
constructor(e, t,
|
|
13
|
-
this.loader = t, this.merge =
|
|
12
|
+
constructor(e, t, s = (n, r) => r) {
|
|
13
|
+
this.loader = t, this.merge = s, this.state = h(e);
|
|
14
14
|
}
|
|
15
15
|
loader;
|
|
16
16
|
merge;
|
|
@@ -52,16 +52,16 @@ class b {
|
|
|
52
52
|
for (; this.trailingLoad; ) {
|
|
53
53
|
const e = this.trailingLoad;
|
|
54
54
|
this.trailingLoad = null;
|
|
55
|
-
const t = this.state.key,
|
|
55
|
+
const t = this.state.key, s = this.state.requestId + 1;
|
|
56
56
|
this.state = {
|
|
57
57
|
...this.state,
|
|
58
58
|
status: e.mode === "append" ? "loading_more" : this.state.data === null ? "loading" : "refreshing",
|
|
59
59
|
error: null,
|
|
60
|
-
requestId:
|
|
60
|
+
requestId: s
|
|
61
61
|
}, this.publish();
|
|
62
62
|
try {
|
|
63
63
|
const n = await this.loader({ key: t, cursor: e.cursor });
|
|
64
|
-
if (t !== this.state.key ||
|
|
64
|
+
if (t !== this.state.key || s !== this.state.requestId) continue;
|
|
65
65
|
this.state = {
|
|
66
66
|
...this.state,
|
|
67
67
|
status: "ready",
|
|
@@ -70,7 +70,7 @@ class b {
|
|
|
70
70
|
updatedAt: Date.now()
|
|
71
71
|
}, this.publish();
|
|
72
72
|
} catch (n) {
|
|
73
|
-
if (t !== this.state.key ||
|
|
73
|
+
if (t !== this.state.key || s !== this.state.requestId) continue;
|
|
74
74
|
this.state = {
|
|
75
75
|
...this.state,
|
|
76
76
|
status: "error",
|
|
@@ -83,53 +83,53 @@ class b {
|
|
|
83
83
|
for (const e of this.listeners) e(this.state);
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
-
function p(
|
|
86
|
+
function p(i) {
|
|
87
87
|
const e = {}, t = [];
|
|
88
|
-
for (const
|
|
89
|
-
e[
|
|
88
|
+
for (const s of i.entities)
|
|
89
|
+
e[s.id] || t.push(s.id), e[s.id] = s;
|
|
90
90
|
return {
|
|
91
91
|
entitiesById: e,
|
|
92
92
|
ids: t,
|
|
93
|
-
nextCursor:
|
|
93
|
+
nextCursor: i.nextCursor
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
|
-
function
|
|
97
|
-
if (t === "replace" ||
|
|
98
|
-
const
|
|
96
|
+
function E(i, e, t) {
|
|
97
|
+
if (t === "replace" || i === null) return e;
|
|
98
|
+
const s = { ...i.entitiesById, ...e.entitiesById }, n = [...i.ids];
|
|
99
99
|
for (const r of e.ids)
|
|
100
|
-
|
|
101
|
-
return { entitiesById:
|
|
100
|
+
i.entitiesById[r] || n.push(r);
|
|
101
|
+
return { entitiesById: s, ids: n, nextCursor: e.nextCursor };
|
|
102
102
|
}
|
|
103
|
-
function w(
|
|
104
|
-
return
|
|
103
|
+
function w(i) {
|
|
104
|
+
return i ? i.ids.map((e) => i.entitiesById[e]).filter((e) => !!e) : [];
|
|
105
105
|
}
|
|
106
|
-
function
|
|
107
|
-
return
|
|
106
|
+
function R(i) {
|
|
107
|
+
return i.visible ? i.minimized ? { state: "minimized" } : { state: i.open ? "visible_open" : "visible_closed" } : { state: "hidden" };
|
|
108
108
|
}
|
|
109
|
-
function
|
|
110
|
-
return e === "limit_exceeded" ? { allowed: !1, reason: "credits_exhausted", actions: ["upgrade", "earn_credits"] } : e === "subscription_required" || e === "subscription_inactive" || e === "payment_issue" || e === "subscription_invalid" || e === "payment_required" ? { allowed: !1, reason: "payment_issue", actions: ["upgrade"] } :
|
|
109
|
+
function C(i, e) {
|
|
110
|
+
return e === "limit_exceeded" ? { allowed: !1, reason: "credits_exhausted", actions: ["upgrade", "earn_credits"] } : e === "subscription_required" || e === "subscription_inactive" || e === "payment_issue" || e === "subscription_invalid" || e === "payment_required" ? { allowed: !1, reason: "payment_issue", actions: ["upgrade"] } : i ?? { allowed: !0, reason: "allowed", actions: [] };
|
|
111
111
|
}
|
|
112
|
-
function
|
|
113
|
-
if (!
|
|
114
|
-
const e =
|
|
112
|
+
function L(i) {
|
|
113
|
+
if (!i || typeof i != "object") return !1;
|
|
114
|
+
const e = i.paidCreditFallbackModel;
|
|
115
115
|
return typeof e == "string" && e.length > 0;
|
|
116
116
|
}
|
|
117
|
-
function q(
|
|
118
|
-
return
|
|
117
|
+
function q(i) {
|
|
118
|
+
return i ? i.submissionGate?.allowed === !1 ? { state: "action_required", reason: i.submissionGate.reason } : i.usingPaidCreditFallback === !0 ? { state: "paid_credit_fallback" } : i.creditLimit !== null && i.creditLimit > 0 && i.creditsRemaining !== null && i.creditsRemaining > 0 && i.creditsRemaining / i.creditLimit <= 0.2 ? { state: "low_credits" } : i.creditsUsed !== null ? { state: "usage" } : { state: "hidden" } : { state: "hidden" };
|
|
119
119
|
}
|
|
120
|
-
function Q(
|
|
121
|
-
const e =
|
|
122
|
-
return
|
|
120
|
+
function Q(i) {
|
|
121
|
+
const e = i.hasDraftMessage || i.hasPreSubmittedAttachment;
|
|
122
|
+
return i.hasRunningAssistantTurn && !e ? {
|
|
123
123
|
action: "stop",
|
|
124
|
-
disabled: !
|
|
124
|
+
disabled: !i.canStopRunningTurn
|
|
125
125
|
} : {
|
|
126
126
|
action: "send",
|
|
127
|
-
disabled: !e || !
|
|
127
|
+
disabled: !e || !i.canSubmitMessage
|
|
128
128
|
};
|
|
129
129
|
}
|
|
130
130
|
class $ {
|
|
131
|
-
constructor(e, t,
|
|
132
|
-
this.loadPage = t, this.limit =
|
|
131
|
+
constructor(e, t, s = 20) {
|
|
132
|
+
this.loadPage = t, this.limit = s, this.recentQuery = new b(
|
|
133
133
|
`${e}:recent`,
|
|
134
134
|
async ({ cursor: n }) => p(
|
|
135
135
|
await this.loadPage({ cursor: n, limit: this.limit, pinned: !1 }).then((r) => ({
|
|
@@ -137,7 +137,7 @@ class $ {
|
|
|
137
137
|
nextCursor: r.nextCursor
|
|
138
138
|
}))
|
|
139
139
|
),
|
|
140
|
-
|
|
140
|
+
E
|
|
141
141
|
), this.pinnedQuery = new b(
|
|
142
142
|
`${e}:pinned`,
|
|
143
143
|
async () => p({
|
|
@@ -159,10 +159,10 @@ class $ {
|
|
|
159
159
|
completedRefreshSequence = 0;
|
|
160
160
|
activityReconciliationScheduled = !1;
|
|
161
161
|
getState() {
|
|
162
|
-
const e = this.recentQuery.getState(), t = this.pinnedQuery.getState(),
|
|
162
|
+
const e = this.recentQuery.getState(), t = this.pinnedQuery.getState(), s = [
|
|
163
163
|
...u(t.data),
|
|
164
164
|
...u(e.data)
|
|
165
|
-
], n = new Map(
|
|
165
|
+
], n = new Map(s.map((o) => [o.id, o])), r = Array.from(n.values()).map(
|
|
166
166
|
(o) => this.applyOverrides(o, this.completedRefreshSequence)
|
|
167
167
|
), a = Array.from(this.optimisticEntities.values()).filter((o) => !n.has(o.id)).reverse(), l = e.data || t.data || a.length > 0 ? p({
|
|
168
168
|
entities: [...a, ...r],
|
|
@@ -170,7 +170,7 @@ class $ {
|
|
|
170
170
|
}) : null;
|
|
171
171
|
return {
|
|
172
172
|
key: e.key.slice(0, -7),
|
|
173
|
-
status:
|
|
173
|
+
status: _(e, t),
|
|
174
174
|
data: l,
|
|
175
175
|
error: e.error ?? t.error,
|
|
176
176
|
requestId: Math.max(e.requestId, t.requestId),
|
|
@@ -216,20 +216,20 @@ class $ {
|
|
|
216
216
|
isActive: t,
|
|
217
217
|
confirmAfterRefresh: this.completedRefreshSequence + 1,
|
|
218
218
|
releaseAfterRefresh: this.completedRefreshSequence + 2
|
|
219
|
-
}), this.updateEntity(e, (
|
|
219
|
+
}), this.updateEntity(e, (s) => ({ ...s, isActive: t }));
|
|
220
220
|
}
|
|
221
221
|
setPinned(e, t) {
|
|
222
|
-
const
|
|
223
|
-
return this.pinnedOverrides.set(e,
|
|
222
|
+
const s = { pinned: t, confirmAfterRefresh: Number.POSITIVE_INFINITY };
|
|
223
|
+
return this.pinnedOverrides.set(e, s), this.updateEntity(e, (n) => ({ ...n, isPinned: t })), s;
|
|
224
224
|
}
|
|
225
225
|
confirmPinned(e, t) {
|
|
226
226
|
this.pinnedOverrides.get(e) === t && (t.confirmAfterRefresh = this.completedRefreshSequence + 1);
|
|
227
227
|
}
|
|
228
|
-
rollbackPinned(e, t,
|
|
229
|
-
this.pinnedOverrides.get(e) === t && (this.pinnedOverrides.delete(e), this.updateEntity(e, (n) => ({ ...n, isPinned:
|
|
228
|
+
rollbackPinned(e, t, s) {
|
|
229
|
+
this.pinnedOverrides.get(e) === t && (this.pinnedOverrides.delete(e), this.updateEntity(e, (n) => ({ ...n, isPinned: s })));
|
|
230
230
|
}
|
|
231
231
|
setTitle(e, t) {
|
|
232
|
-
this.titleOverrides.set(e, t), this.updateEntity(e, (
|
|
232
|
+
this.titleOverrides.set(e, t), this.updateEntity(e, (s) => ({ ...s, customTitle: t }));
|
|
233
233
|
}
|
|
234
234
|
confirmTitle(e) {
|
|
235
235
|
this.titleOverrides.delete(e);
|
|
@@ -238,34 +238,34 @@ class $ {
|
|
|
238
238
|
const e = [
|
|
239
239
|
...u(this.pinnedQuery.getState().data),
|
|
240
240
|
...u(this.recentQuery.getState().data)
|
|
241
|
-
], t = new Set(e.map((
|
|
242
|
-
for (const
|
|
243
|
-
t.has(
|
|
244
|
-
for (const
|
|
241
|
+
], t = new Set(e.map((s) => s.id));
|
|
242
|
+
for (const s of this.optimisticEntities.keys())
|
|
243
|
+
t.has(s) && this.optimisticEntities.delete(s);
|
|
244
|
+
for (const s of e) this.applyOverrides(s, this.completedRefreshSequence);
|
|
245
245
|
this.publish();
|
|
246
246
|
}
|
|
247
247
|
async loadAllPinned() {
|
|
248
248
|
const e = [];
|
|
249
249
|
let t = null;
|
|
250
250
|
do {
|
|
251
|
-
const
|
|
252
|
-
e.push(...
|
|
251
|
+
const s = await this.loadPage({ cursor: t, limit: this.limit, pinned: !0 });
|
|
252
|
+
e.push(...s.sessions), t = s.nextCursor;
|
|
253
253
|
} while (t);
|
|
254
254
|
return e;
|
|
255
255
|
}
|
|
256
256
|
applyOverrides(e, t) {
|
|
257
|
-
let
|
|
257
|
+
let s = e;
|
|
258
258
|
const n = this.activityOverrides.get(e.id);
|
|
259
|
-
n && (t >= n.confirmAfterRefresh && e.isActive === n.isActive ? this.activityOverrides.delete(e.id) : t >= n.releaseAfterRefresh ? this.activityOverrides.delete(e.id) :
|
|
259
|
+
n && (t >= n.confirmAfterRefresh && e.isActive === n.isActive ? this.activityOverrides.delete(e.id) : t >= n.releaseAfterRefresh ? this.activityOverrides.delete(e.id) : s = { ...s, isActive: n.isActive });
|
|
260
260
|
const r = this.pinnedOverrides.get(e.id);
|
|
261
|
-
return r && (t >= r.confirmAfterRefresh && e.isPinned === !0 === r.pinned ? this.pinnedOverrides.delete(e.id) :
|
|
261
|
+
return r && (t >= r.confirmAfterRefresh && e.isPinned === !0 === r.pinned ? this.pinnedOverrides.delete(e.id) : s = { ...s, isPinned: r.pinned }), this.titleOverrides.has(e.id) && (s = { ...s, customTitle: this.titleOverrides.get(e.id) ?? null }), s;
|
|
262
262
|
}
|
|
263
263
|
updateProjection() {
|
|
264
264
|
this.publish();
|
|
265
265
|
}
|
|
266
266
|
updateEntity(e, t) {
|
|
267
|
-
const
|
|
268
|
-
|
|
267
|
+
const s = this.optimisticEntities.get(e);
|
|
268
|
+
s && this.optimisticEntities.set(e, t(s)), this.publish();
|
|
269
269
|
}
|
|
270
270
|
hasUnconfirmedActivityOverride() {
|
|
271
271
|
return Array.from(this.activityOverrides.values()).some(
|
|
@@ -276,16 +276,16 @@ class $ {
|
|
|
276
276
|
for (const e of this.listeners) e(this.getState());
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
|
-
function u(
|
|
280
|
-
return
|
|
279
|
+
function u(i) {
|
|
280
|
+
return i ? i.ids.map((e) => i.entitiesById[e]).filter((e) => !!e) : [];
|
|
281
281
|
}
|
|
282
|
-
function
|
|
283
|
-
return
|
|
282
|
+
function _(i, e) {
|
|
283
|
+
return i.status === "error" || e.status === "error" ? "error" : i.status === "loading" || e.status === "loading" ? "loading" : i.status === "refreshing" || e.status === "refreshing" ? "refreshing" : i.status === "loading_more" ? "loading_more" : i.status === "ready" || e.status === "ready" ? "ready" : "not_requested";
|
|
284
284
|
}
|
|
285
285
|
class K {
|
|
286
286
|
constructor(e, t = null) {
|
|
287
287
|
this.storage = e, t && (this.decisions = new Map(
|
|
288
|
-
t.filter(
|
|
288
|
+
t.filter(y).map((s) => [this.getDecisionKey(s), s])
|
|
289
289
|
), this.initialized = !0);
|
|
290
290
|
}
|
|
291
291
|
storage;
|
|
@@ -297,102 +297,102 @@ class K {
|
|
|
297
297
|
if (this.initialized) return;
|
|
298
298
|
const e = await this.storage.load();
|
|
299
299
|
this.decisions = new Map(
|
|
300
|
-
e.filter(
|
|
300
|
+
e.filter(y).map((t) => [this.getDecisionKey(t), t])
|
|
301
301
|
), this.initialized = !0;
|
|
302
302
|
}
|
|
303
303
|
isEligible(e, t = Date.now()) {
|
|
304
|
-
const
|
|
305
|
-
return
|
|
304
|
+
const s = this.scheduledEligibility.get(this.getExactKey(e));
|
|
305
|
+
return s !== void 0 && s > t ? !1 : this.isDecisionEligible(this.decisions.get(this.getExactKey(e)), t) && this.isDecisionEligible(this.decisions.get(this.getCategoryKey(e)), t);
|
|
306
306
|
}
|
|
307
307
|
getDecision(e) {
|
|
308
308
|
return this.decisions.get(this.getExactKey(e)) ?? this.decisions.get(this.getCategoryKey(e)) ?? null;
|
|
309
309
|
}
|
|
310
310
|
getStatus(e, t = Date.now()) {
|
|
311
|
-
const
|
|
312
|
-
if (
|
|
311
|
+
const s = this.scheduledEligibility.get(this.getExactKey(e));
|
|
312
|
+
if (s !== void 0 && s > t) return "scheduled";
|
|
313
313
|
const n = this.getDecision(e);
|
|
314
314
|
return n ? n.action === "never" || n.action === "dont_show_again" ? "suppressed" : n.action === "dismiss" ? "resolved" : n.nextEligibleAt && Date.parse(n.nextEligibleAt) > t ? "snoozed" : "presentable" : "presentable";
|
|
315
315
|
}
|
|
316
316
|
scheduleEligibility(e, t) {
|
|
317
|
-
const
|
|
318
|
-
return n !== void 0 ? n : (this.scheduledEligibility.set(
|
|
317
|
+
const s = this.getExactKey(e), n = this.scheduledEligibility.get(s);
|
|
318
|
+
return n !== void 0 ? n : (this.scheduledEligibility.set(s, t), t);
|
|
319
319
|
}
|
|
320
320
|
getNextEligibilityAt(e = Date.now()) {
|
|
321
|
-
for (const [
|
|
322
|
-
n <= e && this.scheduledEligibility.delete(
|
|
321
|
+
for (const [s, n] of this.scheduledEligibility)
|
|
322
|
+
n <= e && this.scheduledEligibility.delete(s);
|
|
323
323
|
const t = [
|
|
324
324
|
...this.scheduledEligibility.values(),
|
|
325
|
-
...Array.from(this.decisions.values()).map((
|
|
325
|
+
...Array.from(this.decisions.values()).map((s) => s.nextEligibleAt ? Date.parse(s.nextEligibleAt) : Number.NaN).filter((s) => Number.isFinite(s) && s > e)
|
|
326
326
|
];
|
|
327
327
|
return t.length > 0 ? Math.min(...t) : null;
|
|
328
328
|
}
|
|
329
|
-
act(e, t,
|
|
330
|
-
const n = this.actionQueue.then(() => this.applyAction(e, t,
|
|
329
|
+
act(e, t, s = {}) {
|
|
330
|
+
const n = this.actionQueue.then(() => this.applyAction(e, t, s));
|
|
331
331
|
return this.actionQueue = n.then(() => {
|
|
332
332
|
}, () => {
|
|
333
333
|
}), n;
|
|
334
334
|
}
|
|
335
|
-
async applyAction(e, t,
|
|
335
|
+
async applyAction(e, t, s) {
|
|
336
336
|
if (!e.allowedActions.includes(t))
|
|
337
337
|
throw new Error(`Interaction ${e.key} does not allow ${t}.`);
|
|
338
|
-
if (!
|
|
338
|
+
if (!I(t))
|
|
339
339
|
throw new Error(`Interaction action ${t} is not a persistence decision.`);
|
|
340
|
-
const n =
|
|
340
|
+
const n = s.now ?? /* @__PURE__ */ new Date(), r = {
|
|
341
341
|
promptKey: e.key,
|
|
342
342
|
category: e.category,
|
|
343
343
|
action: t,
|
|
344
344
|
scope: e.scope,
|
|
345
345
|
decidedAt: n.toISOString(),
|
|
346
|
-
nextEligibleAt: this.getNextEligibleAt(e, t, n,
|
|
346
|
+
nextEligibleAt: this.getNextEligibleAt(e, t, n, s.snoozeUntil)
|
|
347
347
|
}, a = t === "dont_show_again" ? this.getCategoryKey(e) : this.getExactKey(e), l = new Map(this.decisions);
|
|
348
348
|
return l.set(a, r), await this.storage.save([...l.values()]), this.decisions = l, r;
|
|
349
349
|
}
|
|
350
350
|
isDecisionEligible(e, t) {
|
|
351
351
|
return e ? e.action === "dismiss" || e.action === "never" || e.action === "dont_show_again" ? !1 : !e.nextEligibleAt || Date.parse(e.nextEligibleAt) <= t : !0;
|
|
352
352
|
}
|
|
353
|
-
getNextEligibleAt(e, t,
|
|
353
|
+
getNextEligibleAt(e, t, s, n) {
|
|
354
354
|
if (t === "later")
|
|
355
|
-
return new Date(
|
|
355
|
+
return new Date(s.getTime() + (e.laterDelayMs ?? 3600 * 1e3)).toISOString();
|
|
356
356
|
if (t === "snooze") {
|
|
357
|
-
if (!n || n.getTime() <=
|
|
357
|
+
if (!n || n.getTime() <= s.getTime())
|
|
358
358
|
throw new Error("Snooze requires a future next-eligible time.");
|
|
359
359
|
return n.toISOString();
|
|
360
360
|
}
|
|
361
361
|
return null;
|
|
362
362
|
}
|
|
363
363
|
getDecisionKey(e) {
|
|
364
|
-
const t =
|
|
364
|
+
const t = m(e.scope);
|
|
365
365
|
return e.action === "dont_show_again" ? `${t}:category:${e.category}` : `${t}:interaction:${e.promptKey}`;
|
|
366
366
|
}
|
|
367
367
|
getExactKey(e) {
|
|
368
|
-
return `${
|
|
368
|
+
return `${m(e.scope)}:interaction:${e.key}`;
|
|
369
369
|
}
|
|
370
370
|
getCategoryKey(e) {
|
|
371
|
-
return `${
|
|
371
|
+
return `${m(e.scope)}:category:${e.category}`;
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
|
-
function F(
|
|
374
|
+
function F(i, e) {
|
|
375
375
|
return {
|
|
376
|
-
load: async () => P(
|
|
377
|
-
save: async (t) =>
|
|
376
|
+
load: async () => P(i, e),
|
|
377
|
+
save: async (t) => i.setItem(e, JSON.stringify(t))
|
|
378
378
|
};
|
|
379
379
|
}
|
|
380
|
-
function P(
|
|
381
|
-
const t =
|
|
380
|
+
function P(i, e) {
|
|
381
|
+
const t = i.getItem(e);
|
|
382
382
|
if (!t) return [];
|
|
383
|
-
const
|
|
384
|
-
return Array.isArray(
|
|
383
|
+
const s = JSON.parse(t);
|
|
384
|
+
return Array.isArray(s) ? s.filter(y) : [];
|
|
385
385
|
}
|
|
386
|
-
function
|
|
387
|
-
return `${
|
|
386
|
+
function m(i) {
|
|
387
|
+
return `${i.level}:${i.key}`;
|
|
388
388
|
}
|
|
389
|
-
function
|
|
390
|
-
return
|
|
389
|
+
function I(i) {
|
|
390
|
+
return i === "dismiss" || i === "later" || i === "snooze" || i === "never" || i === "dont_show_again";
|
|
391
391
|
}
|
|
392
|
-
function
|
|
393
|
-
if (!
|
|
394
|
-
const e =
|
|
395
|
-
return typeof e.promptKey == "string" && typeof e.category == "string" && typeof e.decidedAt == "string" && (e.nextEligibleAt === null || typeof e.nextEligibleAt == "string") &&
|
|
392
|
+
function y(i) {
|
|
393
|
+
if (!i || typeof i != "object") return !1;
|
|
394
|
+
const e = i;
|
|
395
|
+
return typeof e.promptKey == "string" && typeof e.category == "string" && typeof e.decidedAt == "string" && (e.nextEligibleAt === null || typeof e.nextEligibleAt == "string") && I(e.action) && !!(e.scope && typeof e.scope == "object" && typeof e.scope.level == "string" && typeof e.scope.key == "string");
|
|
396
396
|
}
|
|
397
397
|
const T = {
|
|
398
398
|
working: "⏳",
|
|
@@ -400,10 +400,10 @@ const T = {
|
|
|
400
400
|
failed: "❗",
|
|
401
401
|
stopped: "⏹️"
|
|
402
402
|
}, M = /^(?:⌛|⏳|✅|❗|⏹️) Pluno(?:: )?/;
|
|
403
|
-
function D(
|
|
404
|
-
if (!e) return g(
|
|
405
|
-
const t = g(
|
|
406
|
-
return t ? `${
|
|
403
|
+
function D(i, e) {
|
|
404
|
+
if (!e) return g(i);
|
|
405
|
+
const t = g(i), s = `${T[e]} Pluno`;
|
|
406
|
+
return t ? `${s}: ${t}` : s;
|
|
407
407
|
}
|
|
408
408
|
class z {
|
|
409
409
|
constructor(e) {
|
|
@@ -422,16 +422,16 @@ class z {
|
|
|
422
422
|
this.liveStatusVersion += 1, this.applyClear();
|
|
423
423
|
}
|
|
424
424
|
async syncStatus(e) {
|
|
425
|
-
const t = this.liveStatusVersion,
|
|
426
|
-
|
|
425
|
+
const t = this.liveStatusVersion, s = await e();
|
|
426
|
+
s === void 0 || t !== this.liveStatusVersion || (s ? this.applyStatus(s) : this.applyClear());
|
|
427
427
|
}
|
|
428
428
|
applyStatus(e) {
|
|
429
429
|
const t = this.titleDocument.getTitle();
|
|
430
430
|
t !== this.lastAppliedTitle && (this.baseTitle = g(t)), this.status = e, this.stopObserving || (this.stopObserving = this.titleDocument.observeTitle(() => this.handleTitleChanged())), this.applyTitle();
|
|
431
431
|
}
|
|
432
432
|
applyClear() {
|
|
433
|
-
const e = this.titleDocument.getTitle(), t = this.lastAppliedTitle !== null && e === this.lastAppliedTitle,
|
|
434
|
-
this.status = null, this.lastAppliedTitle = null, this.stopObserving?.(), this.stopObserving = null, t ? this.titleDocument.setTitle(this.baseTitle) :
|
|
433
|
+
const e = this.titleDocument.getTitle(), t = this.lastAppliedTitle !== null && e === this.lastAppliedTitle, s = this.lastAppliedTitle === null ? g(e) : e;
|
|
434
|
+
this.status = null, this.lastAppliedTitle = null, this.stopObserving?.(), this.stopObserving = null, t ? this.titleDocument.setTitle(this.baseTitle) : s !== e && this.titleDocument.setTitle(s);
|
|
435
435
|
}
|
|
436
436
|
handleTitleChanged() {
|
|
437
437
|
!this.status || this.titleDocument.getTitle() === this.lastAppliedTitle || this.applyTitle();
|
|
@@ -443,15 +443,15 @@ class z {
|
|
|
443
443
|
this.lastAppliedTitle = e, this.titleDocument.getTitle() !== e && this.titleDocument.setTitle(e);
|
|
444
444
|
}
|
|
445
445
|
}
|
|
446
|
-
function B(
|
|
446
|
+
function B(i) {
|
|
447
447
|
return {
|
|
448
|
-
getTitle: () =>
|
|
448
|
+
getTitle: () => i.title,
|
|
449
449
|
setTitle: (e) => {
|
|
450
|
-
|
|
450
|
+
i.title = e;
|
|
451
451
|
},
|
|
452
452
|
observeTitle: (e) => {
|
|
453
453
|
const t = new MutationObserver(e);
|
|
454
|
-
return t.observe(
|
|
454
|
+
return t.observe(i.head, {
|
|
455
455
|
childList: !0,
|
|
456
456
|
subtree: !0,
|
|
457
457
|
characterData: !0
|
|
@@ -459,15 +459,15 @@ function B(s) {
|
|
|
459
459
|
}
|
|
460
460
|
};
|
|
461
461
|
}
|
|
462
|
-
function g(
|
|
463
|
-
return
|
|
462
|
+
function g(i) {
|
|
463
|
+
return i.replace(M, "");
|
|
464
464
|
}
|
|
465
|
-
const
|
|
466
|
-
function
|
|
467
|
-
const e =
|
|
468
|
-
return e.length >
|
|
465
|
+
const S = 500;
|
|
466
|
+
function k(i) {
|
|
467
|
+
const e = i.replace(/\n\s*at\s[\s\S]*$/, "").replace(/-----BEGIN [^-]*PRIVATE KEY-----[\s\S]*?(?:-----END [^-]*PRIVATE KEY-----|$)/g, "[REDACTED]").replace(/\b(?:set-cookie|cookie)\s*[:=]\s*[^\n]+/gi, "cookie=[REDACTED]").replace(/\bdata:[^\s<>"']+/gi, "[DATA]").replace(/\b(?:https?:\/\/|www\.)[^\s<>"']+/gi, "[URL]").replace(/\b(?:Bearer|Basic)\s+[^\s,;"']+/gi, "[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)?/g, "[REDACTED]").replace(/\b(?:sk|pk|ghp|gho|github_pat|xoxb|xoxp)[-_][A-Za-z0-9_-]{8,}/g, "[REDACTED]").replace(/\b((?:access|refresh|id|auth)[_-]?token|api[_-]?key|client[_-]?secret|password|passwd|pwd|secret|token|jwt|authorization|cookie|set-cookie)\b["']?\s*[:=]\s*(?:"[^"]*"|'[^']*'|[^\s,;}&]+)/gi, "$1=[REDACTED]").replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, "[EMAIL]").replace(/(?:[A-Z]:[\\/]|\\\\|(?:~|\.\.?)?\/|[\w.-]+[\\/])[^\s<>"']+/gi, "[FILE]").replace(new RegExp("(?<![\\w.])(?:[\\w.-]+\\.[A-Z][A-Z0-9]{0,15}|\\.[A-Z][\\w.-]*)\\b", "gi"), "[FILE]").replace(/\s+/g, " ").trim();
|
|
468
|
+
return e.length > S ? `${e.slice(0, S - 1)}…` : e;
|
|
469
469
|
}
|
|
470
|
-
const
|
|
470
|
+
const O = {
|
|
471
471
|
"duplicate-message-item": "A canonical message rendered more than once.",
|
|
472
472
|
"duplicate-canonical-item": "A canonical session item rendered more than once.",
|
|
473
473
|
"duplicate-tool-call": "A tool call rendered more than once.",
|
|
@@ -476,14 +476,16 @@ const x = {
|
|
|
476
476
|
"foreign-session-item-visible": "The visible transcript contains state owned by another session.",
|
|
477
477
|
"terminal-response-reactivated": "A terminal response became active again.",
|
|
478
478
|
"terminal-history-not-append-only": "An established terminal outcome disappeared or changed order.",
|
|
479
|
-
"runtime-transcript-not-rendered": "A nonempty runtime transcript is displaying starter prompts."
|
|
479
|
+
"runtime-transcript-not-rendered": "A nonempty runtime transcript is displaying starter prompts.",
|
|
480
|
+
"thinking-groups-without-user-message": "Multiple thinking groups appeared without a user message between them.",
|
|
481
|
+
"thinking-without-progress": "Thinking remained visible without progress for five minutes."
|
|
480
482
|
};
|
|
481
|
-
function
|
|
482
|
-
return typeof
|
|
483
|
+
function x(i) {
|
|
484
|
+
return typeof i == "string" && i.startsWith("ui_invariant:") && Object.prototype.hasOwnProperty.call(O, i.slice(13));
|
|
483
485
|
}
|
|
484
|
-
function N(
|
|
485
|
-
if (!
|
|
486
|
-
const e =
|
|
486
|
+
function N(i) {
|
|
487
|
+
if (!i || typeof i != "object" || !("type" in i)) return !1;
|
|
488
|
+
const e = i;
|
|
487
489
|
switch (e.type) {
|
|
488
490
|
case "runtime.connect":
|
|
489
491
|
case "session.new":
|
|
@@ -495,7 +497,7 @@ function N(s) {
|
|
|
495
497
|
case "runtime.report_displayed_error":
|
|
496
498
|
return (e.reason === "conversation_error" || e.reason === "attachment_error" || e.reason === "history_error" || e.reason === "action_error") && typeof e.errorFingerprint == "string" && /^fnv1a-[0-9a-f]{8}$/.test(e.errorFingerprint) && (e.displayedMessage === void 0 || typeof e.displayedMessage == "string" && e.displayedMessage.length <= 500);
|
|
497
499
|
case "runtime.report_invalid_state_transition":
|
|
498
|
-
return (e.reason === "submitted_turn_returned_to_welcome_without_new_chat" || e.reason === "new_messages_button_without_user_scroll" ||
|
|
500
|
+
return (e.reason === "submitted_turn_returned_to_welcome_without_new_chat" || e.reason === "new_messages_button_without_user_scroll" || x(e.reason)) && (e.clientMessageId === void 0 || typeof e.clientMessageId == "string");
|
|
499
501
|
case "runtime.widget_lifecycle":
|
|
500
502
|
return (e.action === "opened" || e.action === "closed" || e.action === "minimized") && typeof e.trigger == "string";
|
|
501
503
|
case "session.load":
|
|
@@ -523,8 +525,8 @@ function N(s) {
|
|
|
523
525
|
}
|
|
524
526
|
}
|
|
525
527
|
class H {
|
|
526
|
-
constructor(e, t,
|
|
527
|
-
this.adapter = t, this.state =
|
|
528
|
+
constructor(e, t, s) {
|
|
529
|
+
this.adapter = t, this.state = f(e), this.model = s;
|
|
528
530
|
}
|
|
529
531
|
adapter;
|
|
530
532
|
listeners = {};
|
|
@@ -538,19 +540,30 @@ class H {
|
|
|
538
540
|
interactions = [];
|
|
539
541
|
account = null;
|
|
540
542
|
stagedProactiveSuggestionClientMessageId = null;
|
|
543
|
+
unacknowledgedSubmissions = /* @__PURE__ */ new Map();
|
|
541
544
|
operationQueue = Promise.resolve();
|
|
542
545
|
destroyed = !1;
|
|
543
546
|
on(e, t) {
|
|
544
|
-
const
|
|
545
|
-
return
|
|
547
|
+
const s = this.listeners[e] ?? /* @__PURE__ */ new Set();
|
|
548
|
+
return s.add(t), this.listeners[e] = s, () => s.delete(t);
|
|
546
549
|
}
|
|
547
550
|
getState() {
|
|
548
|
-
return
|
|
551
|
+
return f(this.state);
|
|
549
552
|
}
|
|
550
|
-
updateProjection(e, t,
|
|
553
|
+
updateProjection(e, t, s, n, r) {
|
|
551
554
|
if (!this.destroyed) {
|
|
552
|
-
|
|
553
|
-
|
|
555
|
+
this.state = f(e);
|
|
556
|
+
for (const [a, l] of this.unacknowledgedSubmissions) {
|
|
557
|
+
if (e.user?.id !== l.userId || l.sessionId !== null && e.sessionId !== l.sessionId || e.messages.some(
|
|
558
|
+
(o) => o.clientMessageId === a
|
|
559
|
+
)) {
|
|
560
|
+
this.unacknowledgedSubmissions.delete(a);
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
563
|
+
l.sessionId ??= e.sessionId, this.state.messages.push(l.message), this.state.pendingMessageStatus = "sending", this.state.turnPhase ??= "sending", this.state.taskStatus ??= "working";
|
|
564
|
+
}
|
|
565
|
+
if (t !== void 0 && (this.model = t), s) {
|
|
566
|
+
this.sessionHistoryState = A(s);
|
|
554
567
|
for (const a of this.sessionHistoryListeners)
|
|
555
568
|
a(this.getSessionHistoryState());
|
|
556
569
|
}
|
|
@@ -570,7 +583,7 @@ class H {
|
|
|
570
583
|
}
|
|
571
584
|
destroy() {
|
|
572
585
|
if (!this.destroyed) {
|
|
573
|
-
this.destroyed = !0, this.attachmentFiles.clear(), this.sessionHistoryListeners.clear(), this.interactionListeners.clear(), this.accountListeners.clear();
|
|
586
|
+
this.destroyed = !0, this.unacknowledgedSubmissions.clear(), this.attachmentFiles.clear(), this.sessionHistoryListeners.clear(), this.interactionListeners.clear(), this.accountListeners.clear();
|
|
574
587
|
for (const e of Object.values(this.listeners)) e?.clear();
|
|
575
588
|
this.adapter.onDisconnect?.();
|
|
576
589
|
}
|
|
@@ -590,27 +603,31 @@ class H {
|
|
|
590
603
|
}).catch(() => {
|
|
591
604
|
});
|
|
592
605
|
}
|
|
593
|
-
reportDisplayedError(e, t,
|
|
606
|
+
reportDisplayedError(e, t, s) {
|
|
594
607
|
this.adapter.dispatch({
|
|
595
608
|
type: "runtime.report_displayed_error",
|
|
596
609
|
reason: e,
|
|
597
610
|
errorFingerprint: t,
|
|
598
|
-
...
|
|
611
|
+
...s ? { displayedMessage: k(s) } : {}
|
|
599
612
|
}).catch(() => {
|
|
600
613
|
});
|
|
601
614
|
}
|
|
602
615
|
sendMessage(e, t = {}) {
|
|
603
|
-
const
|
|
604
|
-
if (!
|
|
616
|
+
const s = e.trim(), n = t.attachments ?? [];
|
|
617
|
+
if (!s && n.length === 0) return Promise.resolve(null);
|
|
605
618
|
const r = t.clientMessageId ?? (t.proactiveSuggestionQuestion && this.stagedProactiveSuggestionClientMessageId ? this.stagedProactiveSuggestionClientMessageId : crypto.randomUUID()), a = t.submittedAt ?? Date.now(), l = this.state, o = {
|
|
606
619
|
id: `local-${r}`,
|
|
607
620
|
role: "user",
|
|
608
|
-
content:
|
|
621
|
+
content: s,
|
|
609
622
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
610
623
|
...n.length > 0 ? { attachments: n } : {},
|
|
611
624
|
clientMessageId: r
|
|
612
625
|
};
|
|
613
|
-
return this.
|
|
626
|
+
return this.unacknowledgedSubmissions.set(r, {
|
|
627
|
+
message: { ...o, attachments: o.attachments?.map((c) => ({ ...c })) },
|
|
628
|
+
sessionId: l.sessionId,
|
|
629
|
+
userId: l.user?.id
|
|
630
|
+
}), this.state = {
|
|
614
631
|
...this.state,
|
|
615
632
|
messages: [...this.state.messages, o],
|
|
616
633
|
pendingMessageStatus: "sending",
|
|
@@ -619,12 +636,12 @@ class H {
|
|
|
619
636
|
isRetrying: !1,
|
|
620
637
|
lastError: null
|
|
621
638
|
}, this.emit("state", this.getState()), this.enqueueOperation(() => this.sendMessageNow(
|
|
622
|
-
|
|
639
|
+
s,
|
|
623
640
|
{ ...t, clientMessageId: r, submittedAt: a },
|
|
624
641
|
l
|
|
625
642
|
));
|
|
626
643
|
}
|
|
627
|
-
async sendMessageNow(e, t,
|
|
644
|
+
async sendMessageNow(e, t, s) {
|
|
628
645
|
const n = e, r = t.clientMessageId;
|
|
629
646
|
let a = t.attachments ?? [], l = !1;
|
|
630
647
|
try {
|
|
@@ -663,15 +680,15 @@ class H {
|
|
|
663
680
|
c.id && this.attachmentFiles.delete(c.id);
|
|
664
681
|
return r === this.stagedProactiveSuggestionClientMessageId && (this.stagedProactiveSuggestionClientMessageId = null), o?.clientMessageId ?? r;
|
|
665
682
|
} catch (o) {
|
|
666
|
-
throw this.state = {
|
|
683
|
+
throw this.unacknowledgedSubmissions.delete(r), this.state = {
|
|
667
684
|
...this.state,
|
|
668
685
|
messages: this.state.messages.filter(
|
|
669
686
|
(c) => c.id !== `local-${r}` && c.id !== `optimistic-user-message:${r}`
|
|
670
687
|
),
|
|
671
|
-
pendingMessageStatus:
|
|
672
|
-
turnPhase:
|
|
673
|
-
isThinking:
|
|
674
|
-
taskStatus:
|
|
688
|
+
pendingMessageStatus: s.pendingMessageStatus,
|
|
689
|
+
turnPhase: s.turnPhase,
|
|
690
|
+
isThinking: s.isThinking,
|
|
691
|
+
taskStatus: s.taskStatus
|
|
675
692
|
}, this.emit("state", this.getState()), l && await this.adapter.dispatch({
|
|
676
693
|
type: "conversation.fail_staged",
|
|
677
694
|
clientMessageId: r,
|
|
@@ -699,11 +716,11 @@ class H {
|
|
|
699
716
|
};
|
|
700
717
|
}
|
|
701
718
|
stop() {
|
|
702
|
-
return this.dispatch({ type: "run.stop" }).then(() => {
|
|
719
|
+
return this.unacknowledgedSubmissions.clear(), this.dispatch({ type: "run.stop" }).then(() => {
|
|
703
720
|
});
|
|
704
721
|
}
|
|
705
722
|
startNewSession(e = {}) {
|
|
706
|
-
return e.notifyTransport === !1 ? Promise.resolve() : this.dispatch({ type: "session.new" }).then(() => {
|
|
723
|
+
return this.unacknowledgedSubmissions.clear(), e.notifyTransport === !1 ? Promise.resolve() : this.dispatch({ type: "session.new" }).then(() => {
|
|
707
724
|
});
|
|
708
725
|
}
|
|
709
726
|
async listSessions(e = {}) {
|
|
@@ -715,7 +732,7 @@ class H {
|
|
|
715
732
|
};
|
|
716
733
|
}
|
|
717
734
|
getSessionHistoryState() {
|
|
718
|
-
return
|
|
735
|
+
return A(this.sessionHistoryState);
|
|
719
736
|
}
|
|
720
737
|
subscribeSessionHistory(e) {
|
|
721
738
|
return this.sessionHistoryListeners.add(e), e(this.getSessionHistoryState()), () => this.sessionHistoryListeners.delete(e);
|
|
@@ -743,12 +760,12 @@ class H {
|
|
|
743
760
|
subscribeInteractions(e) {
|
|
744
761
|
return this.interactionListeners.add(e), e(this.getInteractions()), () => this.interactionListeners.delete(e);
|
|
745
762
|
}
|
|
746
|
-
actOnInteraction(e, t,
|
|
763
|
+
actOnInteraction(e, t, s, n = {}) {
|
|
747
764
|
return this.dispatch({
|
|
748
765
|
type: "interaction.act",
|
|
749
766
|
interactionId: e,
|
|
750
767
|
action: t,
|
|
751
|
-
expectedRevision:
|
|
768
|
+
expectedRevision: s,
|
|
752
769
|
...n
|
|
753
770
|
}).then(() => {
|
|
754
771
|
});
|
|
@@ -763,17 +780,17 @@ class H {
|
|
|
763
780
|
return Promise.resolve();
|
|
764
781
|
}
|
|
765
782
|
loadSession(e) {
|
|
766
|
-
return this.dispatch({ type: "session.load", sessionId: e }).then(() => {
|
|
783
|
+
return this.unacknowledgedSubmissions.clear(), this.dispatch({ type: "session.load", sessionId: e }).then(() => {
|
|
767
784
|
});
|
|
768
785
|
}
|
|
769
786
|
stageProactiveSuggestionQuestion(e) {
|
|
770
787
|
const t = e.trim();
|
|
771
788
|
if (!t) return Promise.resolve();
|
|
772
|
-
const
|
|
773
|
-
return this.stagedProactiveSuggestionClientMessageId =
|
|
789
|
+
const s = this.stagedProactiveSuggestionClientMessageId ?? crypto.randomUUID();
|
|
790
|
+
return this.stagedProactiveSuggestionClientMessageId = s, this.dispatch({
|
|
774
791
|
type: "conversation.stage_proactive_suggestion",
|
|
775
792
|
question: t,
|
|
776
|
-
clientMessageId:
|
|
793
|
+
clientMessageId: s
|
|
777
794
|
}).then(() => {
|
|
778
795
|
});
|
|
779
796
|
}
|
|
@@ -790,40 +807,40 @@ class H {
|
|
|
790
807
|
), t;
|
|
791
808
|
}
|
|
792
809
|
emit(e, t) {
|
|
793
|
-
const
|
|
794
|
-
for (const n of
|
|
810
|
+
const s = this.listeners[e];
|
|
811
|
+
for (const n of s ?? []) n(t);
|
|
795
812
|
}
|
|
796
813
|
}
|
|
797
|
-
function
|
|
814
|
+
function f(i) {
|
|
798
815
|
return {
|
|
799
|
-
...
|
|
800
|
-
starterPrompts: [...
|
|
801
|
-
appearance:
|
|
802
|
-
messages:
|
|
816
|
+
...i,
|
|
817
|
+
starterPrompts: [...i.starterPrompts],
|
|
818
|
+
appearance: i.appearance ? { ...i.appearance } : null,
|
|
819
|
+
messages: i.messages.map((e) => {
|
|
803
820
|
const t = {
|
|
804
821
|
...e,
|
|
805
822
|
attachments: e.attachments?.map((a) => ({ ...a }))
|
|
806
|
-
},
|
|
823
|
+
}, s = e.assistantDraftItemId, n = e.clientMessageId, r = e.proactiveSuggestionClientMessageId;
|
|
807
824
|
return r && Object.defineProperty(t, "proactiveSuggestionClientMessageId", {
|
|
808
825
|
value: r,
|
|
809
826
|
enumerable: !1
|
|
810
|
-
}),
|
|
811
|
-
value:
|
|
827
|
+
}), s && Object.defineProperty(t, "assistantDraftItemId", {
|
|
828
|
+
value: s,
|
|
812
829
|
enumerable: !1
|
|
813
830
|
}), n && Object.defineProperty(t, "clientMessageId", {
|
|
814
831
|
value: n,
|
|
815
832
|
enumerable: !1
|
|
816
833
|
}), t;
|
|
817
834
|
}),
|
|
818
|
-
activeScheduledFollowUps:
|
|
835
|
+
activeScheduledFollowUps: i.activeScheduledFollowUps?.map((e) => ({ ...e })) ?? null
|
|
819
836
|
};
|
|
820
837
|
}
|
|
821
|
-
function
|
|
838
|
+
function A(i) {
|
|
822
839
|
return {
|
|
823
|
-
...
|
|
824
|
-
data:
|
|
825
|
-
entities: w(
|
|
826
|
-
nextCursor:
|
|
840
|
+
...i,
|
|
841
|
+
data: i.data ? p({
|
|
842
|
+
entities: w(i.data).map((e) => ({ ...e })),
|
|
843
|
+
nextCursor: i.data.nextCursor
|
|
827
844
|
}) : null
|
|
828
845
|
};
|
|
829
846
|
}
|
|
@@ -837,14 +854,14 @@ export {
|
|
|
837
854
|
h as createProductAgentQueryState,
|
|
838
855
|
B as createProductAgentTaskPageTitleDocument,
|
|
839
856
|
D as formatProductAgentTaskPageTitle,
|
|
840
|
-
|
|
857
|
+
L as hasProductAgentPaidCreditFallback,
|
|
841
858
|
N as isProductAgentRuntimeCommand,
|
|
842
|
-
|
|
859
|
+
E as mergeProductAgentEntityPages,
|
|
843
860
|
p as normalizeProductAgentEntityPage,
|
|
844
861
|
P as readLocalStorageInteractionDecisions,
|
|
845
|
-
|
|
862
|
+
C as reconcileProductAgentSubmissionGate,
|
|
846
863
|
q as resolveProductAgentBillingPresentation,
|
|
847
864
|
Q as resolveProductAgentComposerAction,
|
|
848
|
-
|
|
865
|
+
R as resolveProductAgentWidgetPresentation,
|
|
849
866
|
w as selectProductAgentQueryEntities
|
|
850
867
|
};
|