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,176 @@
1
+ import { createDecipheriv, createHash } from "node:crypto";
2
+ const GOOGLE_CALLBACK_PATH = "/api/v1/calendar/oauth/google/callback";
3
+ const DEFAULT_APP_PORT = "4317";
4
+ const DEFAULT_APP_BASE_URL = `http://127.0.0.1:${DEFAULT_APP_PORT}`;
5
+ const PACKAGED_DEFAULT_GOOGLE_CREDENTIAL_KEY_MATERIAL = [
6
+ "forge",
7
+ "desktop",
8
+ "oauth",
9
+ "default",
10
+ "google",
11
+ "bundle",
12
+ "2026",
13
+ "local"
14
+ ];
15
+ const PACKAGED_DEFAULT_GOOGLE_CLIENT_ID_ENCRYPTED = {
16
+ iv: "2fc1a6723312a10b7d176f13",
17
+ data: "9fbdf9dfcd1cc8674fa46150dd0f4678df8ce1ba52cdf0ceb4d4a76c9c5df01b3d8a21f194201c827524a6e06b0d4a55c7002edb3fa20b76b67f540e46ba28f506a73edaf6559a1d",
18
+ tag: "1965dfe1213ecd888e46ea59241d03a9"
19
+ };
20
+ const PACKAGED_DEFAULT_GOOGLE_CLIENT_SECRET_ENCRYPTED = {
21
+ iv: "5a6ca66625e0ff5559b34f99",
22
+ data: "b80dec231f029d92a13426ad3f0b851e20a5b35ec6691e517744fd65349144e75005f1",
23
+ tag: "9d2cfd8a153d91f60d8c628bbe1c2f25"
24
+ };
25
+ const DEFAULT_DEV_WEB_ORIGINS = [
26
+ "http://127.0.0.1:3027",
27
+ "http://localhost:3027"
28
+ ];
29
+ function decryptPackagedGoogleOauthValue(payload) {
30
+ const key = createHash("sha256")
31
+ .update(PACKAGED_DEFAULT_GOOGLE_CREDENTIAL_KEY_MATERIAL.join(":"))
32
+ .digest();
33
+ const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(payload.iv, "hex"));
34
+ decipher.setAuthTag(Buffer.from(payload.tag, "hex"));
35
+ const decrypted = Buffer.concat([
36
+ decipher.update(Buffer.from(payload.data, "hex")),
37
+ decipher.final()
38
+ ]);
39
+ return decrypted.toString("utf8");
40
+ }
41
+ const PACKAGED_DEFAULT_GOOGLE_CLIENT_ID = decryptPackagedGoogleOauthValue(PACKAGED_DEFAULT_GOOGLE_CLIENT_ID_ENCRYPTED);
42
+ const PACKAGED_DEFAULT_GOOGLE_CLIENT_SECRET = decryptPackagedGoogleOauthValue(PACKAGED_DEFAULT_GOOGLE_CLIENT_SECRET_ENCRYPTED);
43
+ function runtimeOriginFromEnv(env) {
44
+ const port = env.PORT?.trim() || DEFAULT_APP_PORT;
45
+ return `http://127.0.0.1:${port}`;
46
+ }
47
+ function normalizeOrigin(value, fieldLabel) {
48
+ let url;
49
+ try {
50
+ url = new URL(value);
51
+ }
52
+ catch {
53
+ throw new Error(`${fieldLabel} must be a full URL.`);
54
+ }
55
+ if (url.protocol !== "http:") {
56
+ throw new Error(`${fieldLabel} must use http in local Forge mode.`);
57
+ }
58
+ if (url.pathname !== "/" && url.pathname !== "") {
59
+ throw new Error(`${fieldLabel} must not include a path.`);
60
+ }
61
+ return url.origin;
62
+ }
63
+ function isLoopbackHostname(hostname) {
64
+ return hostname === "127.0.0.1" || hostname === "localhost";
65
+ }
66
+ function normalizeLoopbackOrigin(value, fieldLabel) {
67
+ const origin = normalizeOrigin(value, fieldLabel);
68
+ const url = new URL(origin);
69
+ if (!isLoopbackHostname(url.hostname)) {
70
+ throw new Error(`${fieldLabel} must use localhost or 127.0.0.1 in local Forge mode.`);
71
+ }
72
+ return origin;
73
+ }
74
+ function normalizeRedirectUri(value, appBaseUrl) {
75
+ let url;
76
+ try {
77
+ url = new URL(value);
78
+ }
79
+ catch {
80
+ throw new Error("GOOGLE_REDIRECT_URI must be a full URL.");
81
+ }
82
+ if (url.protocol !== "http:") {
83
+ throw new Error("GOOGLE_REDIRECT_URI must use http in local Forge mode.");
84
+ }
85
+ if (!isLoopbackHostname(url.hostname)) {
86
+ throw new Error("GOOGLE_REDIRECT_URI must use localhost or 127.0.0.1 in local Forge mode.");
87
+ }
88
+ if (url.pathname !== GOOGLE_CALLBACK_PATH) {
89
+ throw new Error(`GOOGLE_REDIRECT_URI must end with ${GOOGLE_CALLBACK_PATH}.`);
90
+ }
91
+ if (url.origin !== appBaseUrl) {
92
+ throw new Error(`GOOGLE_REDIRECT_URI must use the same origin as APP_BASE_URL (${appBaseUrl}).`);
93
+ }
94
+ return url.toString();
95
+ }
96
+ function normalizeAllowedOrigins(value, appBaseUrl) {
97
+ const rawValues = value && value.trim().length > 0
98
+ ? value
99
+ .split(",")
100
+ .map((entry) => entry.trim())
101
+ .filter((entry) => entry.length > 0)
102
+ : [appBaseUrl, ...DEFAULT_DEV_WEB_ORIGINS];
103
+ const normalized = rawValues.map((entry) => normalizeLoopbackOrigin(entry, "GOOGLE_ALLOWED_ORIGINS"));
104
+ return Array.from(new Set(normalized));
105
+ }
106
+ export function getGoogleCalendarOauthCallbackPath() {
107
+ return GOOGLE_CALLBACK_PATH;
108
+ }
109
+ export function resolveGoogleCalendarOauthPublicConfig(env = process.env, overrides) {
110
+ const runtimeOrigin = runtimeOriginFromEnv(env);
111
+ const appBaseUrl = normalizeLoopbackOrigin(env.APP_BASE_URL?.trim() ||
112
+ env.APP_URL?.trim() ||
113
+ DEFAULT_APP_BASE_URL, env.APP_BASE_URL?.trim() ? "APP_BASE_URL" : "APP_URL");
114
+ const redirectUri = normalizeRedirectUri(env.GOOGLE_REDIRECT_URI?.trim() || `${appBaseUrl}${GOOGLE_CALLBACK_PATH}`, appBaseUrl);
115
+ const allowedOrigins = normalizeAllowedOrigins(env.GOOGLE_ALLOWED_ORIGINS, appBaseUrl);
116
+ const storedClientId = overrides?.clientId?.trim() || "";
117
+ const storedClientSecret = overrides?.clientSecret?.trim() || "";
118
+ const envClientId = env.GOOGLE_CLIENT_ID?.trim() || "";
119
+ const envClientSecret = env.GOOGLE_CLIENT_SECRET?.trim() || "";
120
+ const hasStoredOverride = storedClientId.length > 0 || storedClientSecret.length > 0;
121
+ const hasEnvOverride = envClientId.length > 0 || envClientSecret.length > 0;
122
+ const clientId = hasStoredOverride
123
+ ? storedClientId
124
+ : hasEnvOverride
125
+ ? envClientId
126
+ : PACKAGED_DEFAULT_GOOGLE_CLIENT_ID.trim();
127
+ const clientSecret = hasStoredOverride
128
+ ? storedClientSecret
129
+ : hasEnvOverride
130
+ ? envClientSecret
131
+ : PACKAGED_DEFAULT_GOOGLE_CLIENT_SECRET.trim();
132
+ const isConfigured = clientId.length > 0;
133
+ const hasIncompleteStoredOverride = storedClientId.length > 0 !== storedClientSecret.length > 0;
134
+ const setupMessage = hasIncompleteStoredOverride
135
+ ? "Google OAuth override is incomplete for this Forge install. Save both the client ID and client secret together, or clear both fields to use the packaged default."
136
+ : isConfigured
137
+ ? "Google Calendar sign-in is configured for local Forge. Open Forge on localhost or 127.0.0.1 on the same machine that is running Forge, because Google will redirect back to the local callback on that machine."
138
+ : "Google client ID is not set for this Forge install.";
139
+ return {
140
+ clientId,
141
+ clientSecret,
142
+ storedClientId,
143
+ storedClientSecret,
144
+ appBaseUrl,
145
+ redirectUri,
146
+ allowedOrigins,
147
+ usesPkce: true,
148
+ requiresServerClientSecret: false,
149
+ oauthClientType: "desktop_app",
150
+ authMode: "localhost_pkce",
151
+ isConfigured,
152
+ isReadyForPairing: isConfigured && !hasIncompleteStoredOverride,
153
+ isLocalOnly: true,
154
+ runtimeOrigin,
155
+ setupMessage
156
+ };
157
+ }
158
+ export function resolveGoogleCalendarOauthPrivateConfig(env = process.env, overrides) {
159
+ return resolveGoogleCalendarOauthPublicConfig(env, overrides);
160
+ }
161
+ export function isGoogleCalendarOriginAllowed(origin, allowedOrigins) {
162
+ try {
163
+ return allowedOrigins.includes(new URL(origin).origin);
164
+ }
165
+ catch {
166
+ return false;
167
+ }
168
+ }
169
+ export function isGoogleCalendarLoopbackOrigin(origin) {
170
+ try {
171
+ return isLoopbackHostname(new URL(origin).hostname);
172
+ }
173
+ catch {
174
+ return false;
175
+ }
176
+ }
@@ -1220,6 +1220,9 @@ export const themePreferenceSchema = z.enum([
1220
1220
  "solar",
1221
1221
  "aurora",
1222
1222
  "ember",
1223
+ "paper",
1224
+ "dawn",
1225
+ "atelier",
1223
1226
  "custom",
1224
1227
  "system"
1225
1228
  ]);
