forge-openclaw-plugin 0.2.27 → 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 (31) hide show
  1. package/README.md +1 -0
  2. package/dist/assets/{board-C6jCchjI.js → board-DPFvZf-D.js} +2 -2
  3. package/dist/assets/{board-C6jCchjI.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/{motion-DFHrH2rd.js → motion-Bvwc85ch.js} +2 -2
  8. package/dist/assets/{motion-DFHrH2rd.js.map → motion-Bvwc85ch.js.map} +1 -1
  9. package/dist/assets/{table-ZL7Di_u3.js → table-FJQTJvUR.js} +2 -2
  10. package/dist/assets/{table-ZL7Di_u3.js.map → table-FJQTJvUR.js.map} +1 -1
  11. package/dist/assets/{ui-CKNPpz7q.js → ui-GXFcgvSw.js} +2 -2
  12. package/dist/assets/{ui-CKNPpz7q.js.map → ui-GXFcgvSw.js.map} +1 -1
  13. package/dist/assets/{vendor-DoNZuFhn.js → vendor-Cwf49UMz.js} +204 -204
  14. package/dist/assets/vendor-Cwf49UMz.js.map +1 -0
  15. package/dist/index.html +7 -7
  16. package/dist/server/server/src/app.js +244 -2
  17. package/dist/server/server/src/openapi.js +799 -2
  18. package/dist/server/server/src/repositories/calendar.js +151 -0
  19. package/dist/server/server/src/services/life-force-model.js +20 -0
  20. package/dist/server/server/src/services/life-force.js +1333 -97
  21. package/dist/server/server/src/types.js +21 -1
  22. package/dist/server/src/lib/snapshot-normalizer.js +2 -0
  23. package/openclaw.plugin.json +1 -1
  24. package/package.json +1 -1
  25. package/skills/forge-openclaw/SKILL.md +17 -0
  26. package/skills/forge-openclaw/entity_conversation_playbooks.md +238 -0
  27. package/skills/forge-openclaw/psyche_entity_playbooks.md +57 -0
  28. package/dist/assets/index-DVvS8iiU.css +0 -1
  29. package/dist/assets/index-zYB-9Dfo.js +0 -85
  30. package/dist/assets/index-zYB-9Dfo.js.map +0 -1
  31. package/dist/assets/vendor-DoNZuFhn.js.map +0 -1
@@ -4,6 +4,7 @@ import { recordActivityEvent } from "./activity-events.js";
4
4
  import { decorateOwnedEntity, filterOwnedEntities, inferFirstOwnedUserId, setEntityOwner } from "./entity-ownership.js";
5
5
  import { getProjectById } from "./projects.js";
6
6
  import { getTaskById } from "./tasks.js";
7
+ import { buildCalendarEventActionProfile, buildTaskTimeboxActionProfile, buildWorkBlockTemplateActionProfile, readEntityActionProfile, upsertEntityActionProfile } from "../services/life-force.js";
7
8
  import { calendarConnectionSchema, calendarContextConflictSchema, calendarEventSchema, calendarEventLinkSchema, calendarEventSourceSchema, calendarOverviewPayloadSchema, calendarSchema, calendarSchedulingRulesSchema, taskTimeboxSchema, workBlockInstanceSchema, workBlockTemplateSchema } from "../types.js";
8
9
  const DEFAULT_SCHEDULING_RULES = {
9
10
  allowWorkBlockKinds: [],
@@ -149,6 +150,11 @@ function mapEvent(row) {
149
150
  categories: JSON.parse(row.categories_json || "[]"),
150
151
  sourceMappings,
151
152
  links: listEventLinksForEvent(row.id),
153
+ actionProfile: readEntityActionProfile("calendar_event", row.id, {
154
+ profileKey: `calendar_event_${row.id}`,
155
+ title: row.title,
156
+ entityType: "calendar_event"
157
+ }),
152
158
  remoteUpdatedAt: primarySource?.lastSyncedAt ?? null,
153
159
  deletedAt: row.deleted_at,
154
160
  createdAt: row.created_at,
@@ -168,11 +174,17 @@ function mapWorkBlockTemplate(row) {
168
174
  startsOn: row.starts_on,
169
175
  endsOn: row.ends_on,
170
176
  blockingState: row.blocking_state,
177
+ actionProfile: readEntityActionProfile("work_block_template", row.id, {
178
+ profileKey: `work_block_template_${row.id}`,
179
+ title: row.title,
180
+ entityType: "work_block_template"
181
+ }),
171
182
  createdAt: row.created_at,
172
183
  updatedAt: row.updated_at
173
184
  });
174
185
  }
175
186
  function mapTimebox(row) {
187
+ const task = getTaskById(row.task_id);
176
188
  return taskTimeboxSchema.parse({
177
189
  id: row.id,
178
190
  taskId: row.task_id,
@@ -187,6 +199,21 @@ function mapTimebox(row) {
187
199
  startsAt: row.starts_at,
188
200
  endsAt: row.ends_at,
189
201
  overrideReason: row.override_reason,
202
+ actionProfile: readEntityActionProfile("task_timebox", row.id, {
203
+ profileKey: `task_timebox_${row.id}`,
204
+ title: row.title,
205
+ entityType: "task_timebox"
206
+ }) ??
207
+ (task
208
+ ? buildTaskTimeboxActionProfile({
209
+ timeboxId: row.id,
210
+ title: row.title,
211
+ taskId: row.task_id,
212
+ taskPlannedDurationSeconds: task.plannedDurationSeconds,
213
+ startsAt: row.starts_at,
214
+ endsAt: row.ends_at
215
+ })
216
+ : null),
190
217
  createdAt: row.created_at,
191
218
  updatedAt: row.updated_at
192
219
  });
@@ -597,6 +624,20 @@ export function createCalendarEvent(input) {
597
624
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
598
625
  .run(id, preferredCalendar?.connectionId ?? null, preferredCalendar?.id ?? null, "forge", "native", "confirmed", input.title, input.description, input.location, place.label || input.location, place.address, place.timezone, place.latitude, place.longitude, place.source, place.externalPlaceId, input.startAt, input.endAt, normalizeTimezone(input.timezone), input.isAllDay ? 1 : 0, input.availability, input.eventType, JSON.stringify(input.categories), now, now);
599
626
  replaceEventLinks(id, input.links);
627
+ upsertEntityActionProfile({
628
+ entityType: "calendar_event",
629
+ entityId: id,
630
+ profile: buildCalendarEventActionProfile({
631
+ eventId: id,
632
+ title: input.title,
633
+ eventType: input.eventType,
634
+ availability: input.availability,
635
+ startAt: input.startAt,
636
+ endAt: input.endAt,
637
+ activityPresetKey: input.activityPresetKey ?? null,
638
+ customSustainRateApPerHour: input.customSustainRateApPerHour ?? null
639
+ })
640
+ });
600
641
  setEntityOwner("calendar_event", id, inferCalendarEventOwnerId(input));
601
642
  return getCalendarEventById(id);
602
643
  }
@@ -652,6 +693,34 @@ export function updateCalendarEvent(eventId, patch) {
652
693
  if (patch.links) {
653
694
  replaceEventLinks(eventId, patch.links);
654
695
  }
696
+ if (patch.title !== undefined ||
697
+ patch.startAt !== undefined ||
698
+ patch.endAt !== undefined ||
699
+ patch.availability !== undefined ||
700
+ patch.eventType !== undefined ||
701
+ patch.activityPresetKey !== undefined ||
702
+ patch.customSustainRateApPerHour !== undefined) {
703
+ upsertEntityActionProfile({
704
+ entityType: "calendar_event",
705
+ entityId: eventId,
706
+ profile: buildCalendarEventActionProfile({
707
+ eventId,
708
+ title: next.title,
709
+ eventType: next.eventType,
710
+ availability: next.availability,
711
+ startAt: next.startAt,
712
+ endAt: next.endAt,
713
+ activityPresetKey: patch.activityPresetKey === undefined
714
+ ? current.actionProfile?.metadata?.activityPresetKey
715
+ : patch.activityPresetKey,
716
+ customSustainRateApPerHour: patch.customSustainRateApPerHour === undefined
717
+ ? (typeof current.actionProfile?.metadata?.customSustainRateApPerHour === "number"
718
+ ? current.actionProfile.metadata.customSustainRateApPerHour
719
+ : null)
720
+ : patch.customSustainRateApPerHour
721
+ })
722
+ });
723
+ }
655
724
  if (patch.userId !== undefined || patch.links !== undefined) {
656
725
  setEntityOwner("calendar_event", eventId, patch.userId === undefined
657
726
  ? inferCalendarEventOwnerId({
@@ -699,6 +768,19 @@ export function createWorkBlockTemplate(input) {
699
768
  )
700
769
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
701
770
  .run(id, input.title, input.kind, input.color, normalizeTimezone(input.timezone), JSON.stringify(input.weekDays), input.startMinute, input.endMinute, input.startsOn ?? null, input.endsOn ?? null, input.blockingState, now, now);
771
+ upsertEntityActionProfile({
772
+ entityType: "work_block_template",
773
+ entityId: id,
774
+ profile: buildWorkBlockTemplateActionProfile({
775
+ templateId: id,
776
+ title: input.title,
777
+ kind: input.kind,
778
+ startMinute: input.startMinute,
779
+ endMinute: input.endMinute,
780
+ activityPresetKey: input.activityPresetKey ?? null,
781
+ customSustainRateApPerHour: input.customSustainRateApPerHour ?? null
782
+ })
783
+ });
702
784
  setEntityOwner("work_block_template", id, input.userId);
703
785
  return getWorkBlockTemplateById(id);
704
786
  });
@@ -744,6 +826,32 @@ export function updateWorkBlockTemplate(templateId, patch) {
744
826
  SET title = ?, kind = ?, color = ?, timezone = ?, weekdays_json = ?, start_minute = ?, end_minute = ?, starts_on = ?, ends_on = ?, blocking_state = ?, updated_at = ?
745
827
  WHERE id = ?`)
746
828
  .run(next.title, next.kind, next.color, next.timezone, JSON.stringify(next.weekDays), next.startMinute, next.endMinute, next.startsOn, next.endsOn, next.blockingState, next.updatedAt, templateId);
829
+ if (patch.title !== undefined ||
830
+ patch.kind !== undefined ||
831
+ patch.startMinute !== undefined ||
832
+ patch.endMinute !== undefined ||
833
+ patch.activityPresetKey !== undefined ||
834
+ patch.customSustainRateApPerHour !== undefined) {
835
+ upsertEntityActionProfile({
836
+ entityType: "work_block_template",
837
+ entityId: templateId,
838
+ profile: buildWorkBlockTemplateActionProfile({
839
+ templateId,
840
+ title: next.title,
841
+ kind: next.kind,
842
+ startMinute: next.startMinute,
843
+ endMinute: next.endMinute,
844
+ activityPresetKey: patch.activityPresetKey === undefined
845
+ ? current.actionProfile?.metadata?.activityPresetKey
846
+ : patch.activityPresetKey,
847
+ customSustainRateApPerHour: patch.customSustainRateApPerHour === undefined
848
+ ? (typeof current.actionProfile?.metadata?.customSustainRateApPerHour === "number"
849
+ ? current.actionProfile.metadata.customSustainRateApPerHour
850
+ : null)
851
+ : patch.customSustainRateApPerHour
852
+ })
853
+ });
854
+ }
747
855
  if (patch.userId !== undefined) {
748
856
  setEntityOwner("work_block_template", templateId, patch.userId);
749
857
  }
@@ -790,6 +898,7 @@ function deriveWorkBlockInstances(template, query) {
790
898
  color: template.color,
791
899
  blockingState: template.blockingState,
792
900
  calendarEventId: null,
901
+ actionProfile: template.actionProfile ?? null,
793
902
  createdAt: template.createdAt,
794
903
  updatedAt: template.updatedAt
795
904
  }));
@@ -836,12 +945,27 @@ export function getTaskTimeboxById(timeboxId) {
836
945
  export function createTaskTimebox(input) {
837
946
  const now = nowIso();
838
947
  const id = `timebox_${randomUUID().replaceAll("-", "").slice(0, 10)}`;
948
+ const task = getTaskById(input.taskId);
839
949
  getDatabase()
840
950
  .prepare(`INSERT INTO task_timeboxes (
841
951
  id, task_id, project_id, connection_id, calendar_id, linked_task_run_id, status, source, title, starts_at, ends_at, override_reason, created_at, updated_at
842
952
  )
843
953
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
844
954
  .run(id, input.taskId, input.projectId ?? null, input.connectionId ?? null, input.calendarId ?? null, input.linkedTaskRunId ?? null, input.status ?? "planned", input.source ?? "manual", input.title, input.startsAt, input.endsAt, input.overrideReason ?? null, now, now);
955
+ upsertEntityActionProfile({
956
+ entityType: "task_timebox",
957
+ entityId: id,
958
+ profile: buildTaskTimeboxActionProfile({
959
+ timeboxId: id,
960
+ title: input.title,
961
+ taskId: input.taskId,
962
+ taskPlannedDurationSeconds: task?.plannedDurationSeconds ?? null,
963
+ startsAt: input.startsAt,
964
+ endsAt: input.endsAt,
965
+ activityPresetKey: input.activityPresetKey ?? null,
966
+ customSustainRateApPerHour: input.customSustainRateApPerHour ?? null
967
+ })
968
+ });
845
969
  setEntityOwner("task_timebox", id, inferTaskTimeboxOwnerId(input));
846
970
  return getTaskTimeboxById(id);
847
971
  }
@@ -869,6 +993,33 @@ export function updateTaskTimebox(timeboxId, patch) {
869
993
  starts_at = ?, ends_at = ?, override_reason = ?, updated_at = ?
870
994
  WHERE id = ?`)
871
995
  .run(next.connectionId, next.calendarId, next.remoteEventId, next.linkedTaskRunId, next.status, next.source, next.title, next.startsAt, next.endsAt, next.overrideReason, next.updatedAt, timeboxId);
996
+ if (patch.title !== undefined ||
997
+ patch.startsAt !== undefined ||
998
+ patch.endsAt !== undefined ||
999
+ patch.activityPresetKey !== undefined ||
1000
+ patch.customSustainRateApPerHour !== undefined) {
1001
+ const task = getTaskById(current.taskId);
1002
+ upsertEntityActionProfile({
1003
+ entityType: "task_timebox",
1004
+ entityId: timeboxId,
1005
+ profile: buildTaskTimeboxActionProfile({
1006
+ timeboxId,
1007
+ title: next.title,
1008
+ taskId: current.taskId,
1009
+ taskPlannedDurationSeconds: task?.plannedDurationSeconds ?? null,
1010
+ startsAt: next.startsAt,
1011
+ endsAt: next.endsAt,
1012
+ activityPresetKey: patch.activityPresetKey === undefined
1013
+ ? current.actionProfile?.metadata?.activityPresetKey
1014
+ : patch.activityPresetKey,
1015
+ customSustainRateApPerHour: patch.customSustainRateApPerHour === undefined
1016
+ ? (typeof current.actionProfile?.metadata?.customSustainRateApPerHour === "number"
1017
+ ? current.actionProfile.metadata.customSustainRateApPerHour
1018
+ : null)
1019
+ : patch.customSustainRateApPerHour
1020
+ })
1021
+ });
1022
+ }
872
1023
  if (patch.userId !== undefined) {
873
1024
  setEntityOwner("task_timebox", timeboxId, patch.userId);
874
1025
  }
@@ -3,6 +3,13 @@ export const DEFAULT_TASK_TOTAL_AP = 100;
3
3
  export const DEFAULT_TASK_EXPECTED_DURATION_SECONDS = 24 * 60 * 60;
4
4
  export const TASK_SPLIT_THRESHOLD_SECONDS = 2 * DEFAULT_TASK_EXPECTED_DURATION_SECONDS;
5
5
  export const MIN_LIFE_FORCE_POINT_GAP_MINUTES = 20;
6
+ const COST_RELEVANT_STAT_KEYS = [
7
+ "activation",
8
+ "focus",
9
+ "vigor",
10
+ "composure",
11
+ "flow"
12
+ ];
6
13
  export function clamp(value, min, max) {
7
14
  return Math.min(max, Math.max(min, value));
8
15
  }
@@ -114,6 +121,19 @@ export function buildTaskSplitSuggestion(input) {
114
121
  thresholdSeconds
115
122
  };
116
123
  }
124
+ export function computeLifeForceLevelMultiplier(level) {
125
+ return 1 + Math.max(0, level - 1) * 0.03;
126
+ }
127
+ export function computeStatCostModifier(level) {
128
+ return clamp(1 - Math.max(0, level - 1) * 0.02, 0.55, 1.25);
129
+ }
130
+ export function computeActionCostModifier(weights, levels) {
131
+ const relief = COST_RELEVANT_STAT_KEYS.reduce((sum, key) => {
132
+ const level = Math.max(1, levels[key] ?? 1);
133
+ return sum + weights[key] * Math.max(0, level - 1) * 0.02;
134
+ }, 0);
135
+ return clamp(Number((1 - relief).toFixed(4)), 0.55, 1.25);
136
+ }
117
137
  export function computeCurveArea(points) {
118
138
  if (points.length < 2) {
119
139
  return 0;