@useorgx/openclaw-plugin 0.4.6 → 0.4.9
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.
- package/README.md +310 -24
- package/dashboard/dist/assets/B5NEElEI.css +1 -0
- package/dashboard/dist/assets/BhapSNAs.js +215 -0
- package/dashboard/dist/assets/iFdvE7lx.js +1 -0
- package/dashboard/dist/assets/jRJsmpYM.js +1 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/activity-actor-fields.d.ts +3 -0
- package/dist/activity-actor-fields.js +128 -0
- package/dist/activity-store.js +12 -19
- package/dist/agent-context-store.js +5 -25
- package/dist/agent-run-store.js +5 -25
- package/dist/agent-suite.js +1 -8
- package/dist/artifacts/register-artifact.d.ts +47 -0
- package/dist/artifacts/register-artifact.js +271 -0
- package/dist/auth/flows.d.ts +47 -0
- package/dist/auth/flows.js +169 -0
- package/dist/auth-store.js +14 -39
- package/dist/byok-store.js +5 -19
- package/dist/cli/orgx.d.ts +66 -0
- package/dist/cli/orgx.js +91 -0
- package/dist/config/refresh.d.ts +32 -0
- package/dist/config/refresh.js +55 -0
- package/dist/config/resolution.d.ts +37 -0
- package/dist/config/resolution.js +178 -0
- package/dist/contracts/client.d.ts +1 -0
- package/dist/contracts/client.js +7 -5
- package/dist/contracts/shared-types.d.ts +147 -0
- package/dist/contracts/shared-types.js +3 -0
- package/dist/contracts/types.d.ts +1 -130
- package/dist/contracts/types.js +5 -0
- package/dist/entities/auto-assignment.d.ts +36 -0
- package/dist/entities/auto-assignment.js +115 -0
- package/dist/entity-comment-store.js +5 -25
- package/dist/hash-utils.d.ts +2 -0
- package/dist/hash-utils.js +12 -0
- package/dist/http/helpers/activity-headline.d.ts +10 -0
- package/dist/http/helpers/activity-headline.js +192 -0
- package/dist/http/helpers/artifact-fallback.d.ts +13 -0
- package/dist/http/helpers/artifact-fallback.js +148 -0
- package/dist/http/helpers/auto-continue-engine.d.ts +298 -0
- package/dist/http/helpers/auto-continue-engine.js +1218 -0
- package/dist/http/helpers/autopilot-operations.d.ts +157 -0
- package/dist/http/helpers/autopilot-operations.js +403 -0
- package/dist/http/helpers/autopilot-runtime.d.ts +42 -0
- package/dist/http/helpers/autopilot-runtime.js +319 -0
- package/dist/http/helpers/autopilot-slice-utils.d.ts +38 -0
- package/dist/http/helpers/autopilot-slice-utils.js +476 -0
- package/dist/http/helpers/decision-mapper.d.ts +12 -0
- package/dist/http/helpers/decision-mapper.js +44 -0
- package/dist/http/helpers/dispatch-lifecycle.d.ts +102 -0
- package/dist/http/helpers/dispatch-lifecycle.js +604 -0
- package/dist/http/helpers/hash-utils.d.ts +1 -0
- package/dist/http/helpers/hash-utils.js +1 -0
- package/dist/http/helpers/kickoff-context.d.ts +12 -0
- package/dist/http/helpers/kickoff-context.js +154 -0
- package/dist/http/helpers/mission-control.d.ts +94 -0
- package/dist/http/helpers/mission-control.js +894 -0
- package/dist/http/helpers/openclaw-cli.d.ts +37 -0
- package/dist/http/helpers/openclaw-cli.js +283 -0
- package/dist/http/helpers/runtime-sse.d.ts +20 -0
- package/dist/http/helpers/runtime-sse.js +110 -0
- package/dist/http/helpers/value-utils.d.ts +6 -0
- package/dist/http/helpers/value-utils.js +67 -0
- package/dist/http/index.d.ts +88 -0
- package/dist/http/index.js +2353 -0
- package/dist/http/router.d.ts +23 -0
- package/dist/http/router.js +23 -0
- package/dist/http/routes/agent-control.d.ts +79 -0
- package/dist/http/routes/agent-control.js +684 -0
- package/dist/http/routes/agent-suite.d.ts +29 -0
- package/dist/http/routes/agent-suite.js +198 -0
- package/dist/http/routes/agents-catalog.d.ts +40 -0
- package/dist/http/routes/agents-catalog.js +83 -0
- package/dist/http/routes/billing.d.ts +23 -0
- package/dist/http/routes/billing.js +55 -0
- package/dist/http/routes/debug.d.ts +14 -0
- package/dist/http/routes/debug.js +21 -0
- package/dist/http/routes/decision-actions.d.ts +13 -0
- package/dist/http/routes/decision-actions.js +66 -0
- package/dist/http/routes/delegation.d.ts +19 -0
- package/dist/http/routes/delegation.js +32 -0
- package/dist/http/routes/entities.d.ts +47 -0
- package/dist/http/routes/entities.js +152 -0
- package/dist/http/routes/entity-dynamic.d.ts +25 -0
- package/dist/http/routes/entity-dynamic.js +191 -0
- package/dist/http/routes/health.d.ts +22 -0
- package/dist/http/routes/health.js +49 -0
- package/dist/http/routes/live-legacy.d.ts +110 -0
- package/dist/http/routes/live-legacy.js +598 -0
- package/dist/http/routes/live-misc.d.ts +69 -0
- package/dist/http/routes/live-misc.js +206 -0
- package/dist/http/routes/live-snapshot.d.ts +90 -0
- package/dist/http/routes/live-snapshot.js +297 -0
- package/dist/http/routes/mission-control-actions.d.ts +83 -0
- package/dist/http/routes/mission-control-actions.js +541 -0
- package/dist/http/routes/mission-control-read.d.ts +28 -0
- package/dist/http/routes/mission-control-read.js +67 -0
- package/dist/http/routes/onboarding.d.ts +34 -0
- package/dist/http/routes/onboarding.js +101 -0
- package/dist/http/routes/run-control.d.ts +24 -0
- package/dist/http/routes/run-control.js +86 -0
- package/dist/http/routes/runtime-hooks.d.ts +69 -0
- package/dist/http/routes/runtime-hooks.js +437 -0
- package/dist/http/routes/settings-byok.d.ts +23 -0
- package/dist/http/routes/settings-byok.js +163 -0
- package/dist/http/routes/summary.d.ts +18 -0
- package/dist/http/routes/summary.js +42 -0
- package/dist/http/routes/work-artifacts.d.ts +9 -0
- package/dist/http/routes/work-artifacts.js +36 -0
- package/dist/http/shared-state.d.ts +16 -0
- package/dist/http/shared-state.js +1 -0
- package/dist/http-handler.d.ts +1 -88
- package/dist/http-handler.js +1 -9664
- package/dist/index.js +122 -2121
- package/dist/json-utils.d.ts +1 -0
- package/dist/json-utils.js +8 -0
- package/dist/local-openclaw.js +8 -0
- package/dist/mcp-client-setup.js +75 -90
- package/dist/next-up-queue-store.js +4 -18
- package/dist/runtime-instance-store.js +8 -34
- package/dist/services/background.d.ts +23 -0
- package/dist/services/background.js +23 -0
- package/dist/services/instrumentation.d.ts +29 -0
- package/dist/services/instrumentation.js +136 -0
- package/dist/snapshot-store.js +5 -25
- package/dist/stores/json-store.d.ts +11 -0
- package/dist/stores/json-store.js +42 -0
- package/dist/sync/outbox-replay.d.ts +55 -0
- package/dist/sync/outbox-replay.js +514 -0
- package/dist/tools/core-tools.d.ts +76 -0
- package/dist/tools/core-tools.js +1005 -0
- package/dist/worker-supervisor.js +15 -0
- package/package.json +6 -1
- package/dashboard/dist/assets/0tOC3wSN.js +0 -214
- package/dashboard/dist/assets/Bm8QnMJ_.js +0 -1
- package/dashboard/dist/assets/CyxZio4Y.js +0 -1
- package/dashboard/dist/assets/DaAIOik3.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function parseJsonSafe<T>(value: string): T | null;
|
package/dist/local-openclaw.js
CHANGED
|
@@ -580,6 +580,10 @@ function turnToActivity(turn, session, cachedSummary, index) {
|
|
|
580
580
|
description: modelAlias,
|
|
581
581
|
agentId: session.agentId,
|
|
582
582
|
agentName: session.agentName,
|
|
583
|
+
requesterAgentId: session.agentId ?? null,
|
|
584
|
+
requesterAgentName: session.agentName ?? null,
|
|
585
|
+
executorAgentId: session.agentId ?? null,
|
|
586
|
+
executorAgentName: session.agentName ?? null,
|
|
583
587
|
runId: session.sessionId ?? session.key,
|
|
584
588
|
initiativeId: session.agentId ? `agent:${session.agentId}` : null,
|
|
585
589
|
timestamp: turn.timestamp,
|
|
@@ -747,6 +751,10 @@ function makeSessionSummaryItem(session) {
|
|
|
747
751
|
description: modelAlias ? `Local session (${modelAlias})` : "Local session",
|
|
748
752
|
agentId: session.agentId,
|
|
749
753
|
agentName: session.agentName,
|
|
754
|
+
requesterAgentId: session.agentId ?? null,
|
|
755
|
+
requesterAgentName: session.agentName ?? null,
|
|
756
|
+
executorAgentId: session.agentId ?? null,
|
|
757
|
+
executorAgentName: session.agentName ?? null,
|
|
750
758
|
runId: session.sessionId ?? session.key,
|
|
751
759
|
initiativeId: session.agentId ? `agent:${session.agentId}` : null,
|
|
752
760
|
timestamp: session.updatedAt ?? new Date().toISOString(),
|
package/dist/mcp-client-setup.js
CHANGED
|
@@ -5,22 +5,6 @@ import { randomUUID } from "node:crypto";
|
|
|
5
5
|
import { writeFileAtomicSync, writeJsonFileAtomicSync } from "./fs-utils.js";
|
|
6
6
|
const ORGX_LOCAL_MCP_KEY = "orgx-openclaw";
|
|
7
7
|
const ORGX_HOSTED_MCP_URL = "https://mcp.useorgx.com/mcp";
|
|
8
|
-
const ORGX_LOCAL_MCP_SCOPES = [
|
|
9
|
-
"engineering",
|
|
10
|
-
"product",
|
|
11
|
-
"design",
|
|
12
|
-
"marketing",
|
|
13
|
-
"sales",
|
|
14
|
-
"operations",
|
|
15
|
-
"orchestration",
|
|
16
|
-
];
|
|
17
|
-
function scopedMcpServerKey(scope) {
|
|
18
|
-
return `${ORGX_LOCAL_MCP_KEY}-${scope}`;
|
|
19
|
-
}
|
|
20
|
-
function scopedMcpUrl(localMcpUrl, scope) {
|
|
21
|
-
const base = localMcpUrl.replace(/\/+$/, "");
|
|
22
|
-
return `${base}/${scope}`;
|
|
23
|
-
}
|
|
24
8
|
function escapeRegExp(value) {
|
|
25
9
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26
10
|
}
|
|
@@ -59,6 +43,20 @@ function backupFileSync(path, mode) {
|
|
|
59
43
|
return null;
|
|
60
44
|
}
|
|
61
45
|
}
|
|
46
|
+
function removeLegacyScopedMcpServers(servers) {
|
|
47
|
+
const next = { ...servers };
|
|
48
|
+
let updated = false;
|
|
49
|
+
const scopedPrefix = `${ORGX_LOCAL_MCP_KEY}-`;
|
|
50
|
+
for (const key of Object.keys(next)) {
|
|
51
|
+
if (key === ORGX_LOCAL_MCP_KEY)
|
|
52
|
+
continue;
|
|
53
|
+
if (!key.startsWith(scopedPrefix))
|
|
54
|
+
continue;
|
|
55
|
+
delete next[key];
|
|
56
|
+
updated = true;
|
|
57
|
+
}
|
|
58
|
+
return { updated, next };
|
|
59
|
+
}
|
|
62
60
|
export function patchClaudeMcpConfig(input) {
|
|
63
61
|
const currentServers = isRecord(input.current.mcpServers) ? input.current.mcpServers : {};
|
|
64
62
|
const existingOrgx = isRecord(currentServers.orgx) ? currentServers.orgx : {};
|
|
@@ -88,41 +86,20 @@ export function patchClaudeMcpConfig(input) {
|
|
|
88
86
|
? existing.description
|
|
89
87
|
: "OrgX platform via local OpenClaw plugin (no OAuth)",
|
|
90
88
|
};
|
|
91
|
-
const
|
|
92
|
-
const scopedEntries = {};
|
|
93
|
-
for (const scope of ORGX_LOCAL_MCP_SCOPES) {
|
|
94
|
-
const key = scopedMcpServerKey(scope);
|
|
95
|
-
const expectedUrl = scopedMcpUrl(input.localMcpUrl, scope);
|
|
96
|
-
const existingScoped = isRecord(currentServers[key]) ? currentServers[key] : {};
|
|
97
|
-
const priorUrl = typeof existingScoped.url === "string" ? existingScoped.url : "";
|
|
98
|
-
const priorType = typeof existingScoped.type === "string" ? existingScoped.type : "";
|
|
99
|
-
const nextScoped = {
|
|
100
|
-
...existingScoped,
|
|
101
|
-
type: "http",
|
|
102
|
-
url: expectedUrl,
|
|
103
|
-
description: typeof existingScoped.description === "string" && existingScoped.description.trim().length > 0
|
|
104
|
-
? existingScoped.description
|
|
105
|
-
: `OrgX platform via local OpenClaw plugin (${scope} scope)`,
|
|
106
|
-
};
|
|
107
|
-
scopedEntries[key] = nextScoped;
|
|
108
|
-
if (priorUrl !== expectedUrl || priorType !== "http") {
|
|
109
|
-
updatedScopes.push(scope);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
const nextServers = {
|
|
89
|
+
const mergedServers = {
|
|
113
90
|
...currentServers,
|
|
114
91
|
...(shouldSetHostedOrgx ? { orgx: nextOrgxEntry } : {}),
|
|
115
92
|
[ORGX_LOCAL_MCP_KEY]: nextEntry,
|
|
116
|
-
...scopedEntries,
|
|
117
93
|
};
|
|
94
|
+
const scopedCleanup = removeLegacyScopedMcpServers(mergedServers);
|
|
118
95
|
const next = {
|
|
119
96
|
...input.current,
|
|
120
|
-
mcpServers:
|
|
97
|
+
mcpServers: scopedCleanup.next,
|
|
121
98
|
};
|
|
122
99
|
const updatedLocal = priorUrl !== input.localMcpUrl || priorType !== "http";
|
|
123
100
|
const updatedHosted = shouldSetHostedOrgx &&
|
|
124
101
|
(existingOrgxUrl !== ORGX_HOSTED_MCP_URL || existingOrgxType !== "http");
|
|
125
|
-
const updated = updatedLocal || updatedHosted ||
|
|
102
|
+
const updated = updatedLocal || updatedHosted || scopedCleanup.updated;
|
|
126
103
|
return { updated, next };
|
|
127
104
|
}
|
|
128
105
|
export function patchCursorMcpConfig(input) {
|
|
@@ -133,30 +110,16 @@ export function patchCursorMcpConfig(input) {
|
|
|
133
110
|
...existing,
|
|
134
111
|
url: input.localMcpUrl,
|
|
135
112
|
};
|
|
136
|
-
const
|
|
137
|
-
let updatedScopes = false;
|
|
138
|
-
for (const scope of ORGX_LOCAL_MCP_SCOPES) {
|
|
139
|
-
const key = scopedMcpServerKey(scope);
|
|
140
|
-
const expectedUrl = scopedMcpUrl(input.localMcpUrl, scope);
|
|
141
|
-
const existingScoped = isRecord(currentServers[key]) ? currentServers[key] : {};
|
|
142
|
-
const priorScopedUrl = typeof existingScoped.url === "string" ? existingScoped.url : "";
|
|
143
|
-
scopedEntries[key] = {
|
|
144
|
-
...existingScoped,
|
|
145
|
-
url: expectedUrl,
|
|
146
|
-
};
|
|
147
|
-
if (priorScopedUrl !== expectedUrl)
|
|
148
|
-
updatedScopes = true;
|
|
149
|
-
}
|
|
150
|
-
const nextServers = {
|
|
113
|
+
const mergedServers = {
|
|
151
114
|
...currentServers,
|
|
152
115
|
[ORGX_LOCAL_MCP_KEY]: nextEntry,
|
|
153
|
-
...scopedEntries,
|
|
154
116
|
};
|
|
117
|
+
const scopedCleanup = removeLegacyScopedMcpServers(mergedServers);
|
|
155
118
|
const next = {
|
|
156
119
|
...input.current,
|
|
157
|
-
mcpServers:
|
|
120
|
+
mcpServers: scopedCleanup.next,
|
|
158
121
|
};
|
|
159
|
-
const updated = priorUrl !== input.localMcpUrl ||
|
|
122
|
+
const updated = priorUrl !== input.localMcpUrl || scopedCleanup.updated;
|
|
160
123
|
return { updated, next };
|
|
161
124
|
}
|
|
162
125
|
function upsertCodexMcpServerSection(input) {
|
|
@@ -173,7 +136,9 @@ function upsertCodexMcpServerSection(input) {
|
|
|
173
136
|
}
|
|
174
137
|
const urlLine = `url = "${input.url}"`;
|
|
175
138
|
if (headerIndex === -1) {
|
|
176
|
-
const
|
|
139
|
+
const needsQuote = /[^A-Za-z0-9_]/.test(input.key);
|
|
140
|
+
const keyLiteral = needsQuote ? `"${input.key}"` : input.key;
|
|
141
|
+
const suffix = ["", `[mcp_servers.${keyLiteral}]`, urlLine, ""].join("\n");
|
|
177
142
|
const normalized = currentText.endsWith("\n") ? currentText : `${currentText}\n`;
|
|
178
143
|
return { updated: true, next: `${normalized}${suffix}` };
|
|
179
144
|
}
|
|
@@ -221,29 +186,52 @@ function upsertCodexMcpServerSection(input) {
|
|
|
221
186
|
}
|
|
222
187
|
return { updated, next: `${lines.join("\n")}\n` };
|
|
223
188
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
current = `${normalized}${suffix}`;
|
|
243
|
-
updatedHosted = true;
|
|
189
|
+
function removeCodexLegacyScopedMcpSections(input) {
|
|
190
|
+
const lines = input.current.split(/\r?\n/);
|
|
191
|
+
const scopedPrefix = `${input.baseKey}-`;
|
|
192
|
+
let updated = false;
|
|
193
|
+
let index = 0;
|
|
194
|
+
while (index < lines.length) {
|
|
195
|
+
const trimmed = lines[index].trim();
|
|
196
|
+
const headerMatch = trimmed.match(/^\[mcp_servers\.(?:"([^"]+)"|([A-Za-z0-9_]+))\]\s*$/);
|
|
197
|
+
if (!headerMatch) {
|
|
198
|
+
index += 1;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const key = (headerMatch[1] ?? headerMatch[2] ?? "").trim();
|
|
202
|
+
const isLegacyScoped = key !== input.baseKey &&
|
|
203
|
+
key.startsWith(scopedPrefix);
|
|
204
|
+
if (!isLegacyScoped) {
|
|
205
|
+
index += 1;
|
|
206
|
+
continue;
|
|
244
207
|
}
|
|
208
|
+
let sectionEnd = lines.length;
|
|
209
|
+
for (let i = index + 1; i < lines.length; i += 1) {
|
|
210
|
+
if (lines[i].trim().startsWith("[")) {
|
|
211
|
+
sectionEnd = i;
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const start = index > 0 && lines[index - 1].trim() === "" ? index - 1 : index;
|
|
216
|
+
lines.splice(start, sectionEnd - start);
|
|
217
|
+
updated = true;
|
|
218
|
+
index = Math.max(0, start);
|
|
245
219
|
}
|
|
220
|
+
return { updated, next: `${lines.join("\n")}\n` };
|
|
221
|
+
}
|
|
222
|
+
export function patchCodexConfigToml(input) {
|
|
223
|
+
let current = input.current;
|
|
246
224
|
let updated = false;
|
|
225
|
+
// Ensure the hosted OrgX entry uses a direct `url` (streamable HTTP) so that
|
|
226
|
+
// `codex mcp login orgx` can perform OAuth. Route through upsertCodexMcpServerSection
|
|
227
|
+
// so stale stdio-transport fields (command/args) are stripped automatically.
|
|
228
|
+
const hosted = upsertCodexMcpServerSection({
|
|
229
|
+
current,
|
|
230
|
+
key: "orgx",
|
|
231
|
+
url: ORGX_HOSTED_MCP_URL,
|
|
232
|
+
});
|
|
233
|
+
updated = updated || hosted.updated;
|
|
234
|
+
current = hosted.next;
|
|
247
235
|
const base = upsertCodexMcpServerSection({
|
|
248
236
|
current,
|
|
249
237
|
key: ORGX_LOCAL_MCP_KEY,
|
|
@@ -251,16 +239,13 @@ export function patchCodexConfigToml(input) {
|
|
|
251
239
|
});
|
|
252
240
|
updated = updated || base.updated;
|
|
253
241
|
current = base.next;
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
current = next.next;
|
|
262
|
-
}
|
|
263
|
-
return { updated: updatedHosted || updated, next: current };
|
|
242
|
+
const removedScoped = removeCodexLegacyScopedMcpSections({
|
|
243
|
+
current,
|
|
244
|
+
baseKey: ORGX_LOCAL_MCP_KEY,
|
|
245
|
+
});
|
|
246
|
+
updated = updated || removedScoped.updated;
|
|
247
|
+
current = removedScoped.next;
|
|
248
|
+
return { updated, next: current };
|
|
264
249
|
}
|
|
265
250
|
export async function autoConfigureDetectedMcpClients(input) {
|
|
266
251
|
const logger = input.logger ?? {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync, } from "node:fs";
|
|
2
2
|
import { getOrgxPluginConfigDir, getOrgxPluginConfigPath } from "./paths.js";
|
|
3
3
|
import { backupCorruptFileSync, writeJsonFileAtomicSync } from "./fs-utils.js";
|
|
4
|
+
import { ensureStoreDirSync, parseJsonSafe, } from "./stores/json-store.js";
|
|
4
5
|
const MAX_PINS = 240;
|
|
5
6
|
function storeDir() {
|
|
6
7
|
return getOrgxPluginConfigDir();
|
|
@@ -9,22 +10,7 @@ function storeFile() {
|
|
|
9
10
|
return getOrgxPluginConfigPath("next-up-queue.json");
|
|
10
11
|
}
|
|
11
12
|
function ensureStoreDir() {
|
|
12
|
-
|
|
13
|
-
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
14
|
-
try {
|
|
15
|
-
chmodSync(dir, 0o700);
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
// best effort
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
function parseJson(value) {
|
|
22
|
-
try {
|
|
23
|
-
return JSON.parse(value);
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
13
|
+
ensureStoreDirSync(storeDir());
|
|
28
14
|
}
|
|
29
15
|
function normalizeNullableString(value) {
|
|
30
16
|
if (typeof value !== "string")
|
|
@@ -49,7 +35,7 @@ export function readNextUpQueuePins() {
|
|
|
49
35
|
return { version: 1, updatedAt: new Date().toISOString(), pins: [] };
|
|
50
36
|
}
|
|
51
37
|
const raw = readFileSync(file, "utf8");
|
|
52
|
-
const parsed =
|
|
38
|
+
const parsed = parseJsonSafe(raw);
|
|
53
39
|
if (!parsed || typeof parsed !== "object") {
|
|
54
40
|
backupCorruptFileSync(file);
|
|
55
41
|
return { version: 1, updatedAt: new Date().toISOString(), pins: [] };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, } from "node:fs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { getOrgxPluginConfigDir, getOrgxPluginConfigPath } from "./paths.js";
|
|
4
4
|
import { backupCorruptFileSync, writeJsonFileAtomicSync } from "./fs-utils.js";
|
|
5
|
+
import { clearStoreFileSync, ensureStoreDirSync, parseJsonSafe, } from "./stores/json-store.js";
|
|
5
6
|
const MAX_INSTANCES = 600;
|
|
6
7
|
export const DEFAULT_RUNTIME_HEARTBEAT_TIMEOUT_MS = 90_000;
|
|
7
8
|
function runtimeDir() {
|
|
@@ -14,33 +15,12 @@ function hookTokenFile() {
|
|
|
14
15
|
return getOrgxPluginConfigPath("runtime-hook-token.txt");
|
|
15
16
|
}
|
|
16
17
|
function ensureRuntimeDir() {
|
|
17
|
-
|
|
18
|
-
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
19
|
-
try {
|
|
20
|
-
chmodSync(dir, 0o700);
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
// best effort
|
|
24
|
-
}
|
|
18
|
+
ensureStoreDirSync(runtimeDir());
|
|
25
19
|
}
|
|
26
20
|
function writeHookTokenFile(token) {
|
|
27
21
|
ensureRuntimeDir();
|
|
28
22
|
const file = hookTokenFile();
|
|
29
23
|
writeFileSync(file, `${token}\n`, { encoding: "utf8", mode: 0o600 });
|
|
30
|
-
try {
|
|
31
|
-
chmodSync(file, 0o600);
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
// best effort
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
function parseJson(value) {
|
|
38
|
-
try {
|
|
39
|
-
return JSON.parse(value);
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
24
|
}
|
|
45
25
|
function normalizeNullableString(value) {
|
|
46
26
|
if (typeof value !== "string")
|
|
@@ -85,7 +65,7 @@ function normalizeHookEvent(value) {
|
|
|
85
65
|
}
|
|
86
66
|
function toProviderLogo(sourceClient) {
|
|
87
67
|
if (sourceClient === "codex")
|
|
88
|
-
return "
|
|
68
|
+
return "openai";
|
|
89
69
|
if (sourceClient === "claude-code")
|
|
90
70
|
return "anthropic";
|
|
91
71
|
if (sourceClient === "openclaw")
|
|
@@ -97,9 +77,9 @@ function toProviderLogo(sourceClient) {
|
|
|
97
77
|
function normalizeProviderLogo(value, sourceClient) {
|
|
98
78
|
const normalized = normalizeNullableString(value)?.toLowerCase();
|
|
99
79
|
if (normalized === "codex")
|
|
100
|
-
return "codex";
|
|
80
|
+
return sourceClient === "codex" ? "openai" : "codex";
|
|
101
81
|
if (normalized === "openai")
|
|
102
|
-
return
|
|
82
|
+
return "openai";
|
|
103
83
|
if (normalized === "anthropic")
|
|
104
84
|
return "anthropic";
|
|
105
85
|
if (normalized === "openclaw")
|
|
@@ -201,7 +181,7 @@ export function readRuntimeInstances() {
|
|
|
201
181
|
return { updatedAt: new Date().toISOString(), instances: {} };
|
|
202
182
|
}
|
|
203
183
|
const raw = readFileSync(file, "utf8");
|
|
204
|
-
const parsed =
|
|
184
|
+
const parsed = parseJsonSafe(raw);
|
|
205
185
|
if (!parsed || typeof parsed !== "object") {
|
|
206
186
|
backupCorruptFileSync(file);
|
|
207
187
|
return { updatedAt: new Date().toISOString(), instances: {} };
|
|
@@ -349,13 +329,7 @@ export function listRuntimeInstances(options) {
|
|
|
349
329
|
.slice(0, limit);
|
|
350
330
|
}
|
|
351
331
|
export function clearRuntimeInstances() {
|
|
352
|
-
|
|
353
|
-
try {
|
|
354
|
-
rmSync(file, { force: true });
|
|
355
|
-
}
|
|
356
|
-
catch {
|
|
357
|
-
// best effort
|
|
358
|
-
}
|
|
332
|
+
clearStoreFileSync(runtimeFile());
|
|
359
333
|
}
|
|
360
334
|
export function resolveRuntimeHookToken() {
|
|
361
335
|
const envToken = normalizeNullableString(process.env.ORGX_HOOK_TOKEN);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface RegisterServiceApi {
|
|
2
|
+
registerService: (service: {
|
|
3
|
+
id: string;
|
|
4
|
+
start: () => Promise<void>;
|
|
5
|
+
stop: () => Promise<void>;
|
|
6
|
+
}) => void;
|
|
7
|
+
log?: {
|
|
8
|
+
info?: (msg: string, meta?: Record<string, unknown>) => void;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface RegisterSyncServiceDeps {
|
|
12
|
+
api: RegisterServiceApi;
|
|
13
|
+
syncIntervalMs: number;
|
|
14
|
+
ensureGatewayWatchdog: (logger: Record<string, unknown>) => {
|
|
15
|
+
started: boolean;
|
|
16
|
+
pid?: number | null;
|
|
17
|
+
};
|
|
18
|
+
doSync: () => Promise<void>;
|
|
19
|
+
scheduleNextSync: () => void;
|
|
20
|
+
setSyncServiceRunning: (running: boolean) => void;
|
|
21
|
+
clearSyncTimer: () => void;
|
|
22
|
+
}
|
|
23
|
+
export declare function registerSyncService(deps: RegisterSyncServiceDeps): void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function registerSyncService(deps) {
|
|
2
|
+
deps.api.registerService({
|
|
3
|
+
id: "orgx-sync",
|
|
4
|
+
start: async () => {
|
|
5
|
+
deps.setSyncServiceRunning(true);
|
|
6
|
+
const watchdog = deps.ensureGatewayWatchdog((deps.api.log ?? {}));
|
|
7
|
+
if (watchdog.started) {
|
|
8
|
+
deps.api.log?.info?.("[orgx] Gateway watchdog started", {
|
|
9
|
+
pid: watchdog.pid,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
deps.api.log?.info?.("[orgx] Starting sync service", {
|
|
13
|
+
interval: deps.syncIntervalMs,
|
|
14
|
+
});
|
|
15
|
+
await deps.doSync();
|
|
16
|
+
deps.scheduleNextSync();
|
|
17
|
+
},
|
|
18
|
+
stop: async () => {
|
|
19
|
+
deps.setSyncServiceRunning(false);
|
|
20
|
+
deps.clearSyncTimer();
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
type ToolLike = {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
parameters: Record<string, unknown>;
|
|
5
|
+
execute: (callId: string, params?: unknown) => Promise<{
|
|
6
|
+
content: Array<{
|
|
7
|
+
type: "text";
|
|
8
|
+
text: string;
|
|
9
|
+
}>;
|
|
10
|
+
}>;
|
|
11
|
+
};
|
|
12
|
+
type ServiceLike = {
|
|
13
|
+
id: string;
|
|
14
|
+
start: () => Promise<void>;
|
|
15
|
+
stop: () => Promise<void>;
|
|
16
|
+
};
|
|
17
|
+
type ApiLike = {
|
|
18
|
+
registerTool: (tool: ToolLike, options?: {
|
|
19
|
+
optional?: boolean;
|
|
20
|
+
}) => void;
|
|
21
|
+
registerService: (service: ServiceLike) => void;
|
|
22
|
+
};
|
|
23
|
+
export declare function instrumentPluginApi(input: {
|
|
24
|
+
api: ApiLike;
|
|
25
|
+
installationId: string;
|
|
26
|
+
pluginVersion: string;
|
|
27
|
+
toErrorMessage: (err: unknown) => string;
|
|
28
|
+
}): void;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { posthogCapture } from "../telemetry/posthog.js";
|
|
2
|
+
export function instrumentPluginApi(input) {
|
|
3
|
+
const registerTool = input.api.registerTool.bind(input.api);
|
|
4
|
+
input.api.registerTool = (tool, options) => {
|
|
5
|
+
const toolName = tool.name;
|
|
6
|
+
const optional = Boolean(options?.optional);
|
|
7
|
+
registerTool({
|
|
8
|
+
...tool,
|
|
9
|
+
execute: async (callId, params) => {
|
|
10
|
+
const startedAt = Date.now();
|
|
11
|
+
void posthogCapture({
|
|
12
|
+
event: "openclaw_tool_called",
|
|
13
|
+
distinctId: input.installationId,
|
|
14
|
+
properties: {
|
|
15
|
+
tool_name: toolName,
|
|
16
|
+
tool_optional: optional,
|
|
17
|
+
call_id: callId,
|
|
18
|
+
plugin_version: input.pluginVersion,
|
|
19
|
+
},
|
|
20
|
+
}).catch(() => {
|
|
21
|
+
// best effort
|
|
22
|
+
});
|
|
23
|
+
try {
|
|
24
|
+
const result = await tool.execute(callId, params);
|
|
25
|
+
const durationMs = Date.now() - startedAt;
|
|
26
|
+
void posthogCapture({
|
|
27
|
+
event: "openclaw_tool_succeeded",
|
|
28
|
+
distinctId: input.installationId,
|
|
29
|
+
properties: {
|
|
30
|
+
tool_name: toolName,
|
|
31
|
+
tool_optional: optional,
|
|
32
|
+
call_id: callId,
|
|
33
|
+
duration_ms: durationMs,
|
|
34
|
+
plugin_version: input.pluginVersion,
|
|
35
|
+
},
|
|
36
|
+
}).catch(() => {
|
|
37
|
+
// best effort
|
|
38
|
+
});
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
const durationMs = Date.now() - startedAt;
|
|
43
|
+
void posthogCapture({
|
|
44
|
+
event: "openclaw_tool_failed",
|
|
45
|
+
distinctId: input.installationId,
|
|
46
|
+
properties: {
|
|
47
|
+
tool_name: toolName,
|
|
48
|
+
tool_optional: optional,
|
|
49
|
+
call_id: callId,
|
|
50
|
+
duration_ms: durationMs,
|
|
51
|
+
plugin_version: input.pluginVersion,
|
|
52
|
+
error: input.toErrorMessage(err),
|
|
53
|
+
},
|
|
54
|
+
}).catch(() => {
|
|
55
|
+
// best effort
|
|
56
|
+
});
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
}, options);
|
|
61
|
+
};
|
|
62
|
+
const registerService = input.api.registerService.bind(input.api);
|
|
63
|
+
input.api.registerService = (service) => {
|
|
64
|
+
registerService({
|
|
65
|
+
...service,
|
|
66
|
+
start: async () => {
|
|
67
|
+
const startedAt = Date.now();
|
|
68
|
+
try {
|
|
69
|
+
await service.start();
|
|
70
|
+
const durationMs = Date.now() - startedAt;
|
|
71
|
+
void posthogCapture({
|
|
72
|
+
event: "openclaw_service_started",
|
|
73
|
+
distinctId: input.installationId,
|
|
74
|
+
properties: {
|
|
75
|
+
service_id: service.id,
|
|
76
|
+
duration_ms: durationMs,
|
|
77
|
+
plugin_version: input.pluginVersion,
|
|
78
|
+
},
|
|
79
|
+
}).catch(() => {
|
|
80
|
+
// best effort
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
const durationMs = Date.now() - startedAt;
|
|
85
|
+
void posthogCapture({
|
|
86
|
+
event: "openclaw_service_start_failed",
|
|
87
|
+
distinctId: input.installationId,
|
|
88
|
+
properties: {
|
|
89
|
+
service_id: service.id,
|
|
90
|
+
duration_ms: durationMs,
|
|
91
|
+
plugin_version: input.pluginVersion,
|
|
92
|
+
error: input.toErrorMessage(err),
|
|
93
|
+
},
|
|
94
|
+
}).catch(() => {
|
|
95
|
+
// best effort
|
|
96
|
+
});
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
stop: async () => {
|
|
101
|
+
const startedAt = Date.now();
|
|
102
|
+
try {
|
|
103
|
+
await service.stop();
|
|
104
|
+
const durationMs = Date.now() - startedAt;
|
|
105
|
+
void posthogCapture({
|
|
106
|
+
event: "openclaw_service_stopped",
|
|
107
|
+
distinctId: input.installationId,
|
|
108
|
+
properties: {
|
|
109
|
+
service_id: service.id,
|
|
110
|
+
duration_ms: durationMs,
|
|
111
|
+
plugin_version: input.pluginVersion,
|
|
112
|
+
},
|
|
113
|
+
}).catch(() => {
|
|
114
|
+
// best effort
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
const durationMs = Date.now() - startedAt;
|
|
119
|
+
void posthogCapture({
|
|
120
|
+
event: "openclaw_service_stop_failed",
|
|
121
|
+
distinctId: input.installationId,
|
|
122
|
+
properties: {
|
|
123
|
+
service_id: service.id,
|
|
124
|
+
duration_ms: durationMs,
|
|
125
|
+
plugin_version: input.pluginVersion,
|
|
126
|
+
error: input.toErrorMessage(err),
|
|
127
|
+
},
|
|
128
|
+
}).catch(() => {
|
|
129
|
+
// best effort
|
|
130
|
+
});
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
}
|
package/dist/snapshot-store.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { getOrgxPluginConfigDir, getOrgxPluginConfigPath } from './paths.js';
|
|
3
3
|
import { backupCorruptFileSync, writeJsonFileAtomicSync } from './fs-utils.js';
|
|
4
|
+
import { clearStoreFileSync, ensureStoreDirSync, parseJsonSafe, } from "./stores/json-store.js";
|
|
4
5
|
function snapshotDir() {
|
|
5
6
|
return getOrgxPluginConfigDir();
|
|
6
7
|
}
|
|
@@ -8,22 +9,7 @@ function snapshotFile() {
|
|
|
8
9
|
return getOrgxPluginConfigPath('snapshot.json');
|
|
9
10
|
}
|
|
10
11
|
function ensureSnapshotDir() {
|
|
11
|
-
|
|
12
|
-
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
13
|
-
try {
|
|
14
|
-
chmodSync(dir, 0o700);
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
// best effort
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function parseJson(value) {
|
|
21
|
-
try {
|
|
22
|
-
return JSON.parse(value);
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
12
|
+
ensureStoreDirSync(snapshotDir());
|
|
27
13
|
}
|
|
28
14
|
export function readPersistedSnapshot() {
|
|
29
15
|
const file = snapshotFile();
|
|
@@ -31,7 +17,7 @@ export function readPersistedSnapshot() {
|
|
|
31
17
|
if (!existsSync(file))
|
|
32
18
|
return null;
|
|
33
19
|
const raw = readFileSync(file, 'utf8');
|
|
34
|
-
const parsed =
|
|
20
|
+
const parsed = parseJsonSafe(raw);
|
|
35
21
|
if (!parsed) {
|
|
36
22
|
backupCorruptFileSync(file);
|
|
37
23
|
return null;
|
|
@@ -57,11 +43,5 @@ export function writePersistedSnapshot(snapshot) {
|
|
|
57
43
|
return record;
|
|
58
44
|
}
|
|
59
45
|
export function clearPersistedSnapshot() {
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
rmSync(file, { force: true });
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
// best effort
|
|
66
|
-
}
|
|
46
|
+
clearStoreFileSync(snapshotFile());
|
|
67
47
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { parseJsonSafe } from "../json-utils.js";
|
|
2
|
+
export declare function ensureStoreDirSync(dir: string): void;
|
|
3
|
+
export { parseJsonSafe };
|
|
4
|
+
export declare function readJsonFileOrDefault<T>(input: {
|
|
5
|
+
file: string;
|
|
6
|
+
fallback: () => T;
|
|
7
|
+
isValid?: (value: unknown) => value is T;
|
|
8
|
+
backupOnInvalid?: boolean;
|
|
9
|
+
}): T;
|
|
10
|
+
export declare function writeJsonStoreFileSync(file: string, data: unknown, mode?: number): void;
|
|
11
|
+
export declare function clearStoreFileSync(file: string): void;
|