forge-openclaw-plugin 0.2.26 → 0.2.28

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 (109) hide show
  1. package/README.md +60 -3
  2. package/dist/assets/{board-ta0rUHOf.js → board-DPFvZf-D.js} +2 -2
  3. package/dist/assets/{board-ta0rUHOf.js.map → board-DPFvZf-D.js.map} +1 -1
  4. package/dist/assets/index-Auw3JrdE.css +1 -0
  5. package/dist/assets/index-D1H7myQH.js +85 -0
  6. package/dist/assets/index-D1H7myQH.js.map +1 -0
  7. package/dist/assets/knowledge-graph-layout.worker-DRvzPxhP.js +2 -0
  8. package/dist/assets/knowledge-graph-layout.worker-DRvzPxhP.js.map +1 -0
  9. package/dist/assets/{motion-fBKPB6yw.js → motion-Bvwc85ch.js} +2 -2
  10. package/dist/assets/{motion-fBKPB6yw.js.map → motion-Bvwc85ch.js.map} +1 -1
  11. package/dist/assets/{table-C-IGTQni.js → table-FJQTJvUR.js} +2 -2
  12. package/dist/assets/{table-C-IGTQni.js.map → table-FJQTJvUR.js.map} +1 -1
  13. package/dist/assets/{ui-DInOpaYF.js → ui-GXFcgvSw.js} +2 -2
  14. package/dist/assets/{ui-DInOpaYF.js.map → ui-GXFcgvSw.js.map} +1 -1
  15. package/dist/assets/vendor-Cwf49UMz.js +1247 -0
  16. package/dist/assets/vendor-Cwf49UMz.js.map +1 -0
  17. package/dist/index.html +7 -7
  18. package/dist/openclaw/local-runtime.js +16 -0
  19. package/dist/openclaw/routes.d.ts +27 -0
  20. package/dist/openclaw/routes.js +16 -12
  21. package/dist/server/server/migrations/037_workbench_public_inputs_and_run_inputs.sql +5 -0
  22. package/dist/server/server/migrations/038_data_management_settings.sql +11 -0
  23. package/dist/server/server/migrations/039_life_force_and_action_points.sql +114 -0
  24. package/dist/server/server/migrations/040_screen_time_domain.sql +89 -0
  25. package/dist/server/server/migrations/041_companion_source_states.sql +21 -0
  26. package/dist/server/server/migrations/042_movement_boxes.sql +47 -0
  27. package/dist/server/server/migrations/043_movement_box_overlap_overrides.sql +26 -0
  28. package/dist/server/server/src/app.js +1900 -91
  29. package/dist/server/server/src/connectors/box-registry.js +44 -9
  30. package/dist/server/server/src/data-management-types.js +107 -0
  31. package/dist/server/server/src/db.js +68 -4
  32. package/dist/server/server/src/demo-data.js +2 -2
  33. package/dist/server/server/src/health.js +702 -18
  34. package/dist/server/server/src/managers/platform/llm-manager.js +7 -4
  35. package/dist/server/server/src/managers/platform/mock-workbench-provider.js +149 -0
  36. package/dist/server/server/src/managers/platform/secrets-manager.js +18 -1
  37. package/dist/server/server/src/managers/runtime.js +9 -0
  38. package/dist/server/server/src/movement.js +1971 -112
  39. package/dist/server/server/src/openapi.js +1390 -105
  40. package/dist/server/server/src/psyche-types.js +9 -1
  41. package/dist/server/server/src/repositories/activity-events.js +8 -0
  42. package/dist/server/server/src/repositories/ai-connectors.js +522 -74
  43. package/dist/server/server/src/repositories/calendar.js +151 -0
  44. package/dist/server/server/src/repositories/habits.js +37 -1
  45. package/dist/server/server/src/repositories/model-settings.js +13 -3
  46. package/dist/server/server/src/repositories/notes.js +3 -0
  47. package/dist/server/server/src/repositories/settings.js +380 -18
  48. package/dist/server/server/src/repositories/tasks.js +170 -10
  49. package/dist/server/server/src/runtime-data-root.js +82 -0
  50. package/dist/server/server/src/screen-time.js +802 -0
  51. package/dist/server/server/src/services/data-management.js +788 -0
  52. package/dist/server/server/src/services/entity-crud.js +205 -2
  53. package/dist/server/server/src/services/knowledge-graph.js +1455 -0
  54. package/dist/server/server/src/services/life-force-model.js +217 -0
  55. package/dist/server/server/src/services/life-force.js +2506 -0
  56. package/dist/server/server/src/services/psyche-observation-calendar.js +383 -16
  57. package/dist/server/server/src/types.js +307 -14
  58. package/dist/server/server/src/web.js +228 -13
  59. package/dist/server/src/components/customization/utility-widgets.js +136 -27
  60. package/dist/server/src/components/ui/info-tooltip.js +25 -0
  61. package/dist/server/src/components/workbench-boxes/calendar/calendar-boxes.js +78 -0
  62. package/dist/server/src/components/workbench-boxes/goals/goals-boxes.js +62 -0
  63. package/dist/server/src/components/workbench-boxes/habits/habits-boxes.js +62 -0
  64. package/dist/server/src/components/workbench-boxes/health/health-boxes.js +63 -8
  65. package/dist/server/src/components/workbench-boxes/insights/insights-boxes.js +50 -0
  66. package/dist/server/src/components/workbench-boxes/kanban/kanban-boxes.js +62 -54
  67. package/dist/server/src/components/workbench-boxes/movement/movement-boxes.js +18 -8
  68. package/dist/server/src/components/workbench-boxes/notes/notes-boxes.js +56 -38
  69. package/dist/server/src/components/workbench-boxes/overview/overview-boxes.js +65 -0
  70. package/dist/server/src/components/workbench-boxes/preferences/preferences-boxes.js +78 -0
  71. package/dist/server/src/components/workbench-boxes/projects/projects-boxes.js +35 -30
  72. package/dist/server/src/components/workbench-boxes/psyche/psyche-boxes.js +88 -0
  73. package/dist/server/src/components/workbench-boxes/questionnaires/questionnaires-boxes.js +61 -0
  74. package/dist/server/src/components/workbench-boxes/review/review-boxes.js +53 -0
  75. package/dist/server/src/components/workbench-boxes/shared/define-workbench-box.js +3 -1
  76. package/dist/server/src/components/workbench-boxes/shared/generic-node-view.js +39 -3
  77. package/dist/server/src/components/workbench-boxes/strategies/strategies-boxes.js +62 -0
  78. package/dist/server/src/components/workbench-boxes/tasks/tasks-boxes.js +76 -0
  79. package/dist/server/src/components/workbench-boxes/today/today-boxes.js +47 -32
  80. package/dist/server/src/components/workbench-boxes/wiki/wiki-boxes.js +60 -0
  81. package/dist/server/src/lib/api.js +280 -21
  82. package/dist/server/src/lib/data-management-types.js +1 -0
  83. package/dist/server/src/lib/entity-visuals.js +279 -0
  84. package/dist/server/src/lib/knowledge-graph-types.js +276 -0
  85. package/dist/server/src/lib/knowledge-graph.js +470 -0
  86. package/dist/server/src/lib/schemas.js +4 -0
  87. package/dist/server/src/lib/snapshot-normalizer.js +45 -1
  88. package/dist/server/src/lib/workbench/contracts.js +229 -0
  89. package/dist/server/src/lib/workbench/nodes.js +200 -0
  90. package/dist/server/src/lib/workbench/registry.js +52 -5
  91. package/dist/server/src/lib/workbench/runtime.js +254 -38
  92. package/dist/server/src/lib/workbench/tool-catalog.js +68 -0
  93. package/openclaw.plugin.json +1 -1
  94. package/package.json +1 -1
  95. package/server/migrations/037_workbench_public_inputs_and_run_inputs.sql +5 -0
  96. package/server/migrations/038_data_management_settings.sql +11 -0
  97. package/server/migrations/039_life_force_and_action_points.sql +114 -0
  98. package/server/migrations/040_screen_time_domain.sql +89 -0
  99. package/server/migrations/041_companion_source_states.sql +21 -0
  100. package/server/migrations/042_movement_boxes.sql +47 -0
  101. package/server/migrations/043_movement_box_overlap_overrides.sql +26 -0
  102. package/skills/forge-openclaw/SKILL.md +41 -11
  103. package/skills/forge-openclaw/entity_conversation_playbooks.md +448 -34
  104. package/skills/forge-openclaw/psyche_entity_playbooks.md +170 -17
  105. package/dist/assets/index-Ro0ZF_az.css +0 -1
  106. package/dist/assets/index-ytlpSj23.js +0 -79
  107. package/dist/assets/index-ytlpSj23.js.map +0 -1
  108. package/dist/assets/vendor-lE3tZJcC.js +0 -876
  109. package/dist/assets/vendor-lE3tZJcC.js.map +0 -1
