forge-openclaw-plugin 0.2.25 → 0.2.26

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 (189) hide show
  1. package/dist/assets/{board-VmF4FAfr.js → board-ta0rUHOf.js} +3 -3
  2. package/dist/assets/{board-VmF4FAfr.js.map → board-ta0rUHOf.js.map} +1 -1
  3. package/dist/assets/index-Ro0ZF_az.css +1 -0
  4. package/dist/assets/index-ytlpSj23.js +79 -0
  5. package/dist/assets/index-ytlpSj23.js.map +1 -0
  6. package/dist/assets/{motion-DvkU14p-.js → motion-fBKPB6yw.js} +2 -2
  7. package/dist/assets/{motion-DvkU14p-.js.map → motion-fBKPB6yw.js.map} +1 -1
  8. package/dist/assets/{table-DgiPof9E.js → table-C-IGTQni.js} +2 -2
  9. package/dist/assets/{table-DgiPof9E.js.map → table-C-IGTQni.js.map} +1 -1
  10. package/dist/assets/{ui-nYfoC0Gq.js → ui-DInOpaYF.js} +2 -2
  11. package/dist/assets/{ui-nYfoC0Gq.js.map → ui-DInOpaYF.js.map} +1 -1
  12. package/dist/assets/vendor-lE3tZJcC.js +876 -0
  13. package/dist/assets/vendor-lE3tZJcC.js.map +1 -0
  14. package/dist/index.html +7 -8
  15. package/dist/openclaw/local-runtime.d.ts +3 -1
  16. package/dist/openclaw/local-runtime.js +51 -15
  17. package/dist/openclaw/plugin-entry-shared.js +24 -2
  18. package/dist/openclaw/plugin-sdk-types.d.ts +17 -0
  19. package/dist/openclaw/tools.js +0 -3
  20. package/dist/server/server/migrations/001_core.sql +411 -0
  21. package/dist/server/server/migrations/002_psyche.sql +392 -0
  22. package/dist/server/server/migrations/003_habits.sql +30 -0
  23. package/dist/server/server/migrations/004_habit_links.sql +8 -0
  24. package/dist/server/server/migrations/005_habit_psyche_links.sql +24 -0
  25. package/dist/server/server/migrations/006_work_adjustments.sql +14 -0
  26. package/dist/server/server/migrations/007_weekly_review_closures.sql +17 -0
  27. package/dist/server/server/migrations/008_calendar_execution.sql +147 -0
  28. package/dist/server/server/migrations/009_true_calendar_events.sql +195 -0
  29. package/dist/server/server/migrations/010_calendar_selection_state.sql +6 -0
  30. package/dist/server/server/migrations/011_calendar_timezone_backfill.sql +11 -0
  31. package/dist/server/server/migrations/012_work_block_ranges.sql +7 -0
  32. package/dist/server/server/migrations/013_microsoft_local_auth_settings.sql +8 -0
  33. package/dist/server/server/migrations/014_note_tags_and_ephemeral.sql +8 -0
  34. package/dist/server/server/migrations/015_multi_user_and_strategies.sql +244 -0
  35. package/dist/server/server/migrations/016_health_companion.sql +158 -0
  36. package/dist/server/server/migrations/016_strategy_contracts_and_user_graph.sql +22 -0
  37. package/dist/server/server/migrations/017_preferences.sql +131 -0
  38. package/dist/server/server/migrations/018_preference_catalogs.sql +31 -0
  39. package/dist/server/server/migrations/019_wiki_memory.sql +255 -0
  40. package/dist/server/server/migrations/020_wiki_page_hierarchy.sql +11 -0
  41. package/dist/server/server/migrations/021_hide_evidence_from_wiki_index.sql +3 -0
  42. package/dist/server/server/migrations/022_wiki_ingest_background.sql +85 -0
  43. package/dist/server/server/migrations/023_diagnostic_logs.sql +28 -0
  44. package/dist/server/server/migrations/024_questionnaires.sql +96 -0
  45. package/dist/server/server/migrations/025_ai_model_connections.sql +26 -0
  46. package/dist/server/server/migrations/026_custom_theme_settings.sql +2 -0
  47. package/dist/server/server/migrations/027_ai_processors.sql +31 -0
  48. package/dist/server/server/migrations/028_movement_domain.sql +136 -0
  49. package/dist/server/server/migrations/029_watch_micro_capture.sql +23 -0
  50. package/dist/server/server/migrations/030_surface_layouts.sql +5 -0
  51. package/dist/server/server/migrations/031_ai_processor_runtime_upgrades.sql +10 -0
  52. package/dist/server/server/migrations/032_ai_connectors.sql +44 -0
  53. package/dist/server/server/migrations/033_movement_trip_point_sync.sql +36 -0
  54. package/dist/server/server/migrations/034_movement_segment_sync.sql +49 -0
  55. package/dist/server/server/migrations/035_google_local_auth_settings.sql +2 -0
  56. package/dist/server/server/migrations/036_google_local_auth_client_secret.sql +2 -0
  57. package/dist/server/{app.js → server/src/app.js} +242 -111
  58. package/dist/server/server/src/connectors/box-registry.js +188 -0
  59. package/dist/server/{db.js → server/src/db.js} +4 -0
  60. package/dist/server/server/src/debug.js +19 -0
  61. package/dist/server/{openapi.js → server/src/openapi.js} +2 -2
  62. package/dist/server/{repositories → server/src/repositories}/ai-connectors.js +286 -23
  63. package/dist/server/{repositories → server/src/repositories}/calendar.js +1 -1
  64. package/dist/server/{repositories → server/src/repositories}/settings.js +51 -3
  65. package/dist/server/{services → server/src/services}/calendar-runtime.js +775 -58
  66. package/dist/server/server/src/services/google-calendar-oauth-config.js +176 -0
  67. package/dist/server/{types.js → server/src/types.js} +137 -19
  68. package/dist/server/{web.js → server/src/web.js} +21 -2
  69. package/dist/server/src/components/customization/utility-widgets.js +330 -0
  70. package/dist/server/src/components/workbench-boxes/health/health-boxes.js +92 -0
  71. package/dist/server/src/components/workbench-boxes/kanban/kanban-boxes.js +128 -0
  72. package/dist/server/src/components/workbench-boxes/movement/movement-boxes.js +37 -0
  73. package/dist/server/src/components/workbench-boxes/notes/notes-boxes.js +114 -0
  74. package/dist/server/src/components/workbench-boxes/projects/projects-boxes.js +57 -0
  75. package/dist/server/src/components/workbench-boxes/shared/define-workbench-box.js +4 -0
  76. package/dist/server/src/components/workbench-boxes/shared/generic-node-view.js +13 -0
  77. package/dist/server/src/components/workbench-boxes/today/today-boxes.js +63 -0
  78. package/dist/server/src/lib/api-error.js +37 -0
  79. package/dist/server/src/lib/api.js +1859 -0
  80. package/dist/server/src/lib/calendar-name-deduper.js +144 -0
  81. package/dist/server/src/lib/diagnostics.js +67 -0
  82. package/dist/server/src/lib/psyche-types.js +1 -0
  83. package/dist/server/src/lib/questionnaire-types.js +1 -0
  84. package/dist/server/src/lib/runtime-paths.js +24 -0
  85. package/dist/server/src/lib/schemas.js +234 -0
  86. package/dist/server/src/lib/snapshot-normalizer.js +374 -0
  87. package/dist/server/src/lib/theme-system.js +319 -0
  88. package/dist/server/src/lib/types.js +1 -0
  89. package/dist/server/src/lib/utils.js +22 -0
  90. package/dist/server/src/lib/workbench/boxes.js +16 -0
  91. package/dist/server/src/lib/workbench/nodes.js +15 -0
  92. package/dist/server/src/lib/workbench/registry.js +73 -0
  93. package/dist/server/src/lib/workbench/runtime.js +181 -0
  94. package/openclaw.plugin.json +1 -1
  95. package/package.json +1 -1
  96. package/server/index.js +68 -0
  97. package/server/migrations/035_google_local_auth_settings.sql +2 -0
  98. package/server/migrations/036_google_local_auth_client_secret.sql +2 -0
  99. package/skills/forge-openclaw/SKILL.md +3 -0
  100. package/skills/forge-openclaw/entity_conversation_playbooks.md +213 -24
  101. package/skills/forge-openclaw/psyche_entity_playbooks.md +82 -3
  102. package/dist/assets/index-CFCKDIMH.js +0 -67
  103. package/dist/assets/index-CFCKDIMH.js.map +0 -1
  104. package/dist/assets/index-ZPY6U1TU.css +0 -1
  105. package/dist/assets/vendor-D9PTEPSB.js +0 -824
  106. package/dist/assets/vendor-D9PTEPSB.js.map +0 -1
  107. package/dist/assets/viz-Cqb6s--o.js +0 -34
  108. package/dist/assets/viz-Cqb6s--o.js.map +0 -1
  109. package/dist/server/connectors/box-registry.js +0 -257
  110. /package/dist/server/{demo-data.js → server/src/demo-data.js} +0 -0
  111. /package/dist/server/{discovery-advertiser.js → server/src/discovery-advertiser.js} +0 -0
  112. /package/dist/server/{e2e-server.js → server/src/e2e-server.js} +0 -0
  113. /package/dist/server/{errors.js → server/src/errors.js} +0 -0
  114. /package/dist/server/{health.js → server/src/health.js} +0 -0
  115. /package/dist/server/{index.js → server/src/index.js} +0 -0
  116. /package/dist/server/{managers → server/src/managers}/base.js +0 -0
  117. /package/dist/server/{managers → server/src/managers}/contracts.js +0 -0
  118. /package/dist/server/{managers → server/src/managers}/platform/api-gateway-manager.js +0 -0
  119. /package/dist/server/{managers → server/src/managers}/platform/audit-manager.js +0 -0
  120. /package/dist/server/{managers → server/src/managers}/platform/authentication-manager.js +0 -0
  121. /package/dist/server/{managers → server/src/managers}/platform/authorization-manager.js +0 -0
  122. /package/dist/server/{managers → server/src/managers}/platform/background-job-manager.js +0 -0
  123. /package/dist/server/{managers → server/src/managers}/platform/configuration-manager.js +0 -0
  124. /package/dist/server/{managers → server/src/managers}/platform/database-manager.js +0 -0
  125. /package/dist/server/{managers → server/src/managers}/platform/event-bus-manager.js +0 -0
  126. /package/dist/server/{managers → server/src/managers}/platform/external-service-manager.js +0 -0
  127. /package/dist/server/{managers → server/src/managers}/platform/health-manager.js +0 -0
  128. /package/dist/server/{managers → server/src/managers}/platform/llm-manager.js +0 -0
  129. /package/dist/server/{managers → server/src/managers}/platform/migration-manager.js +0 -0
  130. /package/dist/server/{managers → server/src/managers}/platform/openai-responses-provider.js +0 -0
  131. /package/dist/server/{managers → server/src/managers}/platform/search-index-manager.js +0 -0
  132. /package/dist/server/{managers → server/src/managers}/platform/secrets-manager.js +0 -0
  133. /package/dist/server/{managers → server/src/managers}/platform/session-manager.js +0 -0
  134. /package/dist/server/{managers → server/src/managers}/platform/storage-manager.js +0 -0
  135. /package/dist/server/{managers → server/src/managers}/platform/token-manager.js +0 -0
  136. /package/dist/server/{managers → server/src/managers}/platform/transaction-manager.js +0 -0
  137. /package/dist/server/{managers → server/src/managers}/platform/trusted-network.js +0 -0
  138. /package/dist/server/{managers → server/src/managers}/runtime.js +0 -0
  139. /package/dist/server/{managers → server/src/managers}/type-guards.js +0 -0
  140. /package/dist/server/{movement.js → server/src/movement.js} +0 -0
  141. /package/dist/server/{preferences-seeds.js → server/src/preferences-seeds.js} +0 -0
  142. /package/dist/server/{preferences-types.js → server/src/preferences-types.js} +0 -0
  143. /package/dist/server/{psyche-types.js → server/src/psyche-types.js} +0 -0
  144. /package/dist/server/{questionnaire-flow.js → server/src/questionnaire-flow.js} +0 -0
  145. /package/dist/server/{questionnaire-seeds.js → server/src/questionnaire-seeds.js} +0 -0
  146. /package/dist/server/{questionnaire-types.js → server/src/questionnaire-types.js} +0 -0
  147. /package/dist/server/{repositories → server/src/repositories}/activity-events.js +0 -0
  148. /package/dist/server/{repositories → server/src/repositories}/ai-processors.js +0 -0
  149. /package/dist/server/{repositories → server/src/repositories}/collaboration.js +0 -0
  150. /package/dist/server/{repositories → server/src/repositories}/deleted-entities.js +0 -0
  151. /package/dist/server/{repositories → server/src/repositories}/diagnostic-logs.js +0 -0
  152. /package/dist/server/{repositories → server/src/repositories}/domains.js +0 -0
  153. /package/dist/server/{repositories → server/src/repositories}/entity-ownership.js +0 -0
  154. /package/dist/server/{repositories → server/src/repositories}/event-log.js +0 -0
  155. /package/dist/server/{repositories → server/src/repositories}/goals.js +0 -0
  156. /package/dist/server/{repositories → server/src/repositories}/habits.js +0 -0
  157. /package/dist/server/{repositories → server/src/repositories}/model-settings.js +0 -0
  158. /package/dist/server/{repositories → server/src/repositories}/notes.js +0 -0
  159. /package/dist/server/{repositories → server/src/repositories}/preferences.js +0 -0
  160. /package/dist/server/{repositories → server/src/repositories}/projects.js +0 -0
  161. /package/dist/server/{repositories → server/src/repositories}/psyche.js +0 -0
  162. /package/dist/server/{repositories → server/src/repositories}/questionnaires.js +0 -0
  163. /package/dist/server/{repositories → server/src/repositories}/rewards.js +0 -0
  164. /package/dist/server/{repositories → server/src/repositories}/strategies.js +0 -0
  165. /package/dist/server/{repositories → server/src/repositories}/surface-layouts.js +0 -0
  166. /package/dist/server/{repositories → server/src/repositories}/tags.js +0 -0
  167. /package/dist/server/{repositories → server/src/repositories}/task-runs.js +0 -0
  168. /package/dist/server/{repositories → server/src/repositories}/tasks.js +0 -0
  169. /package/dist/server/{repositories → server/src/repositories}/users.js +0 -0
  170. /package/dist/server/{repositories → server/src/repositories}/weekly-reviews.js +0 -0
  171. /package/dist/server/{repositories → server/src/repositories}/wiki-memory.js +0 -0
  172. /package/dist/server/{repositories → server/src/repositories}/work-adjustments.js +0 -0
  173. /package/dist/server/{seed-demo.js → server/src/seed-demo.js} +0 -0
  174. /package/dist/server/{services → server/src/services}/context.js +0 -0
  175. /package/dist/server/{services → server/src/services}/dashboard.js +0 -0
  176. /package/dist/server/{services → server/src/services}/entity-crud.js +0 -0
  177. /package/dist/server/{services → server/src/services}/gamification.js +0 -0
  178. /package/dist/server/{services → server/src/services}/insights.js +0 -0
  179. /package/dist/server/{services → server/src/services}/openai-codex-oauth.js +0 -0
  180. /package/dist/server/{services → server/src/services}/projects.js +0 -0
  181. /package/dist/server/{services → server/src/services}/psyche-observation-calendar.js +0 -0
  182. /package/dist/server/{services → server/src/services}/psyche.js +0 -0
  183. /package/dist/server/{services → server/src/services}/relations.js +0 -0
  184. /package/dist/server/{services → server/src/services}/reviews.js +0 -0
  185. /package/dist/server/{services → server/src/services}/run-recovery.js +0 -0
  186. /package/dist/server/{services → server/src/services}/tagging.js +0 -0
  187. /package/dist/server/{services → server/src/services}/task-run-watchdog.js +0 -0
  188. /package/dist/server/{services → server/src/services}/work-time.js +0 -0
  189. /package/dist/server/{watch-mobile.js → server/src/watch-mobile.js} +0 -0
