forge-openclaw-plugin 0.2.3 → 0.2.7

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 (117) hide show
  1. package/README.md +114 -6
  2. package/dist/assets/board-CzgvdLO8.js +6 -0
  3. package/dist/assets/board-CzgvdLO8.js.map +1 -0
  4. package/dist/assets/favicon-BCHm9dUV.ico +0 -0
  5. package/dist/assets/index-8d_oM8fL.js +27 -0
  6. package/dist/assets/index-8d_oM8fL.js.map +1 -0
  7. package/dist/assets/index-D4A_bq8m.css +1 -0
  8. package/dist/assets/motion-STUd1O46.js +10 -0
  9. package/dist/assets/motion-STUd1O46.js.map +1 -0
  10. package/dist/assets/plus-jakarta-sans-latin-ext-wght-normal-DmpS2jIq.woff2 +0 -0
  11. package/dist/assets/plus-jakarta-sans-latin-wght-normal-eXO_dkmS.woff2 +0 -0
  12. package/dist/assets/plus-jakarta-sans-vietnamese-wght-normal-qRpaaN48.woff2 +0 -0
  13. package/dist/assets/sora-latin-ext-wght-normal-CawQDOvP.woff2 +0 -0
  14. package/dist/assets/sora-latin-wght-normal-DdqRvwsR.woff2 +0 -0
  15. package/dist/assets/space-grotesk-latin-500-normal-CNSSEhBt.woff +0 -0
  16. package/dist/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
  17. package/dist/assets/space-grotesk-latin-700-normal-CwsQ-cCU.woff +0 -0
  18. package/dist/assets/space-grotesk-latin-700-normal-RjhwGPKo.woff2 +0 -0
  19. package/dist/assets/space-grotesk-latin-ext-500-normal-3dgZTiw9.woff +0 -0
  20. package/dist/assets/space-grotesk-latin-ext-500-normal-DUe3BAxM.woff2 +0 -0
  21. package/dist/assets/space-grotesk-latin-ext-700-normal-BQnZhY3m.woff2 +0 -0
  22. package/dist/assets/space-grotesk-latin-ext-700-normal-HVCqSBdx.woff +0 -0
  23. package/dist/assets/space-grotesk-vietnamese-500-normal-BTqKIpxg.woff +0 -0
  24. package/dist/assets/space-grotesk-vietnamese-500-normal-BmEvtly_.woff2 +0 -0
  25. package/dist/assets/space-grotesk-vietnamese-700-normal-DMty7AZE.woff2 +0 -0
  26. package/dist/assets/space-grotesk-vietnamese-700-normal-Duxec5Rn.woff +0 -0
  27. package/dist/assets/table-CtNlETLc.js +23 -0
  28. package/dist/assets/table-CtNlETLc.js.map +1 -0
  29. package/dist/assets/ui-ThzkR_oW.js +46 -0
  30. package/dist/assets/ui-ThzkR_oW.js.map +1 -0
  31. package/dist/assets/vendor-CRS-psbw.css +1 -0
  32. package/dist/assets/vendor-DyHAI6nk.js +423 -0
  33. package/dist/assets/vendor-DyHAI6nk.js.map +1 -0
  34. package/dist/assets/viz-BJuBCz_G.js +34 -0
  35. package/dist/assets/viz-BJuBCz_G.js.map +1 -0
  36. package/dist/favicon.ico +0 -0
  37. package/dist/favicon.png +0 -0
  38. package/dist/index.html +29 -0
  39. package/dist/openclaw/api-client.d.ts +8 -0
  40. package/dist/openclaw/api-client.js +31 -4
  41. package/dist/openclaw/local-runtime.d.ts +3 -0
  42. package/dist/openclaw/local-runtime.js +135 -0
  43. package/dist/openclaw/parity.d.ts +4 -4
  44. package/dist/openclaw/parity.js +23 -33
  45. package/dist/openclaw/plugin-entry-shared.d.ts +5 -3
  46. package/dist/openclaw/plugin-entry-shared.js +52 -10
  47. package/dist/openclaw/routes.d.ts +12 -3
  48. package/dist/openclaw/routes.js +156 -924
  49. package/dist/openclaw/tools.js +242 -1100
  50. package/dist/server/app.js +2450 -0
  51. package/dist/server/db.js +313 -0
  52. package/dist/server/e2e-server.js +20 -0
  53. package/dist/server/errors.js +15 -0
  54. package/dist/server/index.js +16 -0
  55. package/dist/server/managers/base.js +17 -0
  56. package/dist/server/managers/contracts.js +47 -0
  57. package/dist/server/managers/platform/api-gateway-manager.js +11 -0
  58. package/dist/server/managers/platform/audit-manager.js +15 -0
  59. package/dist/server/managers/platform/authentication-manager.js +56 -0
  60. package/dist/server/managers/platform/authorization-manager.js +56 -0
  61. package/dist/server/managers/platform/background-job-manager.js +10 -0
  62. package/dist/server/managers/platform/configuration-manager.js +33 -0
  63. package/dist/server/managers/platform/database-manager.js +14 -0
  64. package/dist/server/managers/platform/event-bus-manager.js +7 -0
  65. package/dist/server/managers/platform/external-service-manager.js +11 -0
  66. package/dist/server/managers/platform/health-manager.js +7 -0
  67. package/dist/server/managers/platform/migration-manager.js +8 -0
  68. package/dist/server/managers/platform/search-index-manager.js +4 -0
  69. package/dist/server/managers/platform/secrets-manager.js +19 -0
  70. package/dist/server/managers/platform/session-manager.js +121 -0
  71. package/dist/server/managers/platform/storage-manager.js +16 -0
  72. package/dist/server/managers/platform/token-manager.js +37 -0
  73. package/dist/server/managers/platform/transaction-manager.js +8 -0
  74. package/dist/server/managers/platform/trusted-network.js +39 -0
  75. package/dist/server/managers/runtime.js +56 -0
  76. package/dist/server/managers/type-guards.js +4 -0
  77. package/dist/server/openapi.js +3512 -0
  78. package/dist/server/psyche-types.js +395 -0
  79. package/dist/server/repositories/activity-events.js +157 -0
  80. package/dist/server/repositories/collaboration.js +497 -0
  81. package/dist/server/repositories/comments.js +176 -0
  82. package/dist/server/repositories/deleted-entities.js +192 -0
  83. package/dist/server/repositories/domains.js +30 -0
  84. package/dist/server/repositories/event-log.js +64 -0
  85. package/dist/server/repositories/goals.js +159 -0
  86. package/dist/server/repositories/projects.js +214 -0
  87. package/dist/server/repositories/psyche.js +1356 -0
  88. package/dist/server/repositories/rewards.js +675 -0
  89. package/dist/server/repositories/settings.js +399 -0
  90. package/dist/server/repositories/tags.js +160 -0
  91. package/dist/server/repositories/task-runs.js +488 -0
  92. package/dist/server/repositories/tasks.js +413 -0
  93. package/dist/server/services/context.js +214 -0
  94. package/dist/server/services/dashboard.js +170 -0
  95. package/dist/server/services/entity-crud.js +576 -0
  96. package/dist/server/services/gamification.js +215 -0
  97. package/dist/server/services/insights.js +91 -0
  98. package/dist/server/services/projects.js +75 -0
  99. package/dist/server/services/psyche.js +63 -0
  100. package/dist/server/services/relations.js +28 -0
  101. package/dist/server/services/reviews.js +88 -0
  102. package/dist/server/services/run-recovery.js +13 -0
  103. package/dist/server/services/tagging.js +49 -0
  104. package/dist/server/services/task-run-watchdog.js +92 -0
  105. package/dist/server/services/work-time.js +176 -0
  106. package/dist/server/types.js +999 -0
  107. package/dist/server/web.js +91 -0
  108. package/openclaw.plugin.json +22 -10
  109. package/package.json +17 -4
  110. package/server/migrations/001_core.sql +333 -0
  111. package/server/migrations/002_psyche.sql +241 -0
  112. package/server/migrations/003_timer_execution.sql +18 -0
  113. package/server/migrations/004_psyche_linked_entities.sql +5 -0
  114. package/server/migrations/005_adaptive_schemas.sql +157 -0
  115. package/server/migrations/006_psyche_auth_setting.sql +4 -0
  116. package/server/migrations/007_deleted_entities.sql +16 -0
  117. package/skills/forge-openclaw/SKILL.md +189 -275
