@agent-native/core 0.185.0-nightly-20260923150956 → 0.185.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 (43) hide show
  1. package/corpus/templates/analytics/CHANGELOG.md +6 -0
  2. package/corpus/templates/brain/CHANGELOG.md +6 -0
  3. package/corpus/templates/calendar/CHANGELOG.md +11 -0
  4. package/corpus/templates/clips/CHANGELOG.md +37 -0
  5. package/corpus/templates/content/CHANGELOG.md +6 -0
  6. package/corpus/templates/design/CHANGELOG.md +9 -0
  7. package/corpus/templates/design/actions/get-design-system-index-status.ts +2 -5
  8. package/corpus/templates/design/actions/get-design-system.ts +6 -3
  9. package/corpus/templates/design/actions/list-design-systems.ts +53 -1
  10. package/corpus/templates/design/app/components/editor/design-start-pickers.tsx +10 -0
  11. package/corpus/templates/design/app/i18n-data.ts +10 -0
  12. package/corpus/templates/design/app/lib/design-system-data.ts +13 -10
  13. package/corpus/templates/design/app/pages/DesignSystems.tsx +11 -8
  14. package/corpus/templates/design/app/pages/Templates.tsx +6 -1
  15. package/corpus/templates/design/changelog/2026-09-22-fixed-the-design-system-picker-showing-a-still-indexing-buil.md +6 -0
  16. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +11 -30
  17. package/corpus/templates/mail/CHANGELOG.md +5 -0
  18. package/corpus/templates/slides/CHANGELOG.md +13 -0
  19. package/corpus/templates/slides/actions/apply-design-system.ts +2 -22
  20. package/corpus/templates/slides/actions/create-deck.ts +4 -54
  21. package/corpus/templates/slides/actions/get-design-system.ts +40 -3
  22. package/corpus/templates/slides/actions/list-design-systems.ts +26 -11
  23. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +16 -23
  24. package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +14 -51
  25. package/corpus/templates/slides/app/hooks/use-design-systems.ts +1 -191
  26. package/corpus/templates/slides/app/i18n/en-US.ts +0 -4
  27. package/corpus/templates/slides/app/lib/design-system-selection.ts +4 -19
  28. package/corpus/templates/slides/app/pages/Index.tsx +3 -16
  29. package/corpus/templates/slides/shared/design-system-validation.ts +16 -18
  30. package/dist/automation/index.d.ts +1 -1
  31. package/dist/collab/routes.d.ts +1 -1
  32. package/dist/collab/struct-routes.d.ts +1 -1
  33. package/dist/secrets/routes.d.ts +3 -3
  34. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  35. package/dist/server/builder-design-systems.d.ts +23 -1
  36. package/dist/server/builder-design-systems.js +58 -17
  37. package/dist/server/index.d.ts +1 -1
  38. package/dist/server/index.js +1 -1
  39. package/dist/server/realtime-token.d.ts +1 -1
  40. package/dist/server/transcribe-voice.d.ts +1 -1
  41. package/docs/content/toolkit-settings.mdx +32 -0
  42. package/package.json +4 -4
  43. package/corpus/templates/slides/actions/refresh-design-system-indexing-status.ts +0 -120
@@ -5,14 +5,11 @@ import { z } from "zod";
5
5
 
6
6
  import { getDb, schema } from "../server/db/index.js";
7
7
  import { notifyClients } from "../server/handlers/decks.js";
8
- import { parseDesignSystemIndexingStatus } from "../shared/design-system-validation.js";
9
8
 
