@useorgx/openclaw-plugin 0.4.8 → 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/dashboard/dist/assets/B5NEElEI.css +1 -0
- package/dashboard/dist/assets/BhapSNAs.js +215 -0
- package/dashboard/dist/assets/{BNeJ0kpF.js → iFdvE7lx.js} +1 -1
- package/dashboard/dist/assets/{CUV9IHHi.js → jRJsmpYM.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dist/activity-store.js +4 -18
- 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/auth/flows.d.ts +47 -0
- package/dist/auth/flows.js +169 -0
- package/dist/auth-store.js +6 -26
- 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/shared-types.d.ts +147 -0
- package/dist/contracts/shared-types.js +3 -0
- package/dist/contracts/types.d.ts +1 -134
- 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 -10605
- package/dist/index.js +108 -2243
- package/dist/json-utils.d.ts +1 -0
- package/dist/json-utils.js +8 -0
- package/dist/next-up-queue-store.js +4 -18
- package/dist/runtime-instance-store.js +5 -31
- 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/package.json +1 -1
- package/dashboard/dist/assets/BzkiMPmM.js +0 -215
- package/dashboard/dist/assets/Ie7d9Iq2.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function parseJsonSafe<T>(value: string): T | null;
|
|
@@ -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")
|
|
@@ -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;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, } from "node:fs";
|
|
2
|
+
import { backupCorruptFileSync, writeJsonFileAtomicSync } from "../fs-utils.js";
|
|
3
|
+
import { parseJsonSafe } from "../json-utils.js";
|
|
4
|
+
export function ensureStoreDirSync(dir) {
|
|
5
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
6
|
+
try {
|
|
7
|
+
chmodSync(dir, 0o700);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// best effort
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export { parseJsonSafe };
|
|
14
|
+
export function readJsonFileOrDefault(input) {
|
|
15
|
+
const { file, fallback, isValid, backupOnInvalid = true, } = input;
|
|
16
|
+
if (!existsSync(file))
|
|
17
|
+
return fallback();
|
|
18
|
+
try {
|
|
19
|
+
const raw = readFileSync(file, "utf8");
|
|
20
|
+
const parsed = parseJsonSafe(raw);
|
|
21
|
+
const valid = parsed !== null && (isValid ? isValid(parsed) : true);
|
|
22
|
+
if (valid)
|
|
23
|
+
return parsed;
|
|
24
|
+
if (backupOnInvalid)
|
|
25
|
+
backupCorruptFileSync(file);
|
|
26
|
+
return fallback();
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return fallback();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function writeJsonStoreFileSync(file, data, mode = 0o600) {
|
|
33
|
+
writeJsonFileAtomicSync(file, data, mode);
|
|
34
|
+
}
|
|
35
|
+
export function clearStoreFileSync(file) {
|
|
36
|
+
try {
|
|
37
|
+
rmSync(file, { force: true });
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// best effort
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { OrgXClient } from "../api.js";
|
|
2
|
+
import type { OutboxEvent } from "../outbox.js";
|
|
3
|
+
import type { ReportingPhase, ReportingSourceClient } from "../types.js";
|
|
4
|
+
export type ReplayStatus = "idle" | "running" | "success" | "error";
|
|
5
|
+
export type OutboxReplayState = {
|
|
6
|
+
status: ReplayStatus;
|
|
7
|
+
lastReplayAttemptAt: string | null;
|
|
8
|
+
lastReplaySuccessAt: string | null;
|
|
9
|
+
lastReplayFailureAt: string | null;
|
|
10
|
+
lastReplayError: string | null;
|
|
11
|
+
};
|
|
12
|
+
interface ReportingContextInput {
|
|
13
|
+
initiative_id?: unknown;
|
|
14
|
+
run_id?: unknown;
|
|
15
|
+
correlation_id?: unknown;
|
|
16
|
+
source_client?: unknown;
|
|
17
|
+
initiativeId?: unknown;
|
|
18
|
+
runId?: unknown;
|
|
19
|
+
correlationId?: unknown;
|
|
20
|
+
sourceClient?: unknown;
|
|
21
|
+
}
|
|
22
|
+
type ReplayContext = {
|
|
23
|
+
initiativeId: string;
|
|
24
|
+
runId?: string;
|
|
25
|
+
correlationId?: string;
|
|
26
|
+
sourceClient?: ReportingSourceClient;
|
|
27
|
+
};
|
|
28
|
+
export interface CreateOutboxReplayerDeps {
|
|
29
|
+
client: OrgXClient;
|
|
30
|
+
logger: {
|
|
31
|
+
info?: (msg: string, meta?: Record<string, unknown>) => void;
|
|
32
|
+
warn?: (msg: string, meta?: Record<string, unknown>) => void;
|
|
33
|
+
};
|
|
34
|
+
toErrorMessage: (err: unknown) => string;
|
|
35
|
+
stableHash: (value: string) => string;
|
|
36
|
+
resolveReportingContext: (input: ReportingContextInput) => {
|
|
37
|
+
ok: true;
|
|
38
|
+
value: ReplayContext;
|
|
39
|
+
} | {
|
|
40
|
+
ok: false;
|
|
41
|
+
error: string;
|
|
42
|
+
};
|
|
43
|
+
pickStringField: (input: Record<string, unknown>, ...keys: string[]) => string | null;
|
|
44
|
+
pickStringArrayField: (input: Record<string, unknown>, ...keys: string[]) => string[] | undefined;
|
|
45
|
+
toReportingPhase: (phase: string, progressPct?: number) => ReportingPhase;
|
|
46
|
+
parseRetroEntityType: (value: string | null) => "initiative" | "task" | "milestone" | "workstream" | null | undefined;
|
|
47
|
+
isUuid: (value: string | undefined) => value is string;
|
|
48
|
+
readOutboxReplayState: () => OutboxReplayState;
|
|
49
|
+
writeOutboxReplayState: (next: OutboxReplayState) => void;
|
|
50
|
+
}
|
|
51
|
+
export declare function createOutboxReplayer(deps: CreateOutboxReplayerDeps): {
|
|
52
|
+
replayOutboxEvent: (event: OutboxEvent) => Promise<void>;
|
|
53
|
+
flushOutboxQueues: () => Promise<void>;
|
|
54
|
+
};
|
|
55
|
+
export {};
|