@@ -1249,6 +1252,24 @@ export const microsoftCalendarAuthSettingsSchema = z.object({
1249
1252
  isReadyForSignIn: z.boolean(),
1250
1253
  setupMessage: z.string()
1251
1254
  });
1255
+ export const googleCalendarAuthSettingsSchema = z.object({
1256
+ clientId: z.string(),
1257
+ clientSecret: z.string(),
1258
+ storedClientId: z.string(),
1259
+ storedClientSecret: z.string(),
1260
+ appBaseUrl: z.string(),
1261
+ redirectUri: z.string(),
1262
+ allowedOrigins: z.array(z.string()),
1263
+ usesPkce: z.literal(true),
1264
+ requiresServerClientSecret: z.literal(false),
1265
+ oauthClientType: z.literal("desktop_app"),
1266
+ authMode: z.literal("localhost_pkce"),
1267
+ isConfigured: z.boolean(),
1268
+ isReadyForPairing: z.boolean(),
1269
+ isLocalOnly: z.literal(true),
1270
+ runtimeOrigin: z.string(),
1271
+ setupMessage: z.string()
1272
+ });
1252
1273
  export const aiModelProviderSchema = z.enum([
1253
1274
  "openai-api",
1254
1275
  "openai-codex",
@@ -1416,15 +1437,32 @@ export const forgeBoxToolAdapterSchema = z.object({
1416
1437
  description: trimmedString.default(""),
1417
1438
  accessMode: aiProcessorAccessModeSchema.default("read")
1418
1439
  });
1440
+ export const forgeBoxPortDefinitionSchema = z.object({
1441
+ key: nonEmptyTrimmedString,
1442
+ label: nonEmptyTrimmedString,
1443
+ kind: nonEmptyTrimmedString.default("content"),
1444
+ required: z.boolean().default(false),
1445
+ expandableKeys: z.array(nonEmptyTrimmedString).default([])
1446
+ });
1419
1447
  export const forgeBoxCatalogEntrySchema = z.object({
1420
- boxId: nonEmptyTrimmedString,
1448
+ id: nonEmptyTrimmedString,
1449
+ boxId: trimmedString.optional(),
1421
1450
  surfaceId: trimmedString.nullable(),
1422
1451
  routePath: trimmedString.nullable(),
1423
- label: nonEmptyTrimmedString,
1452
+ title: nonEmptyTrimmedString,
1453
+ label: trimmedString.optional(),
1454
+ icon: trimmedString.nullable().optional(),
1424
1455
  description: trimmedString.default(""),
1425
1456
  category: nonEmptyTrimmedString,
1426
- capabilityModes: z.array(forgeBoxCapabilityModeSchema).default(["content"]),
1427
- toolAdapters: z.array(forgeBoxToolAdapterSchema).default([])
1457
+ tags: z.array(nonEmptyTrimmedString).default([]),
1458
+ capabilityModes: z.array(forgeBoxCapabilityModeSchema).default(["content"]).optional(),
1459
+ inputs: z.array(forgeBoxPortDefinitionSchema).default([]),
1460
+ params: z.array(forgeBoxPortDefinitionSchema).default([]),
1461
+ output: z.array(forgeBoxPortDefinitionSchema).default([]),
1462
+ tools: z.array(forgeBoxToolAdapterSchema).default([]),
1463
+ outputs: z.array(forgeBoxPortDefinitionSchema).default([]).optional(),
1464
+ toolAdapters: z.array(forgeBoxToolAdapterSchema).default([]).optional(),
1465
+ snapshotResolverKey: trimmedString.optional()
1428
1466
  });
1429
1467
  export const forgeBoxSnapshotSchema = z.object({
1430
1468
  boxId: nonEmptyTrimmedString,
@@ -1436,11 +1474,16 @@ export const forgeBoxSnapshotSchema = z.object({
1436
1474
  });
1437
1475
  export const aiConnectorKindSchema = z.enum(["functor", "chat"]);
1438
1476
  export const aiConnectorNodeTypeSchema = z.enum([
1477
+ "box",
1439
1478
  "box_input",
1479
+ "value",
1440
1480
  "user_input",
1441
1481
  "functor",
1442
1482
  "chat",
1443
- "output"
1483
+ "output",
1484
+ "merge",
1485
+ "template",
1486
+ "pick_key"
1444
1487
  ]);
1445
1488
  export const aiConnectorNodeModelConfigSchema = z.object({
1446
1489
  connectionId: trimmedString.nullable().default(null),
@@ -1462,9 +1505,20 @@ export const aiConnectorNodeSchema = z.object({
1462
1505
  description: trimmedString.default(""),
1463
1506
  boxId: trimmedString.nullable().optional(),
1464
1507
  prompt: trimmedString.optional(),
1508
+ promptTemplate: trimmedString.optional(),
1465
1509
  systemPrompt: trimmedString.optional(),
1466
1510
  outputKey: trimmedString.optional(),
1467
1511
  enabledToolKeys: z.array(nonEmptyTrimmedString).default([]),
1512
+ inputs: z.array(forgeBoxPortDefinitionSchema).default([]).optional(),
1513
+ outputs: z.array(forgeBoxPortDefinitionSchema).default([]).optional(),
1514
+ params: z.array(forgeBoxPortDefinitionSchema).default([]).optional(),
1515
+ paramValues: z.record(z.string(), z.unknown()).default({}).optional(),
1516
+ template: trimmedString.optional(),
1517
+ selectedKey: trimmedString.optional(),
1518
+ valueType: z
1519
+ .enum(["string", "number", "boolean", "null", "array", "object"])
1520
+ .optional(),
1521
+ valueLiteral: trimmedString.optional(),
1468
1522
  modelConfig: aiConnectorNodeModelConfigSchema.optional()
1469
1523
  })
1470
1524
  });
@@ -1488,7 +1542,31 @@ export const aiConnectorRunResultSchema = z.object({
1488
1542
  label: z.string(),
1489
1543
  text: z.string(),
1490
1544
  json: z.record(z.string(), z.unknown()).nullable()
1491
- }))
1545
+ })),
1546
+ debugTrace: z
1547
+ .object({
1548
+ nodes: z.array(z.object({
1549
+ nodeId: nonEmptyTrimmedString,
1550
+ nodeType: aiConnectorNodeTypeSchema,
1551
+ label: nonEmptyTrimmedString,
1552
+ input: z.array(z.object({
1553
+ sourceNodeId: nonEmptyTrimmedString,
1554
+ sourceHandle: trimmedString.nullable(),
1555
+ targetHandle: trimmedString.nullable(),
1556
+ text: z.string(),
1557
+ json: z.record(z.string(), z.unknown()).nullable()
1558
+ })),
1559
+ output: z.object({
1560
+ text: z.string(),
1561
+ json: z.record(z.string(), z.unknown()).nullable()
1562
+ }),
1563
+ tools: z.array(z.string()).default([]),
1564
+ logs: z.array(z.string()).default([]),
1565
+ error: z.string().nullable()
1566
+ })),
1567
+ errors: z.array(z.string()).default([])
1568
+ })
1569
+ .optional()
1492
1570
  });
