forge-openclaw-plugin 0.2.19 → 0.2.21

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 (82) hide show
  1. package/README.md +133 -2
  2. package/dist/assets/board-_C6oMy5w.js +6 -0
  3. package/dist/assets/{board-8L3uX7_O.js.map → board-_C6oMy5w.js.map} +1 -1
  4. package/dist/assets/index-B4A6TooJ.js +63 -0
  5. package/dist/assets/index-B4A6TooJ.js.map +1 -0
  6. package/dist/assets/index-D6Xs_2mo.css +1 -0
  7. package/dist/assets/{motion-1GAqqi8M.js → motion-D4sZgCHd.js} +2 -2
  8. package/dist/assets/{motion-1GAqqi8M.js.map → motion-D4sZgCHd.js.map} +1 -1
  9. package/dist/assets/{table-DBGlgRjk.js → table-BWzTaky1.js} +2 -2
  10. package/dist/assets/{table-DBGlgRjk.js.map → table-BWzTaky1.js.map} +1 -1
  11. package/dist/assets/{ui-iTluWjC4.js → ui-BzK4azQb.js} +7 -7
  12. package/dist/assets/{ui-iTluWjC4.js.map → ui-BzK4azQb.js.map} +1 -1
  13. package/dist/assets/vendor-DT3pnAKJ.css +1 -0
  14. package/dist/assets/vendor-De38P6YR.js +729 -0
  15. package/dist/assets/vendor-De38P6YR.js.map +1 -0
  16. package/dist/assets/viz-C6hfyqzu.js +34 -0
  17. package/dist/assets/viz-C6hfyqzu.js.map +1 -0
  18. package/dist/index.html +9 -9
  19. package/dist/openclaw/parity.d.ts +1 -1
  20. package/dist/openclaw/parity.js +29 -2
  21. package/dist/openclaw/routes.js +207 -24
  22. package/dist/openclaw/tools.js +324 -35
  23. package/dist/server/app.js +2080 -92
  24. package/dist/server/db.js +3 -0
  25. package/dist/server/health.js +1284 -0
  26. package/dist/server/managers/platform/background-job-manager.js +138 -2
  27. package/dist/server/managers/platform/llm-manager.js +126 -0
  28. package/dist/server/managers/platform/openai-responses-provider.js +773 -0
  29. package/dist/server/managers/runtime.js +6 -1
  30. package/dist/server/openapi.js +718 -0
  31. package/dist/server/preferences-seeds.js +409 -0
  32. package/dist/server/preferences-types.js +368 -0
  33. package/dist/server/psyche-types.js +42 -18
  34. package/dist/server/repositories/activity-events.js +53 -4
  35. package/dist/server/repositories/calendar.js +89 -15
  36. package/dist/server/repositories/collaboration.js +8 -3
  37. package/dist/server/repositories/diagnostic-logs.js +243 -0
  38. package/dist/server/repositories/entity-ownership.js +92 -0
  39. package/dist/server/repositories/goals.js +7 -2
  40. package/dist/server/repositories/habits.js +122 -16
  41. package/dist/server/repositories/notes.js +119 -41
  42. package/dist/server/repositories/preferences.js +1765 -0
  43. package/dist/server/repositories/projects.js +18 -7
  44. package/dist/server/repositories/psyche.js +84 -27
  45. package/dist/server/repositories/rewards.js +112 -4
  46. package/dist/server/repositories/strategies.js +450 -0
  47. package/dist/server/repositories/tags.js +11 -6
  48. package/dist/server/repositories/task-runs.js +10 -2
  49. package/dist/server/repositories/tasks.js +99 -17
  50. package/dist/server/repositories/users.js +417 -0
  51. package/dist/server/repositories/wiki-memory.js +3366 -0
  52. package/dist/server/services/context.js +20 -18
  53. package/dist/server/services/dashboard.js +29 -6
  54. package/dist/server/services/entity-crud.js +21 -3
  55. package/dist/server/services/insights.js +9 -7
  56. package/dist/server/services/projects.js +2 -1
  57. package/dist/server/services/psyche.js +10 -9
  58. package/dist/server/types.js +594 -30
  59. package/openclaw.plugin.json +1 -1
  60. package/package.json +1 -1
  61. package/server/migrations/015_multi_user_and_strategies.sql +244 -0
  62. package/server/migrations/016_health_companion.sql +158 -0
  63. package/server/migrations/016_strategy_contracts_and_user_graph.sql +22 -0
  64. package/server/migrations/017_preferences.sql +131 -0
  65. package/server/migrations/018_preference_catalogs.sql +31 -0
  66. package/server/migrations/019_wiki_memory.sql +255 -0
  67. package/server/migrations/020_wiki_page_hierarchy.sql +11 -0
  68. package/server/migrations/021_hide_evidence_from_wiki_index.sql +3 -0
  69. package/server/migrations/022_wiki_ingest_background.sql +85 -0
  70. package/server/migrations/023_diagnostic_logs.sql +28 -0
  71. package/skills/forge-openclaw/SKILL.md +126 -34
  72. package/skills/forge-openclaw/entity_conversation_playbooks.md +337 -0
  73. package/skills/forge-openclaw/psyche_entity_playbooks.md +404 -0
  74. package/dist/assets/board-8L3uX7_O.js +0 -6
  75. package/dist/assets/index-Cj1IBH_w.js +0 -36
  76. package/dist/assets/index-Cj1IBH_w.js.map +0 -1
  77. package/dist/assets/index-DQT6EbuS.css +0 -1
  78. package/dist/assets/vendor-BvM2F9Dp.js +0 -503
  79. package/dist/assets/vendor-BvM2F9Dp.js.map +0 -1
  80. package/dist/assets/vendor-CRS-psbw.css +0 -1
  81. package/dist/assets/viz-CNeunkfu.js +0 -34
  82. package/dist/assets/viz-CNeunkfu.js.map +0 -1