@@ -0,0 +1,144 @@
1
+ function normalizeNameKey(value) {
2
+ return value.trim().replace(/\s+/g, " ").toLocaleLowerCase();
3
+ }
4
+ function cleanLabel(value) {
5
+ const trimmed = value?.trim();
6
+ return trimmed ? trimmed : null;
7
+ }
8
+ function readBaseCalendarName(value) {
9
+ return cleanLabel(value) ?? "Unnamed calendar";
10
+ }
11
+ function shortCalendarProviderLabel(provider) {
12
+ switch (provider) {
13
+ case "google":
14
+ return "Google";
15
+ case "apple":
16
+ return "Apple";
17
+ case "microsoft":
18
+ return "Microsoft";
19
+ case "caldav":
20
+ default:
21
+ return "CalDAV";
22
+ }
23
+ }
24
+ function readUrlQualifier(value) {
25
+ const trimmed = cleanLabel(value);
26
+ if (!trimmed) {
27
+ return null;
28
+ }
29
+ try {
30
+ const url = new URL(trimmed);
31
+ const segments = url.pathname
32
+ .split("/")
33
+ .map((segment) => segment.trim())
34
+ .filter(Boolean);
35
+ const lastSegment = segments.at(-1);
36
+ if (lastSegment) {
37
+ return `${url.host}/${decodeURIComponent(lastSegment)}`;
38
+ }
39
+ return url.host;
40
+ }
41
+ catch {
42
+ return trimmed;
43
+ }
44
+ }
45
+ function joinQualifier(parts) {
46
+ const cleaned = parts
47
+ .map(cleanLabel)
48
+ .filter((part) => Boolean(part));
49
+ return cleaned.length > 0 ? cleaned.join(" · ") : null;
50
+ }
51
+ function selectUniqueQualifier(group) {
52
+ const selectors = [
53
+ (entry) => entry.providerLabel,
54
+ (entry) => joinQualifier([entry.providerLabel, entry.accountLabel]),
55
+ (entry) => joinQualifier([entry.providerLabel, entry.connectionLabel]),
56
+ (entry) => entry.connectionLabel,
57
+ (entry) => entry.accountLabel,
58
+ (entry) => readUrlQualifier(entry.url),
59
+ (entry) => entry.url
60
+ ];
61
+ for (const select of selectors) {
62
+ const qualifiers = group.map(select);
63
+ if (qualifiers.some((qualifier) => !cleanLabel(qualifier))) {
64
+ continue;
65
+ }
66
+ const normalized = qualifiers.map((qualifier) => normalizeNameKey(qualifier));
67
+ if (new Set(normalized).size === group.length) {
68
+ return qualifiers;
69
+ }
70
+ }
71
+ return group.map((entry, index) => joinQualifier([entry.providerLabel, `${index + 1}`]) ?? `${index + 1}`);
72
+ }
73
+ function buildDedupedNameMap(entries) {
74
+ const deduped = new Map();
75
+ const groups = new Map();
76
+ for (const entry of entries) {
77
+ const key = normalizeNameKey(entry.baseName);
78
+ const bucket = groups.get(key) ?? [];
79
+ bucket.push(entry);
80
+ groups.set(key, bucket);
81
+ }
82
+ for (const group of groups.values()) {
83
+ if (group.length === 1) {
84
+ deduped.set(group[0].id, group[0].baseName);
85
+ continue;
86
+ }
87
+ const qualifiers = selectUniqueQualifier(group);
88
+ group.forEach((entry, index) => {
89
+ deduped.set(entry.id, `${entry.baseName} (${qualifiers[index]})`);
90
+ });
91
+ }
92
+ return deduped;
93
+ }
94
+ export function dedupeCalendarDiscoveryPayload(payload) {
95
+ const dedupedNames = buildDedupedNameMap(payload.calendars.map((calendar) => ({
96
+ id: calendar.url,
97
+ baseName: readBaseCalendarName(calendar.displayName),
98
+ providerLabel: shortCalendarProviderLabel(payload.provider),
99
+ connectionLabel: null,
100
+ accountLabel: payload.accountLabel,
101
+ url: calendar.url
102
+ })));
103
+ return {
104
+ ...payload,
105
+ calendars: payload.calendars.map((calendar) => ({
106
+ ...calendar,
107
+ dedupedName: dedupedNames.get(calendar.url) ??
108
+ readBaseCalendarName(calendar.displayName)
109
+ }))
110
+ };
111
+ }
112
+ export function dedupeCalendarResourcesWithConnections(calendars, connections) {
113
+ const connectionsById = new Map(connections.map((connection) => [connection.id, connection]));
114
+ const dedupedNames = buildDedupedNameMap(calendars.map((calendar) => {
115
+ const connection = connectionsById.get(calendar.connectionId);
116
+ return {
117
+ id: calendar.id,
118
+ baseName: readBaseCalendarName(calendar.title),
119
+ providerLabel: connection
120
+ ? shortCalendarProviderLabel(connection.provider)
121
+ : null,
122
+ connectionLabel: connection?.label ?? null,
123
+ accountLabel: connection?.accountLabel ?? null,
124
+ url: calendar.remoteId
125
+ };
126
+ }));
127
+ return calendars.map((calendar) => ({
128
+ ...calendar,
129
+ dedupedName: dedupedNames.get(calendar.id) ?? readBaseCalendarName(calendar.title)
130
+ }));
131
+ }
132
+ export function dedupeCalendarOverviewPayload(payload) {
133
+ return {
134
+ ...payload,
135
+ calendars: dedupeCalendarResourcesWithConnections(payload.calendars, payload.connections)
136
+ };
137
+ }
138
+ export function readCalendarDisplayName(calendar) {
139
+ if ("title" in calendar) {
140
+ return (cleanLabel(calendar.dedupedName) ?? readBaseCalendarName(calendar.title));
141
+ }
142
+ return (cleanLabel(calendar.dedupedName) ??
143
+ readBaseCalendarName(calendar.displayName));
144
+ }
@@ -0,0 +1,67 @@
1
+ import { resolveForgePath } from "./runtime-paths.js";
2
+ function sanitizeValue(value, depth = 0) {
3
+ if (value === null ||
4
+ typeof value === "boolean" ||
5
+ typeof value === "number" ||
6
+ typeof value === "string") {
7
+ return value;
8
+ }
9
+ if (typeof value === "bigint") {
10
+ return value.toString();
11
+ }
12
+ if (value instanceof Error) {
13
+ return {
14
+ name: value.name,
15
+ message: value.message,
16
+ stack: value.stack ?? null
17
+ };
18
+ }
19
+ if (Array.isArray(value)) {
20
+ if (depth >= 3) {
21
+ return `[Array(${value.length})]`;
22
+ }
23
+ return value.slice(0, 20).map((entry) => sanitizeValue(entry, depth + 1));
24
+ }
25
+ if (value && typeof value === "object") {
26
+ if (depth >= 3) {
27
+ return "[Object]";
28
+ }
29
+ return Object.fromEntries(Object.entries(value)
30
+ .slice(0, 30)
31
+ .map(([key, entry]) => [key, sanitizeValue(entry, depth + 1)]));
32
+ }
33
+ return String(value);
34
+ }
35
+ function sanitizeDetails(details) {
36
+ if (!details) {
37
+ return {};
38
+ }
39
+ return Object.fromEntries(Object.entries(details).map(([key, value]) => [key, sanitizeValue(value)]));
40
+ }
41
+ export async function publishUiDiagnosticLog(input) {
42
+ try {
43
+ await fetch(resolveForgePath("/api/v1/diagnostics/logs"), {
44
+ method: "POST",
45
+ credentials: "same-origin",
46
+ keepalive: true,
47
+ headers: {
48
+ "content-type": "application/json",
49
+ "x-forge-source": "ui"
50
+ },
51
+ body: JSON.stringify({
52
+ ...input,
53
+ source: input.source ?? "ui",
54
+ details: sanitizeDetails(input.details)
55
+ })
56
+ });
57
+ }
58
+ catch {
59
+ // Diagnostics should never break the user flow.
60
+ }
61
+ }
62
+ export function createUiDiagnosticLogger(defaults) {
63
+ return (input) => publishUiDiagnosticLog({
64
+ ...defaults,
65
+ ...input
66
+ });
67
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ export function normalizeAssetBasePath(basePath) {
2
+ if (!basePath || basePath === "/") {
3
+ return "/";
4
+ }
5
+ const withLeadingSlash = basePath.startsWith("/") ? basePath : `/${basePath}`;
6
+ return withLeadingSlash.endsWith("/") ? withLeadingSlash : `${withLeadingSlash}/`;
7
+ }
8
+ export function normalizeRouterBasename(basePath) {
9
+ const normalized = normalizeAssetBasePath(basePath);
10
+ if (normalized === "/") {
11
+ return "/";
12
+ }
13
+ return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
14
+ }
15
+ function getBaseUrl() {
16
+ return new URL(normalizeAssetBasePath(import.meta.env.BASE_URL || "/"), window.location.origin);
17
+ }
18
+ export function resolveForgePath(pathname) {
19
+ if (pathname.startsWith("/api/")) {
20
+ return pathname;
21
+ }
22
+ const normalized = pathname.startsWith("/") ? pathname.slice(1) : pathname;
23
+ return new URL(normalized, getBaseUrl()).pathname;
24
+ }
@@ -0,0 +1,234 @@
1
+ import { z } from "zod";
2
+ import { forgeCustomThemeSchema, forgeThemePreferenceSchema } from "@/lib/theme-system";
3
+ export const appLocaleSchema = z.enum(["en", "fr"]);
4
+ export const inlineCreateNoteSchema = z.object({
5
+ contentMarkdown: z.string().trim().min(1, "Note content is required"),
6
+ author: z.string().trim()
7
+ });
8
+ export const goalMutationSchema = z.object({
9
+ title: z.string().trim().min(1, "Title is required"),
10
+ description: z.string().trim(),
11
+ horizon: z.enum(["quarter", "year", "lifetime"]),
12
+ status: z.enum(["active", "paused", "completed"]),
13
+ userId: z.string().trim().nullable().optional(),
14
+ targetPoints: z.coerce.number().int().min(25).max(10000),
15
+ themeColor: z
16
+ .string()
17
+ .trim()
18
+ .regex(/^#[0-9a-fA-F]{6}$/, "Theme color must be a valid hex value"),
19
+ tagIds: z.array(z.string()),
20
+ notes: z.array(inlineCreateNoteSchema)
21
+ });
22
+ export const projectMutationSchema = z.object({
23
+ goalId: z.string().trim().min(1, "Life goal is required"),
24
+ title: z.string().trim().min(1, "Title is required"),
25
+ description: z.string().trim(),
26
+ status: z.enum(["active", "paused", "completed"]),
27
+ userId: z.string().trim().nullable().optional(),
28
+ targetPoints: z.coerce.number().int().min(25).max(10000),
29
+ themeColor: z
30
+ .string()
31
+ .trim()
32
+ .regex(/^#[0-9a-fA-F]{6}$/, "Theme color must be a valid hex value"),
33
+ notes: z.array(inlineCreateNoteSchema)
34
+ });
35
+ export const settingsMutationSchema = z.object({
36
+ profile: z.object({
37
+ operatorName: z.string().trim().min(1, "Name is required"),
38
+ operatorEmail: z.string().trim().min(1, "Email is required"),
39
+ operatorTitle: z.string().trim().min(1, "Title is required")
40
+ }),
41
+ notifications: z.object({
42
+ goalDriftAlerts: z.boolean(),
43
+ dailyQuestReminders: z.boolean(),
44
+ achievementCelebrations: z.boolean()
45
+ }),
46
+ execution: z.object({
47
+ maxActiveTasks: z.coerce.number().int().min(1).max(8),
48
+ timeAccountingMode: z.enum(["split", "parallel", "primary_only"])
49
+ }),
50
+ themePreference: forgeThemePreferenceSchema,
51
+ customTheme: forgeCustomThemeSchema.nullable().optional(),
52
+ localePreference: appLocaleSchema,
53
+ calendarProviders: z
54
+ .object({
55
+ google: z
56
+ .object({
57
+ clientId: z.string().trim().optional(),
58
+ clientSecret: z.string().trim().optional(),
59
+ storedClientId: z.string().optional(),
60
+ storedClientSecret: z.string().optional(),
61
+ appBaseUrl: z.string().optional(),
62
+ redirectUri: z.string().optional(),
63
+ allowedOrigins: z.array(z.string()).optional(),
64
+ usesPkce: z.literal(true).optional(),
65
+ requiresServerClientSecret: z.literal(false).optional(),
66
+ oauthClientType: z.literal("desktop_app").optional(),
67
+ authMode: z.literal("localhost_pkce").optional(),
68
+ isConfigured: z.boolean().optional(),
69
+ isReadyForPairing: z.boolean().optional(),
70
+ isLocalOnly: z.literal(true).optional(),
71
+ runtimeOrigin: z.string().optional(),
72
+ setupMessage: z.string().optional()
73
+ })
74
+ .optional(),
75
+ microsoft: z
76
+ .object({
77
+ clientId: z.string().trim(),
78
+ tenantId: z.string().trim(),
79
+ redirectUri: z.string().trim()
80
+ })
81
+ .optional()
82
+ })
83
+ .optional()
84
+ .superRefine((value, context) => {
85
+ const google = value?.google;
86
+ if (!google) {
87
+ return;
88
+ }
89
+ const hasClientIdField = google.clientId !== undefined;
90
+ const hasClientSecretField = google.clientSecret !== undefined;
91
+ const hasClientIdValue = (google.clientId?.length ?? 0) > 0;
92
+ const hasClientSecretValue = (google.clientSecret?.length ?? 0) > 0;
93
+ if (hasClientIdField !== hasClientSecretField) {
94
+ context.addIssue({
95
+ code: z.ZodIssueCode.custom,
96
+ path: ["google", hasClientIdField ? "clientSecret" : "clientId"],
97
+ message: "Provide both the Google client ID and client secret together, or clear both together."
98
+ });
99
+ return;
100
+ }
101
+ if (hasClientIdValue !== hasClientSecretValue) {
102
+ context.addIssue({
103
+ code: z.ZodIssueCode.custom,
104
+ path: ["google", hasClientIdValue ? "clientSecret" : "clientId"],
105
+ message: "Provide both the Google client ID and client secret together, or clear both together."
106
+ });
107
+ }
108
+ }),
109
+ modelSettings: z
110
+ .object({
111
+ forgeAgent: z
112
+ .object({
113
+ basicChat: z
114
+ .object({
115
+ connectionId: z.string().trim().nullable().optional(),
116
+ model: z.string().trim().optional()
117
+ })
118
+ .optional(),
119
+ wiki: z
120
+ .object({
121
+ connectionId: z.string().trim().nullable().optional(),
122
+ model: z.string().trim().optional()
123
+ })
124
+ .optional()
125
+ })
126
+ .optional()
127
+ })
128
+ .optional()
129
+ });
130
+ export const createAgentTokenSchema = z.object({
131
+ label: z.string().trim().min(1, "Label is required"),
132
+ agentLabel: z.string().trim().min(1, "Agent name is required"),
133
+ agentType: z.string().trim().min(1, "Agent type is required"),
134
+ description: z.string().trim(),
135
+ trustLevel: z.enum(["standard", "trusted", "autonomous"]),
136
+ autonomyMode: z.enum(["approval_required", "scoped_write", "autonomous"]),
137
+ approvalMode: z.enum(["approval_by_default", "high_impact_only", "none"]),
138
+ scopes: z.array(z.string().trim().min(1)).min(1)
139
+ });
140
+ export const createInsightSchema = z.object({
141
+ originType: z.enum(["system", "user", "agent"]),
142
+ originAgentId: z.string().trim(),
143
+ originLabel: z.string().trim(),
144
+ entityType: z.string().trim(),
145
+ entityId: z.string().trim(),
146
+ timeframeLabel: z.string().trim(),
147
+ title: z.string().trim().min(1, "Title is required"),
148
+ summary: z.string().trim().min(1, "Summary is required"),
149
+ recommendation: z.string().trim().min(1, "Recommendation is required"),
150
+ rationale: z.string().trim(),
151
+ confidence: z.coerce.number().min(0).max(1),
152
+ ctaLabel: z.string().trim().min(1, "CTA label is required")
153
+ });
154
+ export const quickTaskSchema = z.object({
155
+ title: z.string().trim().min(1, "Title is required"),
156
+ description: z.string().trim(),
157
+ owner: z.string().trim().min(1, "Owner is required"),
158
+ userId: z.string().trim().nullable().optional(),
159
+ goalId: z.string().trim(),
160
+ projectId: z.string().trim().min(1, "Project is required"),
161
+ priority: z.enum(["low", "medium", "high", "critical"]),
162
+ status: z.enum(["backlog", "focus", "in_progress", "blocked", "done"]),
163
+ effort: z.enum(["light", "deep", "marathon"]),
164
+ energy: z.enum(["low", "steady", "high"]),
165
+ dueDate: z.string().trim(),
166
+ points: z.coerce.number().int().min(5).max(500),
167
+ tagIds: z.array(z.string()),
168
+ notes: z.array(inlineCreateNoteSchema)
169
+ });
170
+ export const habitMutationSchema = z
171
+ .object({
172
+ title: z.string().trim().min(1, "Title is required"),
173
+ description: z.string().trim(),
174
+ status: z.enum(["active", "paused", "archived"]),
175
+ userId: z.string().trim().nullable().optional(),
176
+ polarity: z.enum(["positive", "negative"]),
177
+ frequency: z.enum(["daily", "weekly"]),
178
+ targetCount: z.coerce.number().int().min(1).max(14),
179
+ weekDays: z.array(z.number().int().min(0).max(6)).max(7),
180
+ linkedGoalIds: z.array(z.string().trim().min(1)),
181
+ linkedProjectIds: z.array(z.string().trim().min(1)),
182
+ linkedTaskIds: z.array(z.string().trim().min(1)),
183
+ linkedValueIds: z.array(z.string().trim().min(1)),
184
+ linkedPatternIds: z.array(z.string().trim().min(1)),
185
+ linkedBehaviorIds: z.array(z.string().trim().min(1)),
186
+ linkedBeliefIds: z.array(z.string().trim().min(1)),
187
+ linkedModeIds: z.array(z.string().trim().min(1)),
188
+ linkedReportIds: z.array(z.string().trim().min(1)),
189
+ linkedBehaviorId: z.string().trim(),
190
+ rewardXp: z.coerce.number().int().min(1).max(100),
191
+ penaltyXp: z.coerce.number().int().min(1).max(100),
192
+ generatedHealthEventTemplate: z.object({
193
+ enabled: z.boolean(),
194
+ workoutType: z.string().trim(),
195
+ title: z.string().trim(),
196
+ durationMinutes: z.coerce.number().int().min(1).max(24 * 60),
197
+ xpReward: z.coerce.number().int().min(0).max(500),
198
+ tags: z.array(z.string().trim()),
199
+ links: z.array(z.object({
200
+ entityType: z.string().trim().min(1),
201
+ entityId: z.string().trim().min(1),
202
+ relationshipType: z.string().trim().default("context")
203
+ })),
204
+ notesTemplate: z.string().trim()
205
+ })
206
+ })
207
+ .superRefine((value, context) => {
208
+ if (value.frequency === "weekly" && value.weekDays.length === 0) {
209
+ context.addIssue({
210
+ code: z.ZodIssueCode.custom,
211
+ path: ["weekDays"],
212
+ message: "Pick at least one weekday"
213
+ });
214
+ }
215
+ });
216
+ export const workAdjustmentMutationSchema = z.object({
217
+ entityType: z.enum(["task", "project"]),
218
+ entityId: z.string().trim().min(1, "A target is required"),
219
+ deltaMinutes: z.coerce
220
+ .number()
221
+ .int()
222
+ .refine((value) => value !== 0, "Minutes must not be zero"),
223
+ note: z.string().trim()
224
+ });
225
+ export const tagMutationSchema = z.object({
226
+ name: z.string().trim().min(1, "Name is required"),
227
+ kind: z.enum(["value", "category", "execution"]),
228
+ userId: z.string().trim().nullable().optional(),
229
+ color: z
230
+ .string()
231
+ .trim()
232
+ .regex(/^#[0-9a-fA-F]{6}$/, "Color must be a valid hex value"),
233
+ description: z.string().trim()
234
+ });