1493
1571
  export const aiConnectorRunSchema = z.object({
1494
1572
  id: nonEmptyTrimmedString,
@@ -1792,6 +1870,7 @@ export const settingsPayloadSchema = z.object({
1792
1870
  psycheAuthRequired: z.boolean()
1793
1871
  }),
1794
1872
  calendarProviders: z.object({
1873
+ google: googleCalendarAuthSettingsSchema,
1795
1874
  microsoft: microsoftCalendarAuthSettingsSchema
1796
1875
  }),
1797
1876
  modelSettings: modelSettingsPayloadSchema,
@@ -2008,10 +2087,7 @@ export const createCalendarConnectionSchema = z.discriminatedUnion("provider", [
2008
2087
  z.object({
2009
2088
  provider: z.literal("google"),
2010
2089
  label: nonEmptyTrimmedString,
2011
- username: nonEmptyTrimmedString,
2012
- clientId: nonEmptyTrimmedString,
2013
- clientSecret: nonEmptyTrimmedString,
2014
- refreshToken: nonEmptyTrimmedString,
2090
+ authSessionId: nonEmptyTrimmedString,
2015
2091
  selectedCalendarUrls: z.array(nonEmptyTrimmedString.url()).min(1),
2016
2092
  forgeCalendarUrl: nonEmptyTrimmedString.url().nullable().optional(),
2017
2093
  createForgeCalendar: z.boolean().optional().default(false)
@@ -2043,13 +2119,6 @@ export const createCalendarConnectionSchema = z.discriminatedUnion("provider", [
2043
2119
  })
2044
2120
  ]);
2045
2121
  export const discoverCalendarConnectionSchema = z.discriminatedUnion("provider", [
2046
- z.object({
2047
- provider: z.literal("google"),
2048
- username: nonEmptyTrimmedString,
2049
- clientId: nonEmptyTrimmedString,
2050
- clientSecret: nonEmptyTrimmedString,
2051
- refreshToken: nonEmptyTrimmedString
2052
- }),
2053
2122
  z.object({
2054
2123
  provider: z.literal("apple"),
2055
2124
  username: nonEmptyTrimmedString,
@@ -2065,6 +2134,10 @@ export const discoverCalendarConnectionSchema = z.discriminatedUnion("provider",
2065
2134
  export const startMicrosoftCalendarOauthSchema = z.object({
2066
2135
  label: nonEmptyTrimmedString.optional()
2067
2136
  });
2137
+ export const startGoogleCalendarOauthSchema = z.object({
2138
+ label: nonEmptyTrimmedString.optional(),
2139
+ browserOrigin: trimmedString.optional()
2140
+ });
2068
2141
  export const testMicrosoftCalendarOauthConfigurationSchema = z.object({
2069
2142
  clientId: nonEmptyTrimmedString.regex(/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/, "Microsoft client IDs must use the standard app registration GUID format."),
2070
2143
  tenantId: trimmedString.default("common"),
@@ -2078,6 +2151,14 @@ export const microsoftCalendarOauthSessionSchema = z.object({
2078
2151
  error: z.string().nullable(),
2079
2152
  discovery: calendarDiscoveryPayloadSchema.nullable()
2080
2153
  });
2154
+ export const googleCalendarOauthSessionSchema = z.object({
2155
+ sessionId: nonEmptyTrimmedString,
2156
+ status: z.enum(["pending", "authorized", "error", "consumed", "expired"]),
2157
+ authUrl: z.string().url().nullable(),
2158
+ accountLabel: z.string().nullable(),
2159
+ error: z.string().nullable(),
2160
+ discovery: calendarDiscoveryPayloadSchema.nullable()
2161
+ });
2081
2162
  export const updateCalendarConnectionSchema = z.object({
2082
2163
  label: nonEmptyTrimmedString.optional(),
2083
2164
  selectedCalendarUrls: z.array(nonEmptyTrimmedString.url()).optional()
@@ -2595,6 +2676,12 @@ export const updateSettingsSchema = z.object({
2595
2676
  .optional(),
2596
2677
  calendarProviders: z
2597
2678
  .object({
2679
+ google: z
2680
+ .object({
2681
+ clientId: trimmedString.optional(),
2682
+ clientSecret: trimmedString.optional()
2683
+ })
2684
+ .optional(),
2598
2685
  microsoft: z
2599
2686
  .object({
2600
2687
  clientId: trimmedString.optional(),
@@ -2603,7 +2690,37 @@ export const updateSettingsSchema = z.object({
2603
2690
  })
2604
2691
  .optional()
2605
2692
  })
2606
- .optional(),
2693
+ .optional()
2694
+ .superRefine((value, context) => {
2695
+ if (!value) {
2696
+ return;
2697
+ }
2698
+ const google = value.google;
2699
+ if (!google) {
2700
+ return;
2701
+ }
2702
+ const hasClientIdField = google.clientId !== undefined;
2703
+ const hasClientSecretField = google.clientSecret !== undefined;
2704
+ const hasClientIdValue = (google.clientId?.length ?? 0) > 0;
2705
+ const hasClientSecretValue = (google.clientSecret?.length ?? 0) > 0;
2706
+ if (hasClientIdField !== hasClientSecretField) {
2707
+ const message = "When overriding Google OAuth credentials, provide both the client ID and client secret together, or clear both fields together.";
2708
+ context.addIssue({
2709
+ code: z.ZodIssueCode.custom,
2710
+ path: ["google", hasClientIdField ? "clientSecret" : "clientId"],
2711
+ message
2712
+ });
2713
+ return;
2714
+ }
2715
+ if (hasClientIdValue !== hasClientSecretValue) {
2716
+ const message = "When overriding Google OAuth credentials, provide both the client ID and client secret together, or clear both fields together.";
2717
+ context.addIssue({
2718
+ code: z.ZodIssueCode.custom,
2719
+ path: ["google", hasClientIdValue ? "clientSecret" : "clientId"],
2720
+ message
2721
+ });
2722
+ }
2723
+ }),
2607
2724
  modelSettings: z
2608
2725
  .object({
2609
2726
  forgeAgent: z
@@ -2748,7 +2865,8 @@ export const runAiConnectorSchema = z.object({
2748
2865
  userInput: trimmedString.default(""),
2749
2866
  context: z.record(z.string(), z.unknown()).default({}),
2750
2867
  boxSnapshots: z.record(z.string(), z.unknown()).default({}),
2751
- conversationId: trimmedString.nullable().default(null)
2868
+ conversationId: trimmedString.nullable().default(null),
2869
+ debug: z.boolean().default(false)
2752
2870
  });
2753
2871
  export const createAgentTokenSchema = z.object({
2754
2872
  label: nonEmptyTrimmedString,
@@ -2,7 +2,6 @@ import { access, readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  const distDir = path.join(process.cwd(), "dist");
4
4
  const packagedRuntimeDistDir = path.join(process.cwd(), "plugins", "forge-codex", "runtime", "dist");
5
- const defaultBasePath = process.env.FORGE_BASE_PATH ?? "/forge/";
6
5
  const contentTypes = {
7
6
  ".css": "text/css; charset=utf-8",
8
7
  ".html": "text/html; charset=utf-8",
@@ -20,6 +19,18 @@ function normalizeBasePath(value) {
20
19
  const withLeadingSlash = value.startsWith("/") ? value : `/${value}`;
21
20
  return withLeadingSlash.endsWith("/") ? withLeadingSlash : `${withLeadingSlash}/`;
22
21
  }
22
+ function normalizeAbsoluteUrl(value) {
23
+ const url = new URL(value);
24
+ url.pathname = normalizeBasePath(url.pathname);
25
+ return url;
26
+ }
27
+ function getDefaultBasePath() {
28
+ return process.env.FORGE_BASE_PATH ?? "/forge/";
29
+ }
30
+ function getDevWebOrigin() {
31
+ const value = process.env.FORGE_DEV_WEB_ORIGIN?.trim();
32
+ return value && value.length > 0 ? value : null;
33
+ }
23
34
  function stripBasePath(requestPath, basePath) {
24
35
  const normalizedBasePath = normalizeBasePath(basePath);
25
36
  if (normalizedBasePath === "/") {
@@ -57,8 +68,16 @@ async function serveAsset(requestPath, reply) {
57
68
  reply.code(404);
58
69
  return { error: "Not found" };
59
70
  }
71
+ const normalizedRequestPath = stripBasePath(requestPath, getDefaultBasePath());
72
+ const devWebOrigin = getDevWebOrigin();
73
+ if (devWebOrigin) {
74
+ const target = new URL(normalizedRequestPath.startsWith("/")
75
+ ? normalizedRequestPath.slice(1)
76
+ : normalizedRequestPath, normalizeAbsoluteUrl(devWebOrigin));
77
+ reply.code(307).redirect(target.toString());
78
+ return reply;
79
+ }
60
80
  const clientDir = await getClientDir();
61
- const normalizedRequestPath = stripBasePath(requestPath, defaultBasePath);
62
81
  const assetPath = resolveAsset(clientDir, normalizedRequestPath);
63
82
  const ext = path.extname(assetPath);
64
83
  try {