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
@@ -3,48 +3,109 @@ function asRecord(value) {
3
3
  ? value
4
4
  : null;
5
5
  }
6
- export function buildWorkbenchOutputMap(text, json, keys) {
7
- const outputMap = {
8
- primary: {
9
- text,
10
- json
6
+ function readTextValue(...values) {
7
+ for (const value of values) {
8
+ if (typeof value === "string") {
9
+ return value;
11
10
  }
12
- };
13
- for (const key of keys) {
14
- if (!json || !(key in json)) {
15
- outputMap[key] = {
16
- text,
17
- json
18
- };
11
+ }
12
+ return "";
13
+ }
14
+ function readNumberValue(...values) {
15
+ for (const value of values) {
16
+ if (typeof value === "number" && Number.isFinite(value)) {
17
+ return value;
18
+ }
19
+ if (typeof value === "string") {
20
+ const parsed = Number(value);
21
+ if (Number.isFinite(parsed)) {
22
+ return parsed;
23
+ }
24
+ }
25
+ }
26
+ return null;
27
+ }
28
+ function readStringArrayValue(...values) {
29
+ for (const value of values) {
30
+ if (Array.isArray(value)) {
31
+ const normalized = value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
32
+ if (normalized.length > 0) {
33
+ return normalized;
34
+ }
19
35
  continue;
20
36
  }
21
- const value = json[key];
22
- outputMap[key] = {
23
- text: typeof value === "string"
24
- ? value
25
- : Array.isArray(value) || asRecord(value)
26
- ? JSON.stringify(value, null, 2)
27
- : String(value ?? ""),
28
- json: asRecord(value)
29
- };
37
+ if (typeof value === "string") {
38
+ const trimmed = value.trim();
39
+ if (!trimmed) {
40
+ continue;
41
+ }
42
+ try {
43
+ const parsed = JSON.parse(trimmed);
44
+ if (Array.isArray(parsed)) {
45
+ const normalized = parsed.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
46
+ if (normalized.length > 0) {
47
+ return normalized;
48
+ }
49
+ }
50
+ }
51
+ catch {
52
+ const normalized = trimmed
53
+ .split(",")
54
+ .map((entry) => entry.trim())
55
+ .filter((entry) => entry.length > 0);
56
+ if (normalized.length > 0) {
57
+ return normalized;
58
+ }
59
+ }
60
+ }
30
61
  }
62
+ return [];
63
+ }
64
+ export function buildWorkbenchOutputMap(text, json, outputs) {
65
+ const outputMap = {};
66
+ const declaredOutputs = outputs.length > 0 ? outputs : [{ key: "summary" }];
67
+ declaredOutputs.forEach((output, index) => {
68
+ const rawValue = json && output.key in json
69
+ ? json[output.key]
70
+ : index === 0 || output.key === "summary"
71
+ ? text
72
+ : null;
73
+ outputMap[output.key] = {
74
+ text: typeof rawValue === "string"
75
+ ? rawValue
76
+ : Array.isArray(rawValue) || asRecord(rawValue)
77
+ ? JSON.stringify(rawValue, null, 2)
78
+ : String(rawValue ?? ""),
79
+ json: asRecord(rawValue)
80
+ };
81
+ });
31
82
  return outputMap;
32
83
  }
84
+ function normalizeWorkbenchOutputPayload(definition, output, primaryText) {
85
+ const declaredOutputs = definition.output ?? [];
86
+ if (!output && declaredOutputs.length === 0) {
87
+ return null;
88
+ }
89
+ const normalized = output ? { ...output } : {};
90
+ if (declaredOutputs.length > 0) {
91
+ const leadKey = declaredOutputs[0]?.key;
92
+ if (leadKey && !(leadKey in normalized)) {
93
+ normalized[leadKey] = primaryText;
94
+ }
95
+ if (declaredOutputs.some((entry) => entry.key === "summary") &&
96
+ !("summary" in normalized)) {
97
+ normalized.summary = primaryText;
98
+ }
99
+ }
100
+ return normalized;
101
+ }
33
102
  export function buildWorkbenchExecutionEnvelope(input, value) {
34
- const payload = {
35
- nodeId: input.nodeId,
36
- nodeType: input.definition.id,
37
- title: input.definition.title,
38
- inputs: input.inputs,
39
- params: input.params,
40
- output: value.output,
41
- logs: value.logs ?? []
42
- };
103
+ const payload = normalizeWorkbenchOutputPayload(input.definition, value.output, value.primaryText);
43
104
  return {
44
105
  primaryText: value.primaryText,
45
106
  payload,
46
107
  logs: value.logs ?? [],
47
- outputMap: buildWorkbenchOutputMap(value.primaryText, payload, Object.keys(value.output ?? {}))
108
+ outputMap: buildWorkbenchOutputMap(value.primaryText, payload, input.definition.output)
48
109
  };
49
110
  }
50
111
  export function buildStaticWorkbenchExecution(input, output, primaryText, logs) {
@@ -86,17 +147,25 @@ export function searchWorkbenchEntities(context, definition, input) {
86
147
  summaryText: summaryLines.length > 0
87
148
  ? summaryLines.join("\n")
88
149
  : `No ${definition.title.toLowerCase()} matches found.`,
89
- limit
150
+ limit,
151
+ query: input.query
90
152
  };
91
153
  }
92
154
  export function buildSearchWorkbenchExecution(input, config) {
93
- const summary = searchWorkbenchEntities(input.context, input.definition, config);
155
+ const query = readTextValue(input.inputs.query, input.params.query, config.query).trim();
156
+ const entityTypes = readStringArrayValue(input.inputs.entityTypes, input.params.entityTypes, config.entityTypes);
157
+ const limit = readNumberValue(input.inputs.limit, input.params.limit, config.limit) ?? config.limit ?? 12;
158
+ const summary = searchWorkbenchEntities(input.context, input.definition, {
159
+ query,
160
+ entityTypes,
161
+ limit
162
+ });
94
163
  return buildWorkbenchExecutionEnvelope(input, {
95
164
  primaryText: summary.summaryText,
96
165
  output: {
166
+ summary: summary.summaryText,
97
167
  matches: summary.matches,
98
- limit: summary.limit,
99
- entityTypes: config.entityTypes
168
+ matchCount: summary.matches.length
100
169
  }
101
170
  });
102
171
  }
@@ -116,6 +185,9 @@ export function buildMovementPlacesExecution(input) {
116
185
  .join("\n")
117
186
  : "No known places are stored yet.",
118
187
  output: {
188
+ summary: places.length > 0
189
+ ? `${places.length} place${places.length === 1 ? "" : "s"} available.`
190
+ : "No known places are stored yet.",
119
191
  places
120
192
  }
121
193
  });
@@ -126,7 +198,14 @@ export function buildSleepWorkbenchExecution(input) {
126
198
  primaryText: payload && typeof payload === "object"
127
199
  ? "Sleep history and derived patterns are available."
128
200
  : "No sleep data is available.",
129
- output: asRecord(payload)
201
+ output: payload && typeof payload === "object"
202
+ ? {
203
+ summary: "Sleep history and derived patterns are available.",
204
+ sleepView: payload
205
+ }
206
+ : {
207
+ summary: "No sleep data is available."
208
+ }
130
209
  });
131
210
  }
132
211
  export function buildSportsWorkbenchExecution(input) {
@@ -135,11 +214,146 @@ export function buildSportsWorkbenchExecution(input) {
135
214
  primaryText: payload && typeof payload === "object"
136
215
  ? "Workout history and composition are available."
137
216
  : "No sports data is available.",
138
- output: asRecord(payload)
217
+ output: payload && typeof payload === "object"
218
+ ? {
219
+ summary: "Workout history and composition are available.",
220
+ sportsView: payload
221
+ }
222
+ : {
223
+ summary: "No sports data is available."
224
+ }
225
+ });
226
+ }
227
+ export function buildOverviewWorkbenchExecution(input) {
228
+ const payload = input.context.services.overview.getContext?.() ?? null;
229
+ const record = asRecord(payload);
230
+ const summary = record
231
+ ? [
232
+ `Projects: ${Array.isArray(record.projects) ? record.projects.length : 0}`,
233
+ `Goals: ${Array.isArray(record.activeGoals) ? record.activeGoals.length : 0}`,
234
+ `Top tasks: ${Array.isArray(record.topTasks) ? record.topTasks.length : 0}`,
235
+ `Due habits: ${Array.isArray(record.dueHabits) ? record.dueHabits.length : 0}`
236
+ ].join("\n")
237
+ : "No overview context is available.";
238
+ return buildWorkbenchExecutionEnvelope(input, {
239
+ primaryText: summary,
240
+ output: record
241
+ ? {
242
+ summary,
243
+ context: record
244
+ }
245
+ : {
246
+ summary
247
+ }
248
+ });
249
+ }
250
+ export function buildInsightsWorkbenchExecution(input) {
251
+ const payload = input.context.services.overview.getInsights?.() ?? null;
252
+ const record = asRecord(payload);
253
+ const status = asRecord(record?.status);
254
+ const coaching = asRecord(record?.coaching);
255
+ const summary = record
256
+ ? [
257
+ typeof status?.systemStatus === "string" ? status.systemStatus : "Insights ready",
258
+ typeof coaching?.title === "string" ? coaching.title : null,
259
+ typeof coaching?.summary === "string" ? coaching.summary : null
260
+ ]
261
+ .filter(Boolean)
262
+ .join("\n")
263
+ : "No insights payload is available.";
264
+ return buildWorkbenchExecutionEnvelope(input, {
265
+ primaryText: summary,
266
+ output: record
267
+ ? {
268
+ summary,
269
+ insights: record
270
+ }
271
+ : {
272
+ summary
273
+ }
274
+ });
275
+ }
276
+ export function buildWeeklyReviewWorkbenchExecution(input) {
277
+ const payload = input.context.services.overview.getWeeklyReview?.() ?? null;
278
+ const record = asRecord(payload);
279
+ const momentum = asRecord(record?.momentumSummary);
280
+ const summary = record
281
+ ? [
282
+ typeof record.windowLabel === "string" ? record.windowLabel : "Weekly review",
283
+ typeof momentum?.totalXp === "number" ? `${momentum.totalXp} XP` : null,
284
+ typeof momentum?.focusHours === "number"
285
+ ? `${momentum.focusHours} focus hours`
286
+ : null
287
+ ]
288
+ .filter(Boolean)
289
+ .join("\n")
290
+ : "No weekly review payload is available.";
291
+ return buildWorkbenchExecutionEnvelope(input, {
292
+ primaryText: summary,
293
+ output: record
294
+ ? {
295
+ summary,
296
+ weeklyReview: record
297
+ }
298
+ : {
299
+ summary
300
+ }
301
+ });
302
+ }
303
+ export function buildWikiPagesWorkbenchExecution(input) {
304
+ const pages = input.context.services.wiki.listPages?.() ?? [];
305
+ const summary = pages.length > 0
306
+ ? pages
307
+ .slice(0, 12)
308
+ .map((page) => typeof page.title === "string"
309
+ ? page.title
310
+ : typeof page.slug === "string"
311
+ ? page.slug
312
+ : typeof page.id === "string"
313
+ ? page.id
314
+ : "Wiki page")
315
+ .join("\n")
316
+ : "No wiki pages are available.";
317
+ return buildWorkbenchExecutionEnvelope(input, {
318
+ primaryText: summary,
319
+ output: {
320
+ summary,
321
+ pages
322
+ }
323
+ });
324
+ }
325
+ export function buildWikiHealthWorkbenchExecution(input) {
326
+ const payload = input.context.services.wiki.getHealth?.() ?? null;
327
+ const record = asRecord(payload);
328
+ const unresolvedLinks = Array.isArray(record?.unresolvedLinks)
329
+ ? record.unresolvedLinks.length
330
+ : null;
331
+ const orphanPages = Array.isArray(record?.orphanPages)
332
+ ? record.orphanPages.length
333
+ : null;
334
+ const summary = record
335
+ ? [
336
+ "Wiki health summary",
337
+ unresolvedLinks !== null ? `${unresolvedLinks} unresolved links` : null,
338
+ orphanPages !== null ? `${orphanPages} orphan pages` : null
339
+ ]
340
+ .filter(Boolean)
341
+ .join("\n")
342
+ : "No wiki health payload is available.";
343
+ return buildWorkbenchExecutionEnvelope(input, {
344
+ primaryText: summary,
345
+ output: record
346
+ ? {
347
+ summary,
348
+ health: record
349
+ }
350
+ : {
351
+ summary
352
+ }
139
353
  });
140
354
  }