10
9
  export default defineAction({
11
10
  description:
12
11
  "Link a design system to a deck. The deck will use this design system's " +
13
- "colors, typography, and styling. Requires editor access on the deck. " +
14
- "The design system must have finished Builder indexing (list-design-systems " +
15
- "reports indexingStatus 'ready'); a still-indexing or unavailable system is rejected.",
12
+ "colors, typography, and styling. Requires editor access on the deck.",
16
13
  schema: z.object({
17
14
  deckId: z.string().describe("Deck ID to apply the design system to"),
18
15
  designSystemId: z.string().describe("Design system ID to link to the deck"),
@@ -20,24 +17,7 @@ export default defineAction({
20
17
  run: async ({ deckId, designSystemId }) => {
21
18
  // Verify access to both the deck and the design system
22
19
  await assertAccess("deck", deckId, "editor");
23
- const designSystemAccess = await assertAccess(
24
- "design-system",
25
- designSystemId,
26
- "viewer",
27
- );
28
- const indexingStatus = parseDesignSystemIndexingStatus(
29
- designSystemAccess.resource.data,
30
- );
31
- if (indexingStatus !== "ready") {
32
- throw Object.assign(
33
- new Error(
34
- indexingStatus === "indexing"
35
- ? `Design system ${designSystemId} is still indexing and has no usable tokens/components yet. Wait for indexing to finish, or use a different design system.`
36
- : `Design system ${designSystemId} is unavailable (indexing failed or its data could not be read). Choose a different design system.`,
37
- ),
38
- { statusCode: 409 },
39
- );
40
- }
20
+ await assertAccess("design-system", designSystemId, "viewer");
41
21
 
42
22
  const db = getDb();
43
23
  const now = new Date().toISOString();
@@ -30,7 +30,6 @@ import {
30
30
  assertHumanReadableDeckTitle,
31
31
  repairGeneratedDeckTitle,
32
32
  } from "../shared/deck-title.js";
33
- import { parseDesignSystemIndexingStatus } from "../shared/design-system-validation.js";
34
33
  import {
35
34
  ensureUniqueSlideIds,
36
35
  rebindCreativeContextSlideLabels,
@@ -117,25 +116,6 @@ function deckNavigationCommand(deckId: string): Record<string, string> {
117
116
  };
118
117
  }
119
118
 
120
- /**
121
- * `list-design-systems` tells agents not to pass a non-'ready' id here, but an
122
- * agent can still race a status change or ignore that guidance — this is the
123
- * boundary that actually owns linking a design system, so it re-checks rather
124
- * than trusting the caller.
125
- */
126
- function assertDesignSystemReady(designSystemId: string, data: string): void {
127
- const status = parseDesignSystemIndexingStatus(data);
128
- if (status === "ready") return;
129
- throw Object.assign(
130
- new Error(
131
- status === "indexing"
132
- ? `Design system ${designSystemId} is still indexing and has no usable tokens/components yet. Wait for indexing to finish, or use a different design system.`
133
- : `Design system ${designSystemId} is unavailable (indexing failed or its data could not be read). Choose a different design system.`,
134
- ),
135
- { statusCode: 409 },
136
- );
137
- }
138
-
139
119
  export default defineAction({
140
120
  title: "Create Slides deck",
141
121
  description:
@@ -310,15 +290,7 @@ export default defineAction({
310
290
 
311
291
  if (deckId) {
312
292
  if (designSystemId) {
313
- const designSystemAccess = await assertAccess(
314
- "design-system",
315
- designSystemId,
316
- "viewer",
317
- );
318
- assertDesignSystemReady(
319
- designSystemId,
320
- designSystemAccess.resource.data,
321
- );
293
+ await assertAccess("design-system", designSystemId, "viewer");
322
294
  }
323
295
  // Update existing deck — requires editor access.
324
296
  await assertAccess("deck", deckId, "editor");
@@ -426,32 +398,10 @@ export default defineAction({
426
398
 
427
399
  let resolvedDesignSystemId = designSystemId;
428
400
  if (resolvedDesignSystemId) {
429
- const designSystemAccess = await assertAccess(
430
- "design-system",
431
- resolvedDesignSystemId,
432
- "viewer",
433
- );
434
- assertDesignSystemReady(
435
- resolvedDesignSystemId,
436
- designSystemAccess.resource.data,
437
- );
401
+ await assertAccess("design-system", resolvedDesignSystemId, "viewer");
438
402
  } else {
439
- const candidateDefaultId = await resolveDefaultDesignSystemId(ownerEmail);
440
- if (candidateDefaultId) {
441
- // An implicit default is a convenience, not an explicit request —
442
- // fall back to no design system instead of failing deck creation
443
- // outright when the caller's default happens to still be indexing.
444
- const [defaultRow] = await db
445
- .select({ data: schema.designSystems.data })
446
- .from(schema.designSystems)
447
- .where(eq(schema.designSystems.id, candidateDefaultId))
448
- .limit(1);
449
- resolvedDesignSystemId =
450
- defaultRow &&
451
- parseDesignSystemIndexingStatus(defaultRow.data) === "ready"
452
- ? candidateDefaultId
453
- : undefined;
454
- }
403
+ resolvedDesignSystemId =
404
+ (await resolveDefaultDesignSystemId(ownerEmail)) ?? undefined;
455
405
  }
456
406
 
457
407
  const id = `deck-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
@@ -4,9 +4,10 @@ import {
4
4
  parseBuilderDesignSystemProxyReference,
5
5
  } from "@agent-native/core/server";
6
6
  import { resolveAccess } from "@agent-native/core/sharing";
7
+ import { and, eq } from "drizzle-orm";
7
8
  import { z } from "zod";
8
9
 
9
- import "../server/db/index.js"; // ensure registerShareableResource runs
10
+ import { getDb, schema } from "../server/db/index.js";
10
11
 
11
12
  const MAX_AGENT_CONTEXT_CHARS = 14_000;
12
13
  const MAX_JSON_CONTEXT_CHARS = 2_500;
@@ -32,7 +33,8 @@ interface BuilderGenerationContext {
32
33
  tokenValues?: Record<string, string>;
33
34
  }>;
34
35
  tokenValues: Record<string, string>;
35
- docCount: number;
36
+ /** null when Builder could not be read at all; 0 means still indexing. */
37
+ docCount: number | null;
36
38
  warning?: string;
37
39
  }
38
40
 
@@ -41,6 +43,37 @@ function truncate(value: string, maxChars: number): string {
41
43
  return `${value.slice(0, maxChars).trimEnd()}\n[truncated]`;
42
44
  }
43
45
 
46
+ // list-design-systems only ever reads the docCount baked into row.data at
47
+ // proxy creation time (always absent) - this is the one place that hydrates
48
+ // a live count from Builder, so it is the one place that can refresh the
49
+ // cache. Compare-and-set against the exact data snapshot this request read
50
+ // avoids clobbering a concurrent sync/update; a lost race just leaves the
51
+ // next call to persist it. Never bumps updatedAt, so a background count
52
+ // refresh doesn't reorder the list.
53
+ async function persistBuilderDocCount(
54
+ row: { id: string; data: string | null },
55
+ docCount: number,
56
+ ): Promise<void> {
57
+ if (!row.data) return;
58
+ let parsed: Record<string, unknown>;
59
+ try {
60
+ parsed = JSON.parse(row.data);
61
+ } catch {
62
+ return;
63
+ }
64
+ if (parsed.docCount === docCount) return;
65
+ const db = getDb();
66
+ await db
67
+ .update(schema.designSystems)
68
+ .set({ data: JSON.stringify({ ...parsed, docCount }) })
69
+ .where(
70
+ and(
71
+ eq(schema.designSystems.id, row.id),
72
+ eq(schema.designSystems.data, row.data),
73
+ ),
74
+ );
75
+ }
76
+
44
77
  function parseJson(value: string | null | undefined): unknown {
45
78
  if (!value) return null;
46
79
  try {
@@ -282,7 +315,7 @@ export default defineAction({
282
315
  ...builderReference,
283
316
  docs: [],
284
317
  tokenValues: {},
285
- docCount: 0,
318
+ docCount: null,
286
319
  warning:
287
320
  error instanceof Error
288
321
  ? error.message
@@ -291,6 +324,10 @@ export default defineAction({
291
324
  )
292
325
  : null;
293
326
 
327
+ if (builder && typeof builder.docCount === "number") {
328
+ await persistBuilderDocCount(row, builder.docCount);
329
+ }
330
+
294
331
  return {
295
332
  id: row.id,
296
333
  title: row.title,
@@ -13,7 +13,6 @@ import { z } from "zod";
13
13
 
14
14
  import { getDb, schema } from "../server/db/index.js";
15
15
  import { resolveDefaultDesignSystemId } from "../server/workspace-defaults.js";
16
- import { parseDesignSystemIndexingStatus } from "../shared/design-system-validation.js";
17
16
 
18
17
  type EffectiveRole = "owner" | ShareRole;
19
18
 
@@ -35,16 +34,32 @@ function strongerRole(current: ShareRole | null, next: ShareRole): ShareRole {
35
34
  return current;
36
35
  }
37
36
 
37
+ /**
38
+ * Builder-reported indexed document count cached on the row. Undefined means
39
+ * "not measured yet", which is not the same as a system with zero documents.
40
+ */
41
+ function cachedBuilderDocCount(data: string | null): number | undefined {
42
+ if (!data) return undefined;
43
+ let parsed: unknown;
44
+ try {
45
+ parsed = JSON.parse(data);
46
+ } catch {
47
+ // coercion-ok: unparseable row data leaves the count unknown, and
48
+ // undefined stays distinguishable from a measured zero.
49
+ return undefined;
50
+ }
51
+ if (!parsed || typeof parsed !== "object") return undefined;
52
+ const docCount = (parsed as Record<string, unknown>).docCount;
53
+ return typeof docCount === "number" ? docCount : undefined;
54
+ }
55
+
38
56
  export default defineAction({
39
57
  description:
40
58
  "List all design systems accessible to the current user. Returns title, " +
41
- "id, isDefault (true only for the caller's effective default), and " +
42
- "indexingStatus ('ready' | 'indexing' | 'unavailable'). Do not pass a " +
43
- "non-'ready' id to create-deck or apply-design-system — its tokens and " +
44
- "components are not queryable yet; call get-design-system to confirm " +
45
- "status if unsure. For a named system, match the exact title and pass " +
46
- "its id as designSystemId — or pass the title as `designSystem` on " +
47
- "create-deck — then call get-design-system once before authoring.",
59
+ "id, and isDefault (true only for the caller's effective default). For a " +
60
+ "named system, match the exact title and pass its id as designSystemId " +
61
+ "— or pass the title as `designSystem` on create-deck — then call " +
62
+ "get-design-system once before authoring.",
48
63
  schema: z.object({
49
64
  compact: z
50
65
  .enum(["true", "false"])
@@ -145,8 +160,8 @@ export default defineAction({
145
160
  role = "owner";
146
161
  }
147
162
  const canManage = canManageRole(role);
148
- const indexingStatus = parseDesignSystemIndexingStatus(row.data);
149
163
 
164
+ const docCount = cachedBuilderDocCount(row.data);
150
165
  if (args.compact === "true") {
151
166
  return {
152
167
  id: row.id,
@@ -154,7 +169,7 @@ export default defineAction({
154
169
  isDefault: row.id === effectiveDefaultId,
155
170
  accessRole: role,
156
171
  canManage,
157
- indexingStatus,
172
+ docCount,
158
173
  };
159
174
  }
160
175
  return {
@@ -162,13 +177,13 @@ export default defineAction({
162
177
  title: row.title,
163
178
  description: row.description,
164
179
  data: row.data,
180
+ docCount,
165
181
  isDefault: row.id === effectiveDefaultId,
166
182
  visibility: row.visibility,
167
183
  accessRole: role,
168
184
  canManage,
169
185
  createdAt: row.createdAt,
170
186
  updatedAt: row.updatedAt,
171
- indexingStatus,
172
187
  };
173
188
  });
174
189
 
@@ -97,9 +97,9 @@ interface BuilderSourceDetails {
97
97
  builderUrl?: string;
98
98
  builderStatus?: string;
99
99
  sourceKind?: BuilderSourceKind;
100
- docs?: Array<unknown>;
101
100
  tokenValues?: Record<string, string>;
102
- docCount?: number;
101
+ /** null when Builder could not be read at all; 0 means still indexing. */
102
+ docCount?: number | null;
103
103
  warning?: string;
104
104
  githubSources?: Array<{
105
105
  repoUrl: string;
@@ -276,10 +276,11 @@ export function DesignSystemSetup({
276
276
  editingId ? { id: editingId } : undefined,
277
277
  {
278
278
  enabled: !!editingId && open,
279
+ // Builder's status string lags the real index state; a zero document
280
+ // count is the only reliable "still indexing" signal. A null count
281
+ // means Builder could not be read, so stop rather than spin.
279
282
  refetchInterval: (query) =>
280
- query.state.data?.builder?.builderStatus === "in-progress"
281
- ? 5_000
282
- : false,
283
+ query.state.data?.builder?.docCount === 0 ? 5_000 : false,
283
284
  },
284
285
  );
285
286
 
@@ -1544,26 +1545,18 @@ function BuilderSourceStatus({
1544
1545
  syncing?: boolean;
1545
1546
  }) {
1546
1547
  const t = useT();
1547
- const docs = builder.docCount ?? builder.docs?.length ?? 0;
1548
+ // Builder's status string drifts out of sync with the real index state, so
1549
+ // the reported document count decides: absent means Builder could not be
1550
+ // read at all, zero means indexing, positive means ready.
1551
+ const docCount = builder.docCount;
1552
+ const docs = docCount ?? 0;
1548
1553
  const tokens = Object.keys(builder.tokenValues ?? {}).length;
1549
- const normalizedStatus = builder.builderStatus?.toLowerCase();
1550
1554
  const hasIndexedResults = docs > 0 || tokens > 0;
1551
- const isIndexed =
1552
- hasIndexedResults ||
1553
- normalizedStatus === "ready" ||
1554
- normalizedStatus === "complete" ||
1555
- normalizedStatus === "completed";
1556
- const isIndexing = ["in-progress", "pending", "processing"].includes(
1557
- normalizedStatus ?? "",
1558
- );
1559
- const state =
1560
- isIndexing && !isIndexed
1561
- ? "indexing"
1562
- : builder.warning
1563
- ? "unavailable"
1564
- : isIndexed
1565
- ? "indexed"
1566
- : "indexing";
1555
+ const state = hasIndexedResults
1556
+ ? "indexed"
1557
+ : builder.warning
1558
+ ? "unavailable"
1559
+ : "indexing";
1567
1560
  const sourceKind = builder.sourceKind;
1568
1561
  const SourceIcon =
1569
1562
  sourceKind === "figma"
@@ -7,7 +7,6 @@ import {
7
7
  IconChevronDown,
8
8
  IconFileText,
9
9
  IconFileTypePdf,
10
- IconLoader2,
11
10
  IconPresentation,
12
11
  IconWorld,
13
12
  } from "@tabler/icons-react";
@@ -39,13 +38,9 @@ import {
39
38
  } from "@/components/ui/select";
40
39
  import type { Deck } from "@/context/DeckContext";
41
40
  import { sortDecksByRecency } from "@/lib/deck-sorting";
42
- import {
43
- isDesignSystemSelectable,
44
- resolveSelectableDesignSystemId,
45
- } from "@/lib/design-system-selection";
41
+ import { resolveSelectableDesignSystemId } from "@/lib/design-system-selection";
46
42
  import { cn } from "@/lib/utils";
47
43
 
48
- import type { DesignSystemIndexingStatus } from "../../../shared/design-system-validation";
49
44
  import { GoogleDriveConnectionCta } from "./GoogleDriveConnectionCta";
50
45
  export interface NewDeckReferenceSelection {
51
46
  designSystemId?: string | null;
@@ -82,7 +77,6 @@ interface DesignSystemOption {
82
77
  id: string;
83
78
  title: string;
84
79
  isDefault?: boolean;
85
- indexingStatus?: DesignSystemIndexingStatus;
86
80
  }
87
81
 
88
82
  interface NewDeckReferenceStepProps {
@@ -137,9 +131,7 @@ export function NewDeckReferenceStep({
137
131
  const t = useT();
138
132
  const [selectedDesignSystemId, setSelectedDesignSystemId] = useState<
139
133
  string | null
140
- >(() =>
141
- resolveSelectableDesignSystemId(designSystems, defaultDesignSystemId),
142
- );
134
+ >(resolveSelectableDesignSystemId(designSystems, defaultDesignSystemId));
143
135
  const [selectedReferenceDeckId, setSelectedReferenceDeckId] = useState<
144
136
  string | null
145
137
  >(defaultReferenceDeckId);
@@ -157,6 +149,9 @@ export function NewDeckReferenceStep({
157
149
  const [showDesignSystemSetup, setShowDesignSystemSetup] = useState(false);
158
150
  const busy = importing || continuing;
159
151
 
152
+ // True while the picker still reflects an auto-applied default rather than
153
+ // an explicit user choice, so a default that resolves after this step is
154
+ // already open can still land - see the hydration effects below.
160
155
  const designSystemAutoRef = useRef(true);
161
156
  const referenceDeckAutoRef = useRef(true);
162
157
 
@@ -165,14 +160,6 @@ export function NewDeckReferenceStep({
165
160
  const selectedReferenceDeck = selectedReferenceDeckId
166
161
  ? deckById.get(selectedReferenceDeckId)
167
162
  : undefined;
168
- const selectedDesignSystem = selectedDesignSystemId
169
- ? designSystems.find((ds) => ds.id === selectedDesignSystemId)
170
- : undefined;
171
- // Selecting one from the list below already disables non-ready rows; this
172
- // also covers a system that starts re-indexing after it was selected.
173
- const selectedDesignSystemUnavailable = Boolean(
174
- selectedDesignSystem && !isDesignSystemSelectable(selectedDesignSystem),
175
- );
176
163
  const hasSelection = Boolean(
177
164
  selectedDesignSystemId ||
178
165
  selectedReferenceDeckId ||
@@ -183,7 +170,9 @@ export function NewDeckReferenceStep({
183
170
  if (!open) return;
184
171
  designSystemAutoRef.current = true;
185
172
  referenceDeckAutoRef.current = true;
186
- setSelectedDesignSystemId(null);
173
+ setSelectedDesignSystemId(
174
+ resolveSelectableDesignSystemId(designSystems, defaultDesignSystemId),
175
+ );
187
176
  setSelectedReferenceDeckId(defaultReferenceDeckId);
188
177
  setReferenceDeckTouched(defaultReferenceDeckId !== null);
189
178
  setImportedReference(null);
@@ -235,7 +224,7 @@ export function NewDeckReferenceStep({
235
224
  };
236
225
 
237
226
  const handleContinue = async () => {
238
- if (busy || selectedDesignSystemUnavailable || !hasSelection) return;
227
+ if (busy || !hasSelection) return;
239
228
  const trimmedSource =
240
229
  selectedSource && selectedSource.value.trim()
241
230
  ? { ...selectedSource, value: selectedSource.value.trim() }
@@ -376,38 +365,13 @@ export function NewDeckReferenceStep({
376
365
  </SelectTrigger>
377
366
  <SelectContent>
378
367
  <SelectItem value="none">{t("home.none")}</SelectItem>
379
- {designSystems.map((designSystem) => {
380
- const selectable = isDesignSystemSelectable(designSystem);
381
- return (
382
- <SelectItem
383
- key={designSystem.id}
384
- value={designSystem.id}
385
- disabled={!selectable}
386
- >
387
- <span className="flex items-center gap-1.5">
388
- {designSystem.title}
389
- {designSystem.indexingStatus === "indexing" && (
390
- <span className="inline-flex items-center gap-1 text-xs text-muted-foreground">
391
- <IconLoader2 className="size-3 animate-spin" />
392
- {t("home.designSystemIndexing")}
393
- </span>
394
- )}
395
- {designSystem.indexingStatus === "unavailable" && (
396
- <span className="text-xs text-muted-foreground">
397
- ({t("home.designSystemUnavailable")})
398
- </span>
399
- )}
400
- </span>
401
- </SelectItem>
402
- );
403
- })}
368
+ {designSystems.map((designSystem) => (
369
+ <SelectItem key={designSystem.id} value={designSystem.id}>
370
+ {designSystem.title}
371
+ </SelectItem>
372
+ ))}
404
373
  </SelectContent>
405
374
  </Select>
406
- {selectedDesignSystemUnavailable && (
407
- <p className="text-xs text-amber-500">
408
- {t("home.designSystemIndexingNotice")}
409
- </p>
410
- )}
411
375
  </div>
412
376
 
413
377
  <div className="grid gap-2">
@@ -644,7 +608,6 @@ export function NewDeckReferenceStep({
644
608
  aria-busy={busy}
645
609
  disabled={
646
610
  busy ||
647
- selectedDesignSystemUnavailable ||
648
611
  !hasSelection ||
649
612
  Boolean(selectedSource && !selectedSource.value.trim())
650
613
  }