@@ -1,11 +1,16 @@
1
1
  import { getDatabase } from "../db.js";
2
2
  import { getFitnessViewData, getSleepViewData } from "../health.js";
3
3
  import { listMovementPlaces } from "../movement.js";
4
+ import { getInsightsPayload } from "../services/insights.js";
5
+ import { getWeeklyReviewPayload } from "../services/reviews.js";
4
6
  import { createNote, listNotes } from "../repositories/notes.js";
5
7
  import { updateTask } from "../repositories/tasks.js";
8
+ import { getOverviewContext } from "../services/context.js";
6
9
  import { searchEntities } from "../services/entity-crud.js";
10
+ import { getWikiHealth, listWikiPages } from "../repositories/wiki-memory.js";
7
11
  import { executeCommonWorkbenchTool, mapWorkbenchTools } from "../../../src/lib/workbench/runtime.js";
8
12
  import { getWorkbenchNodeCatalog, getWorkbenchNodeDefinition } from "../../../src/lib/workbench/registry.js";
13
+ import { normalizeWorkbenchPortDefinition } from "../../../src/lib/workbench/nodes.js";
9
14
  function createSnapshotForConnectorOutput(boxId) {
10
15
  const outputId = boxId.replace(/^connector-output:/, "");
11
16
  const rows = getDatabase()
@@ -38,7 +43,10 @@ function createRuntimeContext(input) {
38
43
  search: searchEntities
39
44
  },
40
45
  notes: {
41
- create: createNote,
46
+ create: ((input) => createNote(input, {
47
+ source: "agent",
48
+ actor: "Workbench"
49
+ })),
42
50
  list: listNotes
43
51
  },
44
52
  movement: {
@@ -48,6 +56,19 @@ function createRuntimeContext(input) {
48
56
  getSleepViewData: getSleepViewData,
49
57
  getFitnessViewData: getFitnessViewData
50
58
  },
59
+ overview: {
60
+ getContext: (() => getOverviewContext()),
61
+ getWeeklyReview: (() => getWeeklyReviewPayload()),
62
+ getInsights: (() => getInsightsPayload())
63
+ },
64
+ wiki: {
65
+ listPages: ((input) => listWikiPages({
66
+ spaceId: typeof input?.spaceId === "string" ? input.spaceId : undefined,
67
+ kind: typeof input?.kind === "string" ? input.kind : undefined,
68
+ limit: typeof input?.limit === "number" ? input.limit : undefined
69
+ })),
70
+ getHealth: (() => getWikiHealth())
71
+ },
51
72
  tasks: {
52
73
  update: ((taskId, patch) => updateTask(taskId, patch, { source: "agent", actor: "Workbench" }))
53
74
  }
@@ -64,12 +85,22 @@ function toCatalogEntry(definition) {
64
85
  if (!definition) {
65
86
  return null;
66
87
  }
67
- const toPortDefinition = (port) => ({
88
+ const toPortDefinition = (port) => normalizeWorkbenchPortDefinition({
68
89
  key: port.key,
69
90
  label: port.label,
70
91
  kind: port.kind,
92
+ description: "description" in port ? port.description : undefined,
71
93
  required: port.required ?? false,
72
- expandableKeys: "expandableKeys" in port ? (port.expandableKeys ?? []) : []
94
+ expandableKeys: "expandableKeys" in port ? (port.expandableKeys ?? []) : [],
95
+ modelName: "modelName" in port ? port.modelName : undefined,
96
+ itemKind: "itemKind" in port ? port.itemKind : undefined,
97
+ shape: "shape" in port
98
+ ? (port.shape ?? []).map((field) => ({
99
+ ...field,
100
+ required: field.required ?? false
101
+ }))
102
+ : [],
103
+ exampleValue: "exampleValue" in port ? port.exampleValue : undefined
73
104
  });
74
105
  return {
75
106
  id: definition.id,
@@ -118,21 +149,25 @@ export function buildConnectorOutputCatalogEntry(input) {
118
149
  params: [],
119
150
  output: [
120
151
  {
121
- key: "primary",
152
+ key: input.outputId,
122
153
  label: "Published output",
123
- kind: "content",
154
+ kind: "record",
155
+ description: "Published output record exposed by this Workbench flow.",
124
156
  required: false,
125
- expandableKeys: []
157
+ expandableKeys: [],
158
+ modelName: "WorkbenchPublishedOutput"
126
159
  }
127
160
  ],
128
161
  tools: [],
129
162
  outputs: [
130
163
  {
131
- key: "primary",
164
+ key: input.outputId,
132
165
  label: "Published output",
133
- kind: "content",
166
+ kind: "record",
167
+ description: "Published output record exposed by this Workbench flow.",
134
168
  required: false,
135
- expandableKeys: []
169
+ expandableKeys: [],
170
+ modelName: "WorkbenchPublishedOutput"
136
171
  }
137
172
  ],
138
173
  toolAdapters: []
@@ -0,0 +1,107 @@
1
+ import { z } from "zod";
2
+ export const dataBackupModeSchema = z.enum([
3
+ "manual",
4
+ "automatic",
5
+ "pre_restore",
6
+ "pre_switch_root"
7
+ ]);
8
+ export const dataRootSwitchModeSchema = z.enum([
9
+ "migrate_current",
10
+ "adopt_existing"
11
+ ]);
12
+ export const dataExportFormatSchema = z.enum([
13
+ "sqlite",
14
+ "json",
15
+ "csv_bundle",
16
+ "schema_sql",
17
+ "schema_json"
18
+ ]);
19
+ export const dataLayoutSchema = z.enum(["flat", "legacy", "missing"]);
20
+ export const dataEntityCountSummarySchema = z.object({
21
+ notes: z.number().int().nonnegative(),
22
+ goals: z.number().int().nonnegative(),
23
+ projects: z.number().int().nonnegative(),
24
+ tasks: z.number().int().nonnegative(),
25
+ taskRuns: z.number().int().nonnegative(),
26
+ tags: z.number().int().nonnegative()
27
+ });
28
+ export const dataBackupEntrySchema = z.object({
29
+ id: z.string(),
30
+ createdAt: z.string(),
31
+ mode: dataBackupModeSchema,
32
+ note: z.string(),
33
+ sourceDataRoot: z.string(),
34
+ backupDirectory: z.string(),
35
+ archivePath: z.string(),
36
+ manifestPath: z.string(),
37
+ databasePath: z.string(),
38
+ sizeBytes: z.number().int().nonnegative(),
39
+ includesWiki: z.boolean(),
40
+ includesSecretsKey: z.boolean(),
41
+ counts: dataEntityCountSummarySchema
42
+ });
43
+ export const dataRuntimeSnapshotSchema = z.object({
44
+ dataRoot: z.string(),
45
+ databasePath: z.string(),
46
+ layout: dataLayoutSchema,
47
+ databaseSizeBytes: z.number().int().nonnegative(),
48
+ databaseLastModifiedAt: z.string().nullable(),
49
+ integrityOk: z.boolean(),
50
+ integrityMessage: z.string(),
51
+ counts: dataEntityCountSummarySchema
52
+ });
53
+ export const dataRecoveryCandidateSchema = z.object({
54
+ id: z.string(),
55
+ dataRoot: z.string(),
56
+ databasePath: z.string(),
57
+ layout: dataLayoutSchema,
58
+ sourceHint: z.string(),
59
+ databaseSizeBytes: z.number().int().nonnegative(),
60
+ databaseLastModifiedAt: z.string().nullable(),
61
+ integrityOk: z.boolean(),
62
+ integrityMessage: z.string(),
63
+ counts: dataEntityCountSummarySchema,
64
+ newerThanCurrent: z.boolean(),
65
+ sameAsCurrent: z.boolean()
66
+ });
67
+ export const dataExportOptionSchema = z.object({
68
+ format: dataExportFormatSchema,
69
+ label: z.string(),
70
+ description: z.string(),
71
+ mimeType: z.string(),
72
+ extension: z.string()
73
+ });
74
+ export const dataManagementSettingsSchema = z.object({
75
+ preferredDataRoot: z.string(),
76
+ backupDirectory: z.string(),
77
+ backupFrequencyHours: z.number().int().positive().nullable(),
78
+ autoRepairEnabled: z.boolean(),
79
+ lastAutoBackupAt: z.string().nullable(),
80
+ lastManualBackupAt: z.string().nullable()
81
+ });
82
+ export const dataManagementStateSchema = z.object({
83
+ generatedAt: z.string(),
84
+ current: dataRuntimeSnapshotSchema,
85
+ settings: dataManagementSettingsSchema,
86
+ backups: z.array(dataBackupEntrySchema),
87
+ exportOptions: z.array(dataExportOptionSchema)
88
+ });
89
+ export const updateDataManagementSettingsSchema = z.object({
90
+ backupDirectory: z.string().trim().optional(),
91
+ backupFrequencyHours: z.number().int().positive().nullable().optional(),
92
+ autoRepairEnabled: z.boolean().optional()
93
+ });
94
+ export const createDataBackupSchema = z.object({
95
+ note: z.string().trim().default("")
96
+ });
97
+ export const switchDataRootSchema = z.object({
98
+ targetDataRoot: z.string().trim().min(1),
99
+ mode: dataRootSwitchModeSchema.default("migrate_current"),
100
+ createSafetyBackup: z.boolean().default(true)
101
+ });
102
+ export const restoreDataBackupSchema = z.object({
103
+ createSafetyBackup: z.boolean().default(true)
104
+ });
105
+ export const dataExportQuerySchema = z.object({
106
+ format: dataExportFormatSchema
107
+ });
@@ -1,10 +1,11 @@
1
- import { existsSync } from "node:fs";
1
+ import { existsSync, readFileSync } from "node:fs";
2
2
  import { mkdir, readdir, readFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { DatabaseSync } from "node:sqlite";
6
6
  import { logForgeDebug } from "./debug.js";
7
7
  import { ensureQuestionnaireSeeds } from "./repositories/questionnaires.js";
8
+ import { getMonorepoRuntimePreferencePath } from "./runtime-data-root.js";
8
9
  function nowIso() {
9
10
  return new Date().toISOString();
10
11
  }
@@ -16,15 +17,62 @@ function dateOffsetIso(days) {
16
17
  const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
17
18
  const migrationsDir = path.join(projectRoot, "server", "migrations");
18
19
  const monorepoForgeDataRoot = path.resolve(projectRoot, "..", "..", "data", "forge");
20
+ function resolveCanonicalDataDir(root = dataRoot) {
21
+ return path.resolve(root);
22
+ }
23
+ function resolveLegacyDataDir(root = dataRoot) {
24
+ return path.join(path.resolve(root), "data");
25
+ }
26
+ function resolveCanonicalDatabasePath(root = dataRoot) {
27
+ return path.join(resolveCanonicalDataDir(root), "forge.sqlite");
28
+ }
29
+ function resolveLegacyDatabasePath(root = dataRoot) {
30
+ return path.join(resolveLegacyDataDir(root), "forge.sqlite");
31
+ }
32
+ function hasCanonicalRuntimeLayout(root = dataRoot) {
33
+ const canonicalRoot = resolveCanonicalDataDir(root);
34
+ return (existsSync(resolveCanonicalDatabasePath(root)) ||
35
+ existsSync(path.join(canonicalRoot, "wiki")) ||
36
+ existsSync(path.join(canonicalRoot, "wiki-ingest")) ||
37
+ existsSync(path.join(canonicalRoot, ".forge-secrets.key")));
38
+ }
39
+ function hasLegacyRuntimeLayout(root = dataRoot) {
40
+ const legacyRoot = resolveLegacyDataDir(root);
41
+ return (existsSync(resolveLegacyDatabasePath(root)) ||
42
+ existsSync(path.join(legacyRoot, "wiki")) ||
43
+ existsSync(path.join(legacyRoot, "wiki-ingest")) ||
44
+ existsSync(path.join(legacyRoot, ".forge-secrets.key")));
45
+ }
46
+ export function resolveDatabasePathForDataRoot(root = dataRoot) {
47
+ if (existsSync(resolveCanonicalDatabasePath(root))) {
48
+ return resolveCanonicalDatabasePath(root);
49
+ }
50
+ if (existsSync(resolveLegacyDatabasePath(root))) {
51
+ return resolveLegacyDatabasePath(root);
52
+ }
53
+ return resolveCanonicalDatabasePath(root);
54
+ }
19
55
  export function resolveDefaultDataRoot(currentWorkingDir = process.cwd()) {
20
56
  const configured = process.env.FORGE_DATA_ROOT?.trim();
21
57
  if (configured) {
22
58
  return path.resolve(configured);
23
59
  }
60
+ if (existsSync(getMonorepoRuntimePreferencePath())) {
61
+ try {
62
+ const raw = readFileSync(getMonorepoRuntimePreferencePath(), "utf8");
63
+ const parsed = JSON.parse(raw);
64
+ if (typeof parsed.dataRoot === "string" && parsed.dataRoot.trim().length > 0) {
65
+ return path.resolve(parsed.dataRoot);
66
+ }
67
+ }
68
+ catch {
69
+ // Ignore invalid local runtime preference files and continue to defaults.
70
+ }
71
+ }
24
72
  // Inside the private monorepo, prefer the tracked shared Forge data root so
25
73
  // the local app, Hermes, OpenClaw, and repo-managed data all point at the
26
74
  // same state by default.
27
- if (existsSync(path.join(monorepoForgeDataRoot, "data"))) {
75
+ if (existsSync(monorepoForgeDataRoot)) {
28
76
  return monorepoForgeDataRoot;
29
77
  }
30
78
  return path.resolve(currentWorkingDir);
@@ -35,13 +83,29 @@ let db = null;
35
83
  let transactionDepth = 0;
36
84
  let savepointCounter = 0;
37
85
  function getDataDir() {
38
- return path.join(dataRoot, "data");
86
+ const databasePath = resolveDatabasePathForDataRoot();
87
+ if (databasePath === resolveCanonicalDatabasePath()) {
88
+ return resolveCanonicalDataDir();
89
+ }
90
+ if (databasePath === resolveLegacyDatabasePath()) {
91
+ return resolveLegacyDataDir();
92
+ }
93
+ if (hasCanonicalRuntimeLayout()) {
94
+ return resolveCanonicalDataDir();
95
+ }
96
+ if (hasLegacyRuntimeLayout()) {
97
+ return resolveLegacyDataDir();
98
+ }
99
+ return resolveCanonicalDataDir();
39
100
  }
40
101
  export function resolveDataDir() {
41
102
  return getDataDir();
42
103
  }
104
+ export function getEffectiveDataRoot() {
105
+ return dataRoot;
106
+ }
43
107
  function getDatabasePath() {
44
- return path.join(getDataDir(), "forge.sqlite");
108
+ return resolveDatabasePathForDataRoot();
45
109
  }
46
110
  export function getDatabase() {
47
111
  if (!db) {
@@ -1,5 +1,5 @@
1
1
  import path from "node:path";
2
- import { closeDatabase, configureDatabase, configureDatabaseSeeding, getDatabase, initializeDatabase } from "./db.js";
2
+ import { closeDatabase, configureDatabase, configureDatabaseSeeding, getDatabase, initializeDatabase, resolveDatabasePathForDataRoot } from "./db.js";
3
3
  const PERSONAL_CONTENT_TABLES = [
4
4
  "goals",
5
5
  "projects",
@@ -23,7 +23,7 @@ function getCounts() {
23
23
  }
24
24
  export async function seedDemoDataIntoRuntime(dataRoot = process.env.FORGE_DATA_ROOT ?? process.cwd()) {
25
25
  const resolvedDataRoot = path.resolve(dataRoot);
26
- const databasePath = path.join(resolvedDataRoot, "data", "forge.sqlite");
26
+ const databasePath = resolveDatabasePathForDataRoot(resolvedDataRoot);
27
27
  closeDatabase();
28
28
  configureDatabase({ dataRoot: resolvedDataRoot });
29
29
  configureDatabaseSeeding(false);