141
355
  export function mapWorkbenchTools(tools) {
142
- return tools.map(({ argsSchema: _argsSchema, ...tool }) => tool);
356
+ return tools.map((tool) => tool);
143
357
  }
144
358
  export function executeCommonWorkbenchTool(context, definition, toolKey, args) {
145
359
  if (toolKey === "forge.search_entities") {
@@ -173,6 +387,8 @@ export function executeCommonWorkbenchTool(context, definition, toolKey, args) {
173
387
  title: typeof args.title === "string" ? args.title : "Workbench note",
174
388
  contentMarkdown: typeof args.markdown === "string" ? args.markdown : "",
175
389
  summary: typeof args.summary === "string" ? args.summary : "",
390
+ links: [],
391
+ tags: [],
176
392
  sourcePath: "workbench",
177
393
  author: "Workbench"
178
394
  });
@@ -0,0 +1,68 @@
1
+ function rankAccessMode(mode) {
2
+ switch (mode) {
3
+ case "exec":
4
+ return 4;
5
+ case "read_write":
6
+ return 3;
7
+ case "write":
8
+ return 2;
9
+ case "read":
10
+ default:
11
+ return 1;
12
+ }
13
+ }
14
+ function preferAccessMode(left, right) {
15
+ return rankAccessMode(left) >= rankAccessMode(right) ? left : right;
16
+ }
17
+ function normalizeToolDescription(toolKey, descriptions) {
18
+ if (toolKey === "forge.search_entities") {
19
+ return "Search across Forge entities. You can optionally narrow the search to specific entity types.";
20
+ }
21
+ if (toolKey === "forge.create_note") {
22
+ return "Create a Forge note from generated content or captured markdown.";
23
+ }
24
+ if (toolKey === "forge.update_task_status") {
25
+ return "Move a task between execution states such as backlog, focus, in progress, blocked, and done.";
26
+ }
27
+ return descriptions.sort((left, right) => right.length - left.length)[0] ?? "Workbench tool";
28
+ }
29
+ export function buildWorkbenchToolCatalog(boxes) {
30
+ const byKey = new Map();
31
+ for (const box of boxes) {
32
+ for (const tool of box.tools) {
33
+ const current = byKey.get(tool.key);
34
+ if (!current) {
35
+ byKey.set(tool.key, {
36
+ key: tool.key,
37
+ label: tool.label,
38
+ description: normalizeToolDescription(tool.key, [tool.description]),
39
+ accessMode: tool.accessMode,
40
+ argsSchema: tool.argsSchema,
41
+ sources: [box.title],
42
+ sourceSurfaceIds: box.surfaceId ? [box.surfaceId] : []
43
+ });
44
+ continue;
45
+ }
46
+ current.accessMode = preferAccessMode(current.accessMode, tool.accessMode);
47
+ current.label = current.label.length >= tool.label.length ? current.label : tool.label;
48
+ current.description = normalizeToolDescription(tool.key, [
49
+ current.description,
50
+ tool.description
51
+ ]);
52
+ current.argsSchema = current.argsSchema ?? tool.argsSchema;
53
+ if (!current.sources.includes(box.title)) {
54
+ current.sources.push(box.title);
55
+ }
56
+ if (box.surfaceId && !current.sourceSurfaceIds.includes(box.surfaceId)) {
57
+ current.sourceSurfaceIds.push(box.surfaceId);
58
+ }
59
+ }
60
+ }
61
+ return [...byKey.values()].sort((left, right) => {
62
+ const accessDelta = rankAccessMode(right.accessMode) - rankAccessMode(left.accessMode);
63
+ if (accessDelta !== 0) {
64
+ return accessDelta;
65
+ }
66
+ return left.label.localeCompare(right.label);
67
+ });
68
+ }
@@ -2,7 +2,7 @@
2
2
  "id": "forge-openclaw-plugin",
3
3
  "name": "Forge",
4
4
  "description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
5
- "version": "0.2.26",
5
+ "version": "0.2.28",
6
6
  "skills": [
7
7
  "./skills"
8
8
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-openclaw-plugin",
3
- "version": "0.2.26",
3
+ "version": "0.2.28",
4
4
  "description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -0,0 +1,5 @@
1
+ ALTER TABLE ai_connectors
2
+ ADD COLUMN public_inputs_json TEXT NOT NULL DEFAULT '[]';
3
+
4
+ ALTER TABLE ai_connector_runs
5
+ ADD COLUMN inputs_json TEXT NOT NULL DEFAULT '{}';
@@ -0,0 +1,11 @@
1
+ CREATE TABLE IF NOT EXISTS data_management_settings (
2
+ id INTEGER PRIMARY KEY CHECK (id = 1),
3
+ preferred_data_root TEXT NOT NULL DEFAULT '',
4
+ backup_directory TEXT NOT NULL DEFAULT '',
5
+ backup_frequency_hours INTEGER,
6
+ auto_repair_enabled INTEGER NOT NULL DEFAULT 1,
7
+ last_auto_backup_at TEXT,
8
+ last_manual_backup_at TEXT,
9
+ created_at TEXT NOT NULL,
10
+ updated_at TEXT NOT NULL
11
+ );
@@ -0,0 +1,114 @@
1
+ ALTER TABLE tasks
2
+ ADD COLUMN resolution_kind TEXT;
3
+
4
+ ALTER TABLE tasks
5
+ ADD COLUMN split_parent_task_id TEXT;
6
+
7
+ CREATE TABLE IF NOT EXISTS life_force_profiles (
8
+ user_id TEXT PRIMARY KEY,
9
+ base_daily_ap INTEGER NOT NULL DEFAULT 200,
10
+ readiness_multiplier REAL NOT NULL DEFAULT 1.0,
11
+ life_force_level INTEGER NOT NULL DEFAULT 1,
12
+ activation_level INTEGER NOT NULL DEFAULT 1,
13
+ focus_level INTEGER NOT NULL DEFAULT 1,
14
+ vigor_level INTEGER NOT NULL DEFAULT 1,
15
+ composure_level INTEGER NOT NULL DEFAULT 1,
16
+ flow_level INTEGER NOT NULL DEFAULT 1,
17
+ created_at TEXT NOT NULL,
18
+ updated_at TEXT NOT NULL
19
+ );
20
+
21
+ CREATE TABLE IF NOT EXISTS life_force_weekday_templates (
22
+ id TEXT PRIMARY KEY,
23
+ user_id TEXT NOT NULL,
24
+ weekday INTEGER NOT NULL,
25
+ baseline_daily_ap INTEGER NOT NULL DEFAULT 200,
26
+ points_json TEXT NOT NULL,
27
+ created_at TEXT NOT NULL,
28
+ updated_at TEXT NOT NULL,
29
+ UNIQUE(user_id, weekday)
30
+ );
31
+
32
+ CREATE TABLE IF NOT EXISTS life_force_day_snapshots (
33
+ id TEXT PRIMARY KEY,
34
+ user_id TEXT NOT NULL,
35
+ date_key TEXT NOT NULL,
36
+ daily_budget_ap REAL NOT NULL,
37
+ sleep_recovery_multiplier REAL NOT NULL DEFAULT 1.0,
38
+ readiness_multiplier REAL NOT NULL DEFAULT 1.0,
39
+ fatigue_debt_carry REAL NOT NULL DEFAULT 0,
40
+ points_json TEXT NOT NULL,
41
+ created_at TEXT NOT NULL,
42
+ updated_at TEXT NOT NULL,
43
+ UNIQUE(user_id, date_key)
44
+ );
45
+
46
+ CREATE TABLE IF NOT EXISTS action_profile_templates (
47
+ id TEXT PRIMARY KEY,
48
+ profile_key TEXT NOT NULL UNIQUE,
49
+ entity_type TEXT,
50
+ title TEXT NOT NULL,
51
+ profile_json TEXT NOT NULL,
52
+ created_at TEXT NOT NULL,
53
+ updated_at TEXT NOT NULL
54
+ );
55
+
56
+ CREATE TABLE IF NOT EXISTS entity_action_profiles (
57
+ id TEXT PRIMARY KEY,
58
+ entity_type TEXT NOT NULL,
59
+ entity_id TEXT NOT NULL,
60
+ profile_json TEXT NOT NULL,
61
+ created_at TEXT NOT NULL,
62
+ updated_at TEXT NOT NULL,
63
+ UNIQUE(entity_type, entity_id)
64
+ );
65
+
66
+ CREATE TABLE IF NOT EXISTS ap_ledger_events (
67
+ id TEXT PRIMARY KEY,
68
+ user_id TEXT NOT NULL,
69
+ date_key TEXT NOT NULL,
70
+ entity_type TEXT NOT NULL,
71
+ entity_id TEXT NOT NULL,
72
+ event_kind TEXT NOT NULL,
73
+ source_kind TEXT NOT NULL,
74
+ starts_at TEXT,
75
+ ends_at TEXT,
76
+ total_ap REAL NOT NULL,
77
+ rate_ap_per_hour REAL,
78
+ metadata_json TEXT NOT NULL DEFAULT '{}',
79
+ created_at TEXT NOT NULL
80
+ );
81
+
82
+ CREATE INDEX IF NOT EXISTS idx_ap_ledger_user_date
83
+ ON ap_ledger_events(user_id, date_key, created_at DESC);
84
+
85
+ CREATE INDEX IF NOT EXISTS idx_ap_ledger_entity
86
+ ON ap_ledger_events(entity_type, entity_id, created_at DESC);
87
+
88
+ CREATE TABLE IF NOT EXISTS stat_xp_events (
89
+ id TEXT PRIMARY KEY,
90
+ user_id TEXT NOT NULL,
91
+ stat_key TEXT NOT NULL,
92
+ delta_xp REAL NOT NULL,
93
+ entity_type TEXT,
94
+ entity_id TEXT,
95
+ metadata_json TEXT NOT NULL DEFAULT '{}',
96
+ created_at TEXT NOT NULL
97
+ );
98
+
99
+ CREATE INDEX IF NOT EXISTS idx_stat_xp_user_stat
100
+ ON stat_xp_events(user_id, stat_key, created_at DESC);
101
+
102
+ CREATE TABLE IF NOT EXISTS fatigue_signals (
103
+ id TEXT PRIMARY KEY,
104
+ user_id TEXT NOT NULL,
105
+ date_key TEXT NOT NULL,
106
+ signal_type TEXT NOT NULL,
107
+ observed_at TEXT NOT NULL,
108
+ note TEXT NOT NULL DEFAULT '',
109
+ delta REAL NOT NULL DEFAULT 0,
110
+ created_at TEXT NOT NULL
111
+ );
112
+
113
+ CREATE INDEX IF NOT EXISTS idx_fatigue_signals_user_date
114
+ ON fatigue_signals(user_id, date_key, observed_at DESC);
@@ -0,0 +1,89 @@
1
+ CREATE TABLE IF NOT EXISTS screen_time_settings (
2
+ user_id TEXT PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
3
+ tracking_enabled INTEGER NOT NULL DEFAULT 0,
4
+ sync_enabled INTEGER NOT NULL DEFAULT 1,
5
+ authorization_status TEXT NOT NULL DEFAULT 'not_determined',
6
+ capture_state TEXT NOT NULL DEFAULT 'disabled',
7
+ last_captured_day_key TEXT,
8
+ last_capture_started_at TEXT,
9
+ last_capture_ended_at TEXT,
10
+ metadata_json TEXT NOT NULL DEFAULT '{}',
11
+ created_at TEXT NOT NULL,
12
+ updated_at TEXT NOT NULL
13
+ );
14
+
15
+ CREATE TABLE IF NOT EXISTS screen_time_day_summaries (
16
+ id TEXT PRIMARY KEY,
17
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
18
+ pairing_session_id TEXT REFERENCES companion_pairing_sessions(id) ON DELETE SET NULL,
19
+ source_device TEXT NOT NULL DEFAULT 'iPhone',
20
+ date_key TEXT NOT NULL,
21
+ total_activity_seconds INTEGER NOT NULL DEFAULT 0,
22
+ pickup_count INTEGER NOT NULL DEFAULT 0,
23
+ notification_count INTEGER NOT NULL DEFAULT 0,
24
+ first_pickup_at TEXT,
25
+ longest_activity_seconds INTEGER NOT NULL DEFAULT 0,
26
+ top_app_bundle_ids_json TEXT NOT NULL DEFAULT '[]',
27
+ top_category_labels_json TEXT NOT NULL DEFAULT '[]',
28
+ metadata_json TEXT NOT NULL DEFAULT '{}',
29
+ created_at TEXT NOT NULL,
30
+ updated_at TEXT NOT NULL,
31
+ UNIQUE (user_id, source_device, date_key)
32
+ );
33
+
34
+ CREATE INDEX IF NOT EXISTS idx_screen_time_day_summaries_user
35
+ ON screen_time_day_summaries(user_id, date_key DESC);
36
+
37
+ CREATE TABLE IF NOT EXISTS screen_time_hourly_segments (
38
+ id TEXT PRIMARY KEY,
39
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
40
+ pairing_session_id TEXT REFERENCES companion_pairing_sessions(id) ON DELETE SET NULL,
41
+ source_device TEXT NOT NULL DEFAULT 'iPhone',
42
+ date_key TEXT NOT NULL,
43
+ hour_index INTEGER NOT NULL,
44
+ started_at TEXT NOT NULL,
45
+ ended_at TEXT NOT NULL,
46
+ total_activity_seconds INTEGER NOT NULL DEFAULT 0,
47
+ pickup_count INTEGER NOT NULL DEFAULT 0,
48
+ notification_count INTEGER NOT NULL DEFAULT 0,
49
+ first_pickup_at TEXT,
50
+ longest_activity_started_at TEXT,
51
+ longest_activity_ended_at TEXT,
52
+ metadata_json TEXT NOT NULL DEFAULT '{}',
53
+ created_at TEXT NOT NULL,
54
+ updated_at TEXT NOT NULL,
55
+ UNIQUE (user_id, source_device, date_key, hour_index)
56
+ );
57
+
58
+ CREATE INDEX IF NOT EXISTS idx_screen_time_hourly_segments_user
59
+ ON screen_time_hourly_segments(user_id, started_at DESC);
60
+
61
+ CREATE TABLE IF NOT EXISTS screen_time_app_usage (
62
+ id TEXT PRIMARY KEY,
63
+ segment_id TEXT NOT NULL REFERENCES screen_time_hourly_segments(id) ON DELETE CASCADE,
64
+ bundle_identifier TEXT NOT NULL,
65
+ display_name TEXT NOT NULL DEFAULT '',
66
+ category_label TEXT,
67
+ total_activity_seconds INTEGER NOT NULL DEFAULT 0,
68
+ pickup_count INTEGER NOT NULL DEFAULT 0,
69
+ notification_count INTEGER NOT NULL DEFAULT 0,
70
+ created_at TEXT NOT NULL,
71
+ updated_at TEXT NOT NULL,
72
+ UNIQUE (segment_id, bundle_identifier)
73
+ );
74
+
75
+ CREATE INDEX IF NOT EXISTS idx_screen_time_app_usage_segment
76
+ ON screen_time_app_usage(segment_id, total_activity_seconds DESC);
77
+
78
+ CREATE TABLE IF NOT EXISTS screen_time_category_usage (
79
+ id TEXT PRIMARY KEY,
80
+ segment_id TEXT NOT NULL REFERENCES screen_time_hourly_segments(id) ON DELETE CASCADE,
81
+ category_label TEXT NOT NULL,
82
+ total_activity_seconds INTEGER NOT NULL DEFAULT 0,
83
+ created_at TEXT NOT NULL,
84
+ updated_at TEXT NOT NULL,
85
+ UNIQUE (segment_id, category_label)
86
+ );
87
+
88
+ CREATE INDEX IF NOT EXISTS idx_screen_time_category_usage_segment
89
+ ON screen_time_category_usage(segment_id, total_activity_seconds DESC);
@@ -0,0 +1,21 @@
1
+ CREATE TABLE IF NOT EXISTS companion_pairing_source_states (
2
+ id TEXT PRIMARY KEY,
3
+ pairing_session_id TEXT NOT NULL REFERENCES companion_pairing_sessions(id) ON DELETE CASCADE,
4
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
5
+ source_key TEXT NOT NULL,
6
+ desired_enabled INTEGER NOT NULL DEFAULT 1,
7
+ applied_enabled INTEGER NOT NULL DEFAULT 0,
8
+ authorization_status TEXT NOT NULL DEFAULT 'not_determined',
9
+ sync_eligible INTEGER NOT NULL DEFAULT 0,
10
+ last_observed_at TEXT,
11
+ metadata_json TEXT NOT NULL DEFAULT '{}',
12
+ created_at TEXT NOT NULL,
13
+ updated_at TEXT NOT NULL,
14
+ UNIQUE (pairing_session_id, source_key)
15
+ );
16
+
17
+ CREATE INDEX IF NOT EXISTS idx_companion_pairing_source_states_pairing
18
+ ON companion_pairing_source_states(pairing_session_id, source_key);
19
+
20
+ CREATE INDEX IF NOT EXISTS idx_companion_pairing_source_states_user
21
+ ON companion_pairing_source_states(user_id, updated_at DESC);