@@ -1,10 +1,146 @@
1
1
  import { AbstractManager } from "../base.js";
2
+ import { recordDiagnosticLog } from "../../repositories/diagnostic-logs.js";
2
3
  export class BackgroundJobManager extends AbstractManager {
4
+ maxConcurrentJobs;
3
5
  name = "BackgroundJobManager";
6
+ queue = [];
7
+ active = new Set();
8
+ draining = false;
9
+ constructor(maxConcurrentJobs = 3) {
10
+ super();
11
+ this.maxConcurrentJobs = maxConcurrentJobs;
12
+ }
4
13
  start() {
5
14
  return;
6
15
  }
7
- stop() {
8
- return;
16
+ enqueue(input) {
17
+ if (this.has(input.id)) {
18
+ this.recordLifecycleLog("info", "background_job_enqueue_skipped", {
19
+ task: input,
20
+ message: `Skipped duplicate background job ${input.label}.`,
21
+ details: {
22
+ queueDepth: this.queue.length,
23
+ activeCount: this.active.size
24
+ },
25
+ functionName: "enqueue"
26
+ });
27
+ return;
28
+ }
29
+ this.queue.push(input);
30
+ this.recordLifecycleLog("info", "background_job_enqueued", {
31
+ task: input,
32
+ message: `Enqueued background job ${input.label}.`,
33
+ details: {
34
+ queueDepth: this.queue.length,
35
+ activeCount: this.active.size
36
+ },
37
+ functionName: "enqueue"
38
+ });
39
+ this.scheduleDrain();
40
+ }
41
+ isActive(jobId) {
42
+ return this.active.has(jobId);
43
+ }
44
+ has(jobId) {
45
+ return (this.active.has(jobId) || this.queue.some((task) => task.id === jobId));
46
+ }
47
+ async stop() {
48
+ this.draining = true;
49
+ while (this.active.size > 0) {
50
+ await new Promise((resolve) => setTimeout(resolve, 25));
51
+ }
52
+ }
53
+ scheduleDrain() {
54
+ if (this.draining ||
55
+ this.queue.length === 0 ||
56
+ this.active.size >= this.maxConcurrentJobs) {
57
+ return;
58
+ }
59
+ queueMicrotask(() => {
60
+ void this.drainAvailable();
61
+ });
62
+ }
63
+ async drainAvailable() {
64
+ if (this.draining) {
65
+ return;
66
+ }
67
+ while (!this.draining &&
68
+ this.queue.length > 0 &&
69
+ this.active.size < this.maxConcurrentJobs) {
70
+ const next = this.queue.shift();
71
+ if (!next) {
72
+ return;
73
+ }
74
+ this.active.add(next.id);
75
+ void this.runTask(next);
76
+ }
77
+ }
78
+ async runTask(next) {
79
+ const startedAt = Date.now();
80
+ this.recordLifecycleLog("info", "background_job_started", {
81
+ task: next,
82
+ message: `Started background job ${next.label}.`,
83
+ details: {
84
+ queueDepth: this.queue.length,
85
+ activeCount: this.active.size,
86
+ maxConcurrentJobs: this.maxConcurrentJobs
87
+ },
88
+ functionName: "runTask"
89
+ });
90
+ try {
91
+ await next.handler();
92
+ this.recordLifecycleLog("info", "background_job_completed", {
93
+ task: next,
94
+ message: `Completed background job ${next.label}.`,
95
+ details: {
96
+ durationMs: Date.now() - startedAt,
97
+ queueDepth: this.queue.length,
98
+ activeCount: this.active.size,
99
+ maxConcurrentJobs: this.maxConcurrentJobs
100
+ },
101
+ functionName: "runTask"
102
+ });
103
+ }
104
+ catch (error) {
105
+ this.recordLifecycleLog("error", "background_job_failed", {
106
+ task: next,
107
+ message: `Background job failed for ${next.label}.`,
108
+ details: {
109
+ durationMs: Date.now() - startedAt,
110
+ queueDepth: this.queue.length,
111
+ activeCount: this.active.size,
112
+ maxConcurrentJobs: this.maxConcurrentJobs,
113
+ error
114
+ },
115
+ functionName: "runTask"
116
+ });
117
+ console.error(`[${this.name}] background job failed for ${next.label}:`, error);
118
+ }
119
+ finally {
120
+ this.active.delete(next.id);
121
+ this.scheduleDrain();
122
+ }
123
+ }
124
+ recordLifecycleLog(level, eventKey, input) {
125
+ try {
126
+ recordDiagnosticLog({
127
+ level,
128
+ source: "system",
129
+ scope: "background_job",
130
+ eventKey,
131
+ message: input.message,
132
+ functionName: input.functionName,
133
+ entityType: "background_job",
134
+ entityId: input.task.id,
135
+ jobId: input.task.id,
136
+ details: {
137
+ label: input.task.label,
138
+ ...(input.details ?? {})
139
+ }
140
+ });
141
+ }
142
+ catch {
143
+ // Diagnostics should never block job execution.
144
+ }
9
145
  }
10
146
  }
@@ -0,0 +1,126 @@
1
+ import { AbstractManager } from "../base.js";
2
+ import { readEncryptedSecret } from "../../repositories/calendar.js";
3
+ function emitDiagnostic(logger, input) {
4
+ logger?.(input);
5
+ }
6
+ export class LlmManager extends AbstractManager {
7
+ secretsManager;
8
+ name = "LlmManager";
9
+ providers = new Map();
10
+ constructor(secretsManager) {
11
+ super();
12
+ this.secretsManager = secretsManager;
13
+ }
14
+ register(provider) {
15
+ for (const alias of provider.providerNames) {
16
+ this.providers.set(alias, provider);
17
+ }
18
+ }
19
+ async compileWikiIngest(profile, input, options = {}, logger) {
20
+ const provider = this.resolveProvider(profile.provider);
21
+ if (!provider) {
22
+ emitDiagnostic(logger, {
23
+ level: "error",
24
+ message: "Wiki ingest LLM provider is not supported.",
25
+ details: {
26
+ scope: "wiki_llm",
27
+ eventKey: "llm_provider_missing",
28
+ provider: profile.provider,
29
+ baseUrl: profile.baseUrl,
30
+ model: profile.model
31
+ }
32
+ });
33
+ return null;
34
+ }
35
+ const apiKey = this.readApiKey(profile.secretId);
36
+ if (!apiKey) {
37
+ emitDiagnostic(logger, {
38
+ level: "error",
39
+ message: "Wiki ingest LLM profile is missing an API key.",
40
+ details: {
41
+ scope: "wiki_llm",
42
+ eventKey: "llm_api_key_missing",
43
+ provider: profile.provider,
44
+ baseUrl: profile.baseUrl,
45
+ model: profile.model,
46
+ secretId: profile.secretId ?? null
47
+ }
48
+ });
49
+ return null;
50
+ }
51
+ return provider.compile({
52
+ apiKey,
53
+ profile,
54
+ input,
55
+ resumeResponseId: options.resumeResponseId ?? null,
56
+ logger
57
+ });
58
+ }
59
+ async testWikiConnection(profile, explicitApiKey, logger) {
60
+ const provider = this.resolveProvider(profile.provider);
61
+ if (!provider) {
62
+ emitDiagnostic(logger, {
63
+ level: "error",
64
+ message: "Wiki LLM connection test requested an unsupported provider.",
65
+ details: {
66
+ scope: "wiki_llm",
67
+ eventKey: "llm_provider_missing",
68
+ provider: profile.provider,
69
+ baseUrl: profile.baseUrl,
70
+ model: profile.model
71
+ }
72
+ });
73
+ throw new Error("Unsupported LLM provider.");
74
+ }
75
+ const apiKey = explicitApiKey?.trim() || this.readApiKey(profile.secretId);
76
+ if (!apiKey) {
77
+ emitDiagnostic(logger, {
78
+ level: "error",
79
+ message: "Wiki LLM connection test is missing an API key.",
80
+ details: {
81
+ scope: "wiki_llm",
82
+ eventKey: "llm_api_key_missing",
83
+ provider: profile.provider,
84
+ baseUrl: profile.baseUrl,
85
+ model: profile.model,
86
+ secretId: profile.secretId ?? null
87
+ }
88
+ });
89
+ throw new Error("Save an OpenAI API key first.");
90
+ }
91
+ const result = await provider.testConnection({
92
+ apiKey,
93
+ profile,
94
+ logger
95
+ });
96
+ return {
97
+ provider: profile.provider,
98
+ model: profile.model,
99
+ baseUrl: profile.baseUrl,
100
+ reasoningEffort: typeof profile.metadata.reasoningEffort === "string"
101
+ ? profile.metadata.reasoningEffort
102
+ : null,
103
+ verbosity: typeof profile.metadata.verbosity === "string"
104
+ ? profile.metadata.verbosity
105
+ : null,
106
+ usingStoredKey: !explicitApiKey?.trim(),
107
+ outputPreview: result.outputPreview
108
+ };
109
+ }
110
+ resolveProvider(providerName) {
111
+ return (this.providers.get(providerName) ??
112
+ this.providers.get("openai-responses") ??
113
+ null);
114
+ }
115
+ readApiKey(secretId) {
116
+ if (!secretId) {
117
+ return null;
118
+ }
119
+ const cipherText = readEncryptedSecret(secretId);
120
+ if (!cipherText) {
121
+ return null;
122
+ }
123
+ const payload = this.secretsManager.openJson(cipherText);
124
+ return payload.apiKey?.trim() || null;
125
+ }
126
+ }