@@ -0,0 +1,92 @@
1
+ import { reconcileExpiredTaskRuns } from "./run-recovery.js";
2
+ const DEFAULT_INTERVAL_MS = 15_000;
3
+ function createInitialStatus(intervalMs, limit) {
4
+ return {
5
+ intervalMs,
6
+ limit: limit ?? null,
7
+ running: false,
8
+ lastStartedAt: null,
9
+ lastCompletedAt: null,
10
+ lastSuccessfulAt: null,
11
+ lastErrorAt: null,
12
+ lastError: null,
13
+ lastRecovery: null,
14
+ totalRecoveredCount: 0,
15
+ consecutiveFailures: 0
16
+ };
17
+ }
18
+ export function createTaskRunWatchdog(options = {}) {
19
+ const intervalMs = Math.max(1_000, options.intervalMs ?? DEFAULT_INTERVAL_MS);
20
+ const now = options.now ?? (() => new Date());
21
+ const reconcile = options.reconcile ??
22
+ ((input) => reconcileExpiredTaskRuns({
23
+ now: input.now,
24
+ limit: input.limit
25
+ }));
26
+ const status = createInitialStatus(intervalMs, options.limit);
27
+ let timer = null;
28
+ let inFlight = null;
29
+ const reconcileNow = async () => {
30
+ if (inFlight) {
31
+ return inFlight;
32
+ }
33
+ status.lastStartedAt = now().toISOString();
34
+ inFlight = Promise.resolve().then(() => reconcile({
35
+ now: now(),
36
+ limit: options.limit
37
+ }));
38
+ try {
39
+ const summary = await inFlight;
40
+ status.lastCompletedAt = summary.recoveredAt;
41
+ status.lastSuccessfulAt = summary.recoveredAt;
42
+ status.lastRecovery = summary;
43
+ status.totalRecoveredCount += summary.recoveredCount;
44
+ status.consecutiveFailures = 0;
45
+ status.lastError = null;
46
+ status.lastErrorAt = null;
47
+ return summary;
48
+ }
49
+ catch (error) {
50
+ const errorAt = now().toISOString();
51
+ status.lastCompletedAt = errorAt;
52
+ status.lastErrorAt = errorAt;
53
+ status.lastError = error instanceof Error ? error.message : String(error);
54
+ status.consecutiveFailures += 1;
55
+ throw error;
56
+ }
57
+ finally {
58
+ inFlight = null;
59
+ }
60
+ };
61
+ const start = async () => {
62
+ if (timer) {
63
+ return status.lastRecovery ?? reconcileNow();
64
+ }
65
+ status.running = true;
66
+ const summary = await reconcileNow();
67
+ timer = setInterval(() => {
68
+ void reconcileNow().catch(() => {
69
+ // Preserve error details in watchdog status without crashing the server loop.
70
+ });
71
+ }, intervalMs);
72
+ timer.unref?.();
73
+ return summary;
74
+ };
75
+ const stop = () => {
76
+ if (timer) {
77
+ clearInterval(timer);
78
+ timer = null;
79
+ }
80
+ status.running = false;
81
+ };
82
+ const getStatus = () => ({
83
+ ...status,
84
+ running: timer !== null
85
+ });
86
+ return {
87
+ start,
88
+ stop,
89
+ reconcileNow,
90
+ getStatus
91
+ };
92
+ }
@@ -0,0 +1,176 @@
1
+ import { getDatabase } from "../db.js";
2
+ function readTimeAccountingMode() {
3
+ try {
4
+ const row = getDatabase()
5
+ .prepare(`SELECT time_accounting_mode
6
+ FROM app_settings
7
+ WHERE id = 1`)
8
+ .get();
9
+ if (row?.time_accounting_mode === "split" ||
10
+ row?.time_accounting_mode === "parallel" ||
11
+ row?.time_accounting_mode === "primary_only") {
12
+ return row.time_accounting_mode;
13
+ }
14
+ }
15
+ catch {
16
+ return "split";
17
+ }
18
+ return "split";
19
+ }
20
+ function readTaskRunTimingRows() {
21
+ return getDatabase()
22
+ .prepare(`SELECT
23
+ id,
24
+ task_id,
25
+ actor,
26
+ status,
27
+ timer_mode,
28
+ planned_duration_seconds,
29
+ is_current,
30
+ claimed_at,
31
+ heartbeat_at,
32
+ lease_expires_at,
33
+ completed_at,
34
+ released_at,
35
+ timed_out_at,
36
+ updated_at
37
+ FROM task_runs
38
+ ORDER BY claimed_at ASC, id ASC`)
39
+ .all();
40
+ }
41
+ function roundCreditedSeconds(value) {
42
+ return Math.round(value * 100) / 100;
43
+ }
44
+ function getRunEndMs(row, nowMs) {
45
+ if (row.status === "active") {
46
+ return Math.max(Date.parse(row.claimed_at), Math.min(nowMs, Date.parse(row.lease_expires_at)));
47
+ }
48
+ const terminal = row.completed_at ??
49
+ row.released_at ??
50
+ row.timed_out_at ??
51
+ row.updated_at ??
52
+ row.lease_expires_at ??
53
+ row.heartbeat_at;
54
+ return Math.max(Date.parse(row.claimed_at), Date.parse(terminal));
55
+ }
56
+ function buildRunTimings(rows, now) {
57
+ const nowMs = now.getTime();
58
+ return rows
59
+ .map((row) => ({
60
+ row,
61
+ startMs: Date.parse(row.claimed_at),
62
+ endMs: getRunEndMs(row, nowMs)
63
+ }))
64
+ .filter((timing) => Number.isFinite(timing.startMs) && Number.isFinite(timing.endMs) && timing.endMs >= timing.startMs);
65
+ }
66
+ function computeCreditedSecondsByActor(timings, mode) {
67
+ const creditedMs = new Map();
68
+ const timingsByActor = new Map();
69
+ for (const timing of timings) {
70
+ const list = timingsByActor.get(timing.row.actor) ?? [];
71
+ list.push(timing);
72
+ timingsByActor.set(timing.row.actor, list);
73
+ creditedMs.set(timing.row.id, 0);
74
+ }
75
+ for (const actorTimings of timingsByActor.values()) {
76
+ const boundaries = [...new Set(actorTimings.flatMap((timing) => [timing.startMs, timing.endMs]))].sort((a, b) => a - b);
77
+ for (let index = 0; index < boundaries.length - 1; index += 1) {
78
+ const startMs = boundaries[index];
79
+ const endMs = boundaries[index + 1];
80
+ const sliceMs = endMs - startMs;
81
+ if (sliceMs <= 0) {
82
+ continue;
83
+ }
84
+ const active = actorTimings.filter((timing) => timing.startMs < endMs && timing.endMs > startMs);
85
+ if (active.length === 0) {
86
+ continue;
87
+ }
88
+ if (mode === "parallel") {
89
+ for (const timing of active) {
90
+ creditedMs.set(timing.row.id, (creditedMs.get(timing.row.id) ?? 0) + sliceMs);
91
+ }
92
+ continue;
93
+ }
94
+ if (mode === "primary_only") {
95
+ const current = active.find((timing) => timing.row.is_current === 1);
96
+ if (current) {
97
+ creditedMs.set(current.row.id, (creditedMs.get(current.row.id) ?? 0) + sliceMs);
98
+ }
99
+ continue;
100
+ }
101
+ const shareMs = sliceMs / active.length;
102
+ for (const timing of active) {
103
+ creditedMs.set(timing.row.id, (creditedMs.get(timing.row.id) ?? 0) + shareMs);
104
+ }
105
+ }
106
+ }
107
+ return new Map([...creditedMs.entries()].map(([runId, value]) => [runId, roundCreditedSeconds(value / 1000)]));
108
+ }
109
+ export function computeWorkTime(now = new Date()) {
110
+ const mode = readTimeAccountingMode();
111
+ const timings = buildRunTimings(readTaskRunTimingRows(), now);
112
+ const creditedByRunId = computeCreditedSecondsByActor(timings, mode);
113
+ const runMetrics = new Map();
114
+ const taskSummaries = new Map();
115
+ for (const timing of timings) {
116
+ const elapsedWallSeconds = Math.max(0, Math.floor((timing.endMs - timing.startMs) / 1000));
117
+ const creditedSeconds = creditedByRunId.get(timing.row.id) ?? 0;
118
+ const remainingSeconds = timing.row.timer_mode === "planned" && timing.row.planned_duration_seconds !== null
119
+ ? Math.max(0, timing.row.planned_duration_seconds - elapsedWallSeconds)
120
+ : null;
121
+ const overtimeSeconds = timing.row.timer_mode === "planned" && timing.row.planned_duration_seconds !== null
122
+ ? Math.max(0, elapsedWallSeconds - timing.row.planned_duration_seconds)
123
+ : 0;
124
+ const isCurrent = timing.row.is_current === 1 && timing.row.status === "active";
125
+ runMetrics.set(timing.row.id, {
126
+ elapsedWallSeconds,
127
+ creditedSeconds,
128
+ remainingSeconds,
129
+ overtimeSeconds,
130
+ isCurrent
131
+ });
132
+ const existing = taskSummaries.get(timing.row.task_id) ?? {
133
+ totalTrackedSeconds: 0,
134
+ totalCreditedSeconds: 0,
135
+ activeRunCount: 0,
136
+ hasCurrentRun: false,
137
+ currentRunId: null
138
+ };
139
+ taskSummaries.set(timing.row.task_id, {
140
+ totalTrackedSeconds: existing.totalTrackedSeconds + elapsedWallSeconds,
141
+ totalCreditedSeconds: roundCreditedSeconds(existing.totalCreditedSeconds + creditedSeconds),
142
+ activeRunCount: existing.activeRunCount + (timing.row.status === "active" ? 1 : 0),
143
+ hasCurrentRun: existing.hasCurrentRun || isCurrent,
144
+ currentRunId: isCurrent ? timing.row.id : existing.currentRunId
145
+ });
146
+ }
147
+ return {
148
+ mode,
149
+ runMetrics,
150
+ taskSummaries
151
+ };
152
+ }
153
+ export function emptyTaskTimeSummary() {
154
+ return {
155
+ totalTrackedSeconds: 0,
156
+ totalCreditedSeconds: 0,
157
+ activeRunCount: 0,
158
+ hasCurrentRun: false,
159
+ currentRunId: null
160
+ };
161
+ }
162
+ export function sumTaskTimeSummaries(taskIds, summaries) {
163
+ return taskIds.reduce((accumulator, taskId) => {
164
+ const summary = summaries.get(taskId);
165
+ if (!summary) {
166
+ return accumulator;
167
+ }
168
+ return {
169
+ totalTrackedSeconds: accumulator.totalTrackedSeconds + summary.totalTrackedSeconds,
170
+ totalCreditedSeconds: roundCreditedSeconds(accumulator.totalCreditedSeconds + summary.totalCreditedSeconds),
171
+ activeRunCount: accumulator.activeRunCount + summary.activeRunCount,
172
+ hasCurrentRun: accumulator.hasCurrentRun || summary.hasCurrentRun,
173
+ currentRunId: accumulator.currentRunId ?? summary.currentRunId
174
+ };
175
+ }, emptyTaskTimeSummary());
176
+ }