refactor: package-own watchdog orchestrator entrypoint

This commit is contained in:
Eve
2026-05-08 16:11:49 +08:00
parent c3b9e12474
commit e99423da97
11 changed files with 175 additions and 67 deletions

View File

@@ -15,13 +15,13 @@
}, },
"bindings": { "bindings": {
"runtime": "openclaw", "runtime": "openclaw",
"entrypoint": "scripts/watchdog_auto_notify_orchestrator.mjs", "entrypoint": "plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs",
"scripts": { "scripts": {
"watchdog": "scripts/long_task_watchdog.mjs", "watchdog": "plugins/reporting-governance/scripts/long_task_watchdog.mjs",
"dispatcher": "scripts/operator_notify_dispatcher.mjs", "dispatcher": "plugins/reporting-governance/scripts/operator_notify_dispatcher.mjs",
"bridgeSupervisor": "scripts/operator_notify_bridge_supervisor.mjs", "bridgeSupervisor": "plugins/reporting-governance/scripts/operator_notify_bridge_supervisor.mjs",
"senderBinding": "scripts/operator_notify_sender_binding.mjs", "senderBinding": "plugins/reporting-governance/scripts/operator_notify_sender_binding.mjs",
"orchestrator": "scripts/watchdog_auto_notify_orchestrator.mjs" "orchestrator": "plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs"
}, },
"artifact_roots": { "artifact_roots": {
"watchdogEvidence": "state/long-task-watchdog", "watchdogEvidence": "state/long-task-watchdog",

View File

@@ -1,10 +1,14 @@
import fs from 'node:fs';
import path from 'node:path'; import path from 'node:path';
import process from 'node:process'; import process from 'node:process';
const ENV_PREFIX = 'OPENCLAW_REPORTING_GOVERNANCE_'; const ENV_PREFIX = 'OPENCLAW_REPORTING_GOVERNANCE_';
const packageRoot = path.resolve(import.meta.dirname, '..', '..'); const packageRoot = path.resolve(import.meta.dirname, '..', '..');
const repoRoot = packageRoot; const repoRoot = path.resolve(packageRoot, '..', '..');
const DEFAULT_SCRIPT_ROOT = path.join(packageRoot, 'scripts');
const LEGACY_SCRIPT_ROOT = path.join(repoRoot, 'scripts');
const SCRIPT_NAMES = { const SCRIPT_NAMES = {
watchdog: 'long_task_watchdog.mjs', watchdog: 'long_task_watchdog.mjs',
@@ -26,6 +30,14 @@ function normalizeString(value) {
return typeof value === 'string' && value.trim() ? value.trim() : null; return typeof value === 'string' && value.trim() ? value.trim() : null;
} }
function defaultScriptPath(fileName) {
const packagePath = path.join(DEFAULT_SCRIPT_ROOT, fileName);
if (fs.existsSync(packagePath)) {
return packagePath;
}
return path.join(LEGACY_SCRIPT_ROOT, fileName);
}
export function resolveRepoPath(...segments) { export function resolveRepoPath(...segments) {
return path.join(repoRoot, ...segments); return path.join(repoRoot, ...segments);
} }
@@ -36,7 +48,7 @@ export function createRuntimeBinding(overrides = {}) {
for (const [key, fileName] of Object.entries(SCRIPT_NAMES)) { for (const [key, fileName] of Object.entries(SCRIPT_NAMES)) {
const envValue = normalizeString(process.env[SCRIPT_ENV_KEYS[key]]); const envValue = normalizeString(process.env[SCRIPT_ENV_KEYS[key]]);
const overrideValue = normalizeString(overrides?.scripts?.[key]); const overrideValue = normalizeString(overrides?.scripts?.[key]);
scripts[key] = path.resolve(overrideValue ?? envValue ?? resolveRepoPath('scripts', fileName)); scripts[key] = path.resolve(overrideValue ?? envValue ?? defaultScriptPath(fileName));
} }
return { return {
@@ -56,4 +68,4 @@ export function resolveScriptPath(name, options = {}) {
return path.resolve(scriptPath); return path.resolve(scriptPath);
} }
export { packageRoot, repoRoot, SCRIPT_ENV_KEYS, SCRIPT_NAMES }; export { packageRoot, repoRoot, SCRIPT_ENV_KEYS, SCRIPT_NAMES, DEFAULT_SCRIPT_ROOT, LEGACY_SCRIPT_ROOT };

View File

@@ -2,7 +2,7 @@ import fs from 'node:fs';
import path from 'node:path'; import path from 'node:path';
const packageRoot = path.resolve(import.meta.dirname, '..', '..'); const packageRoot = path.resolve(import.meta.dirname, '..', '..');
const repoRoot = packageRoot; const repoRoot = path.resolve(packageRoot, '..', '..');
const EXPECTED_KIND = 'DeploymentProfileArtifact'; const EXPECTED_KIND = 'DeploymentProfileArtifact';
const EXPECTED_API_VERSION = 'reporting-governance/v1alpha1'; const EXPECTED_API_VERSION = 'reporting-governance/v1alpha1';

View File

@@ -10,6 +10,7 @@ const schemaPath = path.resolve(packageRoot, 'schemas', 'reporting-governance',
const artifactSchemaRefPath = './schemas/reporting-governance/deployment-profile.schema.json'; const artifactSchemaRefPath = './schemas/reporting-governance/deployment-profile.schema.json';
const defaultSourceProfilePath = path.join('profiles-src', 'strict-manager-mode.yaml'); const defaultSourceProfilePath = path.join('profiles-src', 'strict-manager-mode.yaml');
const packageScriptsRoot = 'scripts'; const packageScriptsRoot = 'scripts';
const packageScriptsRepoPrefix = 'plugins/reporting-governance';
function readText(filePath) { function readText(filePath) {
return fs.readFileSync(filePath, 'utf8'); return fs.readFileSync(filePath, 'utf8');
@@ -73,6 +74,7 @@ export function generateDeploymentProfileArtifact(profile, { sourceProfile } = {
const validated = validateDeploymentProfileSchema(profile); const validated = validateDeploymentProfileSchema(profile);
const id = validated.metadata.id; const id = validated.metadata.id;
const sourceProfilePath = sourceProfile ?? (id === 'strict-manager-mode' ? defaultSourceProfilePath : path.join('profiles-src', `${id}.yaml`)); const sourceProfilePath = sourceProfile ?? (id === 'strict-manager-mode' ? defaultSourceProfilePath : path.join('profiles-src', `${id}.yaml`));
const scriptPrefix = `${packageScriptsRepoPrefix}/${packageScriptsRoot}`;
return { return {
$schema: artifactSchemaRefPath, $schema: artifactSchemaRefPath,
@@ -91,13 +93,13 @@ export function generateDeploymentProfileArtifact(profile, { sourceProfile } = {
}, },
bindings: { bindings: {
runtime: validated.metadata.runtime, runtime: validated.metadata.runtime,
entrypoint: `${packageScriptsRoot}/watchdog_auto_notify_orchestrator.mjs`, entrypoint: `${scriptPrefix}/watchdog_auto_notify_orchestrator.mjs`,
scripts: { scripts: {
watchdog: `${packageScriptsRoot}/long_task_watchdog.mjs`, watchdog: `${scriptPrefix}/long_task_watchdog.mjs`,
dispatcher: `${packageScriptsRoot}/operator_notify_dispatcher.mjs`, dispatcher: `${scriptPrefix}/operator_notify_dispatcher.mjs`,
bridgeSupervisor: `${packageScriptsRoot}/operator_notify_bridge_supervisor.mjs`, bridgeSupervisor: `${scriptPrefix}/operator_notify_bridge_supervisor.mjs`,
senderBinding: `${packageScriptsRoot}/operator_notify_sender_binding.mjs`, senderBinding: `${scriptPrefix}/operator_notify_sender_binding.mjs`,
orchestrator: `${packageScriptsRoot}/watchdog_auto_notify_orchestrator.mjs`, orchestrator: `${scriptPrefix}/watchdog_auto_notify_orchestrator.mjs`,
}, },
artifact_roots: { artifact_roots: {
watchdogEvidence: 'state/long-task-watchdog', watchdogEvidence: 'state/long-task-watchdog',

View File

@@ -66,13 +66,13 @@ const strictProfileArtifact = {
}, },
bindings: { bindings: {
runtime: 'openclaw', runtime: 'openclaw',
entrypoint: 'scripts/watchdog_auto_notify_orchestrator.mjs', entrypoint: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs',
scripts: { scripts: {
watchdog: 'scripts/long_task_watchdog.mjs', watchdog: 'plugins/reporting-governance/scripts/long_task_watchdog.mjs',
dispatcher: 'scripts/operator_notify_dispatcher.mjs', dispatcher: 'plugins/reporting-governance/scripts/operator_notify_dispatcher.mjs',
bridgeSupervisor: 'scripts/operator_notify_bridge_supervisor.mjs', bridgeSupervisor: 'plugins/reporting-governance/scripts/operator_notify_bridge_supervisor.mjs',
senderBinding: 'scripts/operator_notify_sender_binding.mjs', senderBinding: 'plugins/reporting-governance/scripts/operator_notify_sender_binding.mjs',
orchestrator: 'scripts/watchdog_auto_notify_orchestrator.mjs' orchestrator: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs'
}, },
artifact_roots: { artifact_roots: {
queueItems: 'state/operator-notify-queue' queueItems: 'state/operator-notify-queue'

View File

@@ -313,13 +313,13 @@ test('executeGovernanceContract exposes deployment binding when profile artifact
...strictProfile.spec, ...strictProfile.spec,
bindings: { bindings: {
runtime: 'openclaw', runtime: 'openclaw',
entrypoint: 'scripts/watchdog_auto_notify_orchestrator.mjs', entrypoint: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs',
scripts: { scripts: {
watchdog: 'scripts/long_task_watchdog.mjs', watchdog: 'plugins/reporting-governance/scripts/long_task_watchdog.mjs',
dispatcher: 'scripts/operator_notify_dispatcher.mjs', dispatcher: 'plugins/reporting-governance/scripts/operator_notify_dispatcher.mjs',
bridgeSupervisor: 'scripts/operator_notify_bridge_supervisor.mjs', bridgeSupervisor: 'plugins/reporting-governance/scripts/operator_notify_bridge_supervisor.mjs',
senderBinding: 'scripts/operator_notify_sender_binding.mjs', senderBinding: 'plugins/reporting-governance/scripts/operator_notify_sender_binding.mjs',
orchestrator: 'scripts/watchdog_auto_notify_orchestrator.mjs' orchestrator: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs'
}, },
artifact_roots: { artifact_roots: {
queueItems: 'state/operator-notify-queue' queueItems: 'state/operator-notify-queue'
@@ -344,7 +344,7 @@ test('executeGovernanceContract exposes deployment binding when profile artifact
}); });
assert.equal(result.preflight.status, 'pass'); assert.equal(result.preflight.status, 'pass');
assert.equal(result.deploymentBinding.entrypoint, path.resolve(repoRoot, 'scripts/watchdog_auto_notify_orchestrator.mjs')); assert.equal(result.deploymentBinding.entrypoint, path.resolve(repoRoot, 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs'));
assert.equal(result.deploymentBinding.scripts.dispatcher, path.resolve(repoRoot, 'scripts/operator_notify_dispatcher.mjs')); assert.equal(result.deploymentBinding.scripts.dispatcher, path.resolve(repoRoot, 'plugins/reporting-governance/scripts/operator_notify_dispatcher.mjs'));
assert.equal(result.deploymentBinding.artifactRoots.queueItems, path.resolve(repoRoot, 'state/operator-notify-queue')); assert.equal(result.deploymentBinding.artifactRoots.queueItems, path.resolve(repoRoot, 'state/operator-notify-queue'));
}); });

View File

@@ -13,7 +13,7 @@ import {
import { createRuntimeBinding } from '../src/adapters/index.mjs'; import { createRuntimeBinding } from '../src/adapters/index.mjs';
const packageRoot = path.resolve(import.meta.dirname, '..'); const packageRoot = path.resolve(import.meta.dirname, '..');
const repoRoot = path.resolve(packageRoot); const repoRoot = path.resolve(packageRoot, '..', '..');
function createArtifact(overrides = {}) { function createArtifact(overrides = {}) {
return { return {
@@ -23,8 +23,8 @@ function createArtifact(overrides = {}) {
package: { pluginVersion: '0.1.0-mainline' }, package: { pluginVersion: '0.1.0-mainline' },
bindings: { bindings: {
runtime: 'openclaw', runtime: 'openclaw',
entrypoint: 'scripts/watchdog_auto_notify_orchestrator.mjs', entrypoint: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs',
scripts: { watchdog: 'scripts/long_task_watchdog.mjs' }, scripts: { watchdog: 'plugins/reporting-governance/scripts/long_task_watchdog.mjs' },
artifact_roots: { queueItems: 'state/operator-notify-queue' }, artifact_roots: { queueItems: 'state/operator-notify-queue' },
}, },
}, },
@@ -49,8 +49,8 @@ test('deployment binding contract resolves package artifact into real repo scrip
assert.equal(binding.runtime, 'openclaw'); assert.equal(binding.runtime, 'openclaw');
assert.equal(binding.pluginVersion, '0.1.0-mainline'); assert.equal(binding.pluginVersion, '0.1.0-mainline');
assert.equal(binding.compatibilityMode, 'strict_envelope'); assert.equal(binding.compatibilityMode, 'strict_envelope');
assert.equal(binding.entrypoint, path.resolve(repoRoot, 'scripts/watchdog_auto_notify_orchestrator.mjs')); assert.equal(binding.entrypoint, path.resolve(repoRoot, 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs'));
assert.equal(binding.scripts.watchdog, path.resolve(repoRoot, 'scripts/long_task_watchdog.mjs')); assert.equal(binding.scripts.watchdog, path.resolve(repoRoot, 'plugins/reporting-governance/scripts/long_task_watchdog.mjs'));
assert.equal(binding.artifactRoots.queueItems, path.resolve(repoRoot, 'state/operator-notify-queue')); assert.equal(binding.artifactRoots.queueItems, path.resolve(repoRoot, 'state/operator-notify-queue'));
assert.equal(fs.existsSync(binding.scripts.orchestrator), true); assert.equal(fs.existsSync(binding.scripts.orchestrator), true);
}); });
@@ -81,7 +81,7 @@ test('deployment profile artifact validation fails closed on boundary drift', ()
package: { pluginVersion: '0.1.0-mainline' }, package: { pluginVersion: '0.1.0-mainline' },
bindings: { bindings: {
entrypoint: '', entrypoint: '',
scripts: { watchdog: 'scripts/long_task_watchdog.mjs' }, scripts: { watchdog: 'plugins/reporting-governance/scripts/long_task_watchdog.mjs' },
artifact_roots: { queueItems: 'state/operator-notify-queue' }, artifact_roots: { queueItems: 'state/operator-notify-queue' },
}, },
}, },
@@ -94,7 +94,7 @@ test('deployment profile artifact validation fails closed on boundary drift', ()
spec: { spec: {
package: { pluginVersion: '' }, package: { pluginVersion: '' },
bindings: { bindings: {
entrypoint: 'scripts/watchdog_auto_notify_orchestrator.mjs', entrypoint: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs',
scripts: { watchdog: '' }, scripts: { watchdog: '' },
artifact_roots: { queueItems: 'state/operator-notify-queue' }, artifact_roots: { queueItems: 'state/operator-notify-queue' },
}, },
@@ -108,7 +108,7 @@ test('deployment profile artifact validation fails closed on boundary drift', ()
spec: { spec: {
package: { pluginVersion: '0.1.0-mainline' }, package: { pluginVersion: '0.1.0-mainline' },
bindings: { bindings: {
entrypoint: 'scripts/watchdog_auto_notify_orchestrator.mjs', entrypoint: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs',
scripts: [], scripts: [],
artifact_roots: { queueItems: 'state/operator-notify-queue' }, artifact_roots: { queueItems: 'state/operator-notify-queue' },
}, },
@@ -125,7 +125,7 @@ test('deployment profile artifact validation rejects absolute binding paths', ()
package: { pluginVersion: '0.1.0-mainline' }, package: { pluginVersion: '0.1.0-mainline' },
bindings: { bindings: {
entrypoint: '/abs/path', entrypoint: '/abs/path',
scripts: { watchdog: 'scripts/long_task_watchdog.mjs' }, scripts: { watchdog: 'plugins/reporting-governance/scripts/long_task_watchdog.mjs' },
artifact_roots: { queueItems: 'state/operator-notify-queue' }, artifact_roots: { queueItems: 'state/operator-notify-queue' },
}, },
}, },
@@ -138,7 +138,7 @@ test('deployment profile artifact validation rejects absolute binding paths', ()
spec: { spec: {
package: { pluginVersion: '0.1.0-mainline' }, package: { pluginVersion: '0.1.0-mainline' },
bindings: { bindings: {
entrypoint: 'scripts/watchdog_auto_notify_orchestrator.mjs', entrypoint: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs',
scripts: { watchdog: '/abs/path' }, scripts: { watchdog: '/abs/path' },
artifact_roots: { queueItems: 'state/operator-notify-queue' }, artifact_roots: { queueItems: 'state/operator-notify-queue' },
}, },
@@ -152,8 +152,8 @@ test('deployment profile artifact validation rejects absolute binding paths', ()
spec: { spec: {
package: { pluginVersion: '0.1.0-mainline' }, package: { pluginVersion: '0.1.0-mainline' },
bindings: { bindings: {
entrypoint: 'scripts/watchdog_auto_notify_orchestrator.mjs', entrypoint: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs',
scripts: { watchdog: 'scripts/long_task_watchdog.mjs' }, scripts: { watchdog: 'plugins/reporting-governance/scripts/long_task_watchdog.mjs' },
artifact_roots: { queueItems: '/abs/path' }, artifact_roots: { queueItems: '/abs/path' },
}, },
}, },
@@ -169,7 +169,7 @@ test('deployment profile artifact validation rejects escape paths after resoluti
package: { pluginVersion: '0.1.0-mainline' }, package: { pluginVersion: '0.1.0-mainline' },
bindings: { bindings: {
entrypoint: '../../escape', entrypoint: '../../escape',
scripts: { watchdog: 'scripts/long_task_watchdog.mjs' }, scripts: { watchdog: 'plugins/reporting-governance/scripts/long_task_watchdog.mjs' },
artifact_roots: { queueItems: 'state/operator-notify-queue' }, artifact_roots: { queueItems: 'state/operator-notify-queue' },
}, },
}, },
@@ -183,7 +183,7 @@ test('deployment profile artifact validation rejects escape paths after resoluti
spec: { spec: {
package: { pluginVersion: '0.1.0-mainline' }, package: { pluginVersion: '0.1.0-mainline' },
bindings: { bindings: {
entrypoint: 'scripts/watchdog_auto_notify_orchestrator.mjs', entrypoint: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs',
scripts: { watchdog: '../../escape' }, scripts: { watchdog: '../../escape' },
artifact_roots: { queueItems: 'state/operator-notify-queue' }, artifact_roots: { queueItems: 'state/operator-notify-queue' },
}, },
@@ -199,8 +199,8 @@ test('deployment profile artifact validation rejects escape paths after resoluti
spec: { spec: {
package: { pluginVersion: '0.1.0-mainline' }, package: { pluginVersion: '0.1.0-mainline' },
bindings: { bindings: {
entrypoint: 'scripts/watchdog_auto_notify_orchestrator.mjs', entrypoint: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs',
scripts: { watchdog: 'scripts/long_task_watchdog.mjs' }, scripts: { watchdog: 'plugins/reporting-governance/scripts/long_task_watchdog.mjs' },
artifact_roots: { queueItems: '../escape' }, artifact_roots: { queueItems: '../escape' },
}, },
}, },
@@ -216,9 +216,9 @@ test('deployment binding contract allows normalized in-root paths that contain d
package: { pluginVersion: '0.1.0-mainline' }, package: { pluginVersion: '0.1.0-mainline' },
bindings: { bindings: {
runtime: 'openclaw', runtime: 'openclaw',
entrypoint: 'scripts/../scripts/watchdog_auto_notify_orchestrator.mjs', entrypoint: 'plugins/reporting-governance/scripts/../scripts/watchdog_auto_notify_orchestrator.mjs',
scripts: { scripts: {
watchdog: 'scripts/./long_task_watchdog.mjs', watchdog: 'plugins/reporting-governance/scripts/./long_task_watchdog.mjs',
}, },
artifact_roots: { artifact_roots: {
queueItems: 'state/../state/operator-notify-queue', queueItems: 'state/../state/operator-notify-queue',
@@ -229,8 +229,8 @@ test('deployment binding contract allows normalized in-root paths that contain d
repoRootOverride: repoRoot, repoRootOverride: repoRoot,
}); });
assert.equal(binding.entrypoint, path.resolve(repoRoot, 'scripts/watchdog_auto_notify_orchestrator.mjs')); assert.equal(binding.entrypoint, path.resolve(repoRoot, 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs'));
assert.equal(binding.scripts.watchdog, path.resolve(repoRoot, 'scripts/long_task_watchdog.mjs')); assert.equal(binding.scripts.watchdog, path.resolve(repoRoot, 'plugins/reporting-governance/scripts/long_task_watchdog.mjs'));
assert.equal(binding.artifactRoots.queueItems, path.resolve(repoRoot, 'state/operator-notify-queue')); assert.equal(binding.artifactRoots.queueItems, path.resolve(repoRoot, 'state/operator-notify-queue'));
}); });

View File

@@ -380,7 +380,7 @@ test('yaml to artifact generation produces validator-compatible package artifact
assert.equal(artifact.kind, 'DeploymentProfileArtifact'); assert.equal(artifact.kind, 'DeploymentProfileArtifact');
assert.equal(artifact.metadata.source_profile, 'profiles/demo.yaml'); assert.equal(artifact.metadata.source_profile, 'profiles/demo.yaml');
assert.equal(artifact.spec.bindings.entrypoint, 'scripts/watchdog_auto_notify_orchestrator.mjs'); assert.equal(artifact.spec.bindings.entrypoint, 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs');
assert.doesNotThrow(() => validateDeploymentProfileArtifact(artifact)); assert.doesNotThrow(() => validateDeploymentProfileArtifact(artifact));
}); });

View File

@@ -93,13 +93,13 @@ const strictProfileArtifact = {
}, },
bindings: { bindings: {
runtime: 'openclaw', runtime: 'openclaw',
entrypoint: 'scripts/watchdog_auto_notify_orchestrator.mjs', entrypoint: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs',
scripts: { scripts: {
watchdog: 'scripts/long_task_watchdog.mjs', watchdog: 'plugins/reporting-governance/scripts/long_task_watchdog.mjs',
dispatcher: 'scripts/operator_notify_dispatcher.mjs', dispatcher: 'plugins/reporting-governance/scripts/operator_notify_dispatcher.mjs',
bridgeSupervisor: 'scripts/operator_notify_bridge_supervisor.mjs', bridgeSupervisor: 'plugins/reporting-governance/scripts/operator_notify_bridge_supervisor.mjs',
senderBinding: 'scripts/operator_notify_sender_binding.mjs', senderBinding: 'plugins/reporting-governance/scripts/operator_notify_sender_binding.mjs',
orchestrator: 'scripts/watchdog_auto_notify_orchestrator.mjs' orchestrator: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs'
}, },
artifact_roots: { artifact_roots: {
queueItems: 'state/operator-notify-queue' queueItems: 'state/operator-notify-queue'

View File

@@ -127,7 +127,7 @@ test('orchestrator adapter can bootstrap from profile artifact loader path', ()
const result = runOrchestratorAdapter({ const result = runOrchestratorAdapter({
profileId: 'strict-manager-mode', profileId: 'strict-manager-mode',
repoRootOverride: path.resolve(packageRoot), repoRootOverride: path.resolve(packageRoot, '..', '..'),
state: statePath, state: statePath,
evidenceDir: path.join(root, 'evidence'), evidenceDir: path.join(root, 'evidence'),
eventDir: path.join(root, 'events'), eventDir: path.join(root, 'events'),
@@ -160,7 +160,7 @@ test('orchestrator adapter can use artifact_roots.queueItems as the default queu
const result = runOrchestratorAdapter({ const result = runOrchestratorAdapter({
profileId: 'strict-manager-mode', profileId: 'strict-manager-mode',
repoRootOverride: path.resolve(packageRoot), repoRootOverride: path.resolve(packageRoot, '..', '..'),
state: statePath, state: statePath,
evidenceDir: path.join(root, 'evidence'), evidenceDir: path.join(root, 'evidence'),
eventDir: path.join(root, 'events'), eventDir: path.join(root, 'events'),
@@ -184,7 +184,7 @@ test('orchestrator adapter fails closed at use time when artifact_roots.queueIte
const fakeRepoRoot = path.join(sandbox, 'repo'); const fakeRepoRoot = path.join(sandbox, 'repo');
const outsideRoot = path.join(sandbox, 'outside'); const outsideRoot = path.join(sandbox, 'outside');
const realRepoRoot = path.resolve(packageRoot); const realRepoRoot = path.resolve(packageRoot);
fs.mkdirSync(path.join(fakeRepoRoot, 'scripts'), { recursive: true }); fs.mkdirSync(path.join(fakeRepoRoot, 'plugins', 'reporting-governance', 'scripts'), { recursive: true });
fs.mkdirSync(path.join(fakeRepoRoot, 'state', 'operator-notify-queue'), { recursive: true }); fs.mkdirSync(path.join(fakeRepoRoot, 'state', 'operator-notify-queue'), { recursive: true });
fs.mkdirSync(outsideRoot, { recursive: true }); fs.mkdirSync(outsideRoot, { recursive: true });
for (const name of [ for (const name of [
@@ -194,7 +194,7 @@ test('orchestrator adapter fails closed at use time when artifact_roots.queueIte
'operator_notify_bridge_supervisor.mjs', 'operator_notify_bridge_supervisor.mjs',
'operator_notify_sender_binding.mjs', 'operator_notify_sender_binding.mjs',
]) { ]) {
fs.copyFileSync(path.join(realRepoRoot, 'scripts', name), path.join(fakeRepoRoot, 'scripts', name)); fs.copyFileSync(path.join(realRepoRoot, 'scripts', name), path.join(fakeRepoRoot, 'plugins', 'reporting-governance', 'scripts', name));
} }
const deploymentBinding = createDeploymentBindingContract({ const deploymentBinding = createDeploymentBindingContract({
@@ -210,13 +210,13 @@ test('orchestrator adapter fails closed at use time when artifact_roots.queueIte
package: { pluginVersion: '0.1.0-mainline' }, package: { pluginVersion: '0.1.0-mainline' },
bindings: { bindings: {
runtime: 'openclaw', runtime: 'openclaw',
entrypoint: 'scripts/watchdog_auto_notify_orchestrator.mjs', entrypoint: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs',
scripts: { scripts: {
watchdog: 'scripts/long_task_watchdog.mjs', watchdog: 'plugins/reporting-governance/scripts/long_task_watchdog.mjs',
dispatcher: 'scripts/operator_notify_dispatcher.mjs', dispatcher: 'plugins/reporting-governance/scripts/operator_notify_dispatcher.mjs',
bridgeSupervisor: 'scripts/operator_notify_bridge_supervisor.mjs', bridgeSupervisor: 'plugins/reporting-governance/scripts/operator_notify_bridge_supervisor.mjs',
senderBinding: 'scripts/operator_notify_sender_binding.mjs', senderBinding: 'plugins/reporting-governance/scripts/operator_notify_sender_binding.mjs',
orchestrator: 'scripts/watchdog_auto_notify_orchestrator.mjs' orchestrator: 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs'
}, },
artifact_roots: { artifact_roots: {
queueItems: 'state/operator-notify-queue' queueItems: 'state/operator-notify-queue'

View File

@@ -0,0 +1,94 @@
#!/usr/bin/env node
import process from 'node:process';
import { runOrchestratorAdapter } from '../plugins/reporting-governance/src/adapters/orchestrator.mjs';
const cliArgs = parseCliArgs(process.argv.slice(2));
try {
const payload = runOrchestratorAdapter({
compact: cliArgs.compact,
...cliArgs,
});
process.stdout.write(`${JSON.stringify(payload, null, cliArgs.compact ? 0 : 2)}\n`);
} catch (error) {
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
process.exit(1);
}
function parseCliArgs(argv) {
const args = {
state: null,
evidenceDir: null,
eventDir: null,
queueDir: null,
spoolDir: null,
receiptDir: null,
watchdogScript: null,
dispatcherScript: null,
supervisorScript: null,
senderCommand: null,
senderMode: null,
openclawBin: 'openclaw',
now: null,
compact: false,
writeState: false,
claim: false,
dryRun: false,
help: false,
};
for (let i = 0; i < argv.length; i += 1) {
const token = argv[i];
if (token === '--compact') { args.compact = true; continue; }
if (token === '--write-state') { args.writeState = true; continue; }
if (token === '--claim') { args.claim = true; continue; }
if (token === '--dry-run') { args.dryRun = true; continue; }
if (token === '--help' || token === '-h') { args.help = true; continue; }
const pairs = [
['--state', 'state'],
['--evidence-dir', 'evidenceDir'],
['--event-dir', 'eventDir'],
['--queue-dir', 'queueDir'],
['--spool-dir', 'spoolDir'],
['--receipt-dir', 'receiptDir'],
['--watchdog-script', 'watchdogScript'],
['--dispatcher-script', 'dispatcherScript'],
['--supervisor-script', 'supervisorScript'],
['--sender-command', 'senderCommand'],
['--sender-mode', 'senderMode'],
['--openclaw-bin', 'openclawBin'],
['--now', 'now'],
];
let matched = false;
for (const [flag, key] of pairs) {
if (token === flag) {
args[key] = argv[i + 1] ?? args[key];
i += 1;
matched = true;
break;
}
if (token.startsWith(`${flag}=`)) {
args[key] = token.slice(flag.length + 1) || args[key];
matched = true;
break;
}
}
if (matched) continue;
}
if (args.help) {
process.stdout.write([
'Usage:',
' node scripts/watchdog_auto_notify_orchestrator.mjs [--write-state] [--claim] [--dry-run] [--sender-command <shell>] [--sender-mode shim|openclaw-cli] [--openclaw-bin <path>] [--now <iso>] [--compact]',
'',
'Repo-root shim that forwards to package-owned orchestrator implementation.',
'Default runtime binding now resolves package script first; env/override can still point elsewhere.',
].join('\n') + '\n');
process.exit(0);
}
return args;
}