scene-capability-engine 3.0.0
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/CHANGELOG.md +2513 -0
- package/LICENSE +21 -0
- package/README.md +765 -0
- package/README.zh.md +630 -0
- package/bin/kiro-spec-engine.js +796 -0
- package/bin/kse.js +3 -0
- package/bin/sce.js +3 -0
- package/bin/sco.js +3 -0
- package/docs/331-poc-adaptation-roadmap.md +156 -0
- package/docs/331-poc-dual-track-integration-guide.md +120 -0
- package/docs/331-poc-weekly-delivery-checklist.md +52 -0
- package/docs/OFFLINE_INSTALL.md +96 -0
- package/docs/README.md +279 -0
- package/docs/adopt-migration-guide.md +599 -0
- package/docs/adoption-guide.md +616 -0
- package/docs/agent-hooks-analysis.md +815 -0
- package/docs/architecture.md +733 -0
- package/docs/articles/ai-driven-development-philosophy-and-practice-review.md +208 -0
- package/docs/articles/ai-driven-development-philosophy-and-practice.en.md +459 -0
- package/docs/articles/ai-driven-development-philosophy-and-practice.md +492 -0
- package/docs/autonomous-control-guide.md +851 -0
- package/docs/command-reference.md +1368 -0
- package/docs/community.md +115 -0
- package/docs/cross-tool-guide.md +555 -0
- package/docs/developer-guide.md +619 -0
- package/docs/document-governance.md +865 -0
- package/docs/environment-management-guide.md +526 -0
- package/docs/examples/add-export-command/design.md +194 -0
- package/docs/examples/add-export-command/requirements.md +110 -0
- package/docs/examples/add-export-command/tasks.md +88 -0
- package/docs/examples/add-rest-api/design.md +855 -0
- package/docs/examples/add-rest-api/requirements.md +323 -0
- package/docs/examples/add-rest-api/tasks.md +355 -0
- package/docs/examples/add-user-dashboard/design.md +192 -0
- package/docs/examples/add-user-dashboard/requirements.md +143 -0
- package/docs/examples/add-user-dashboard/tasks.md +91 -0
- package/docs/faq.md +697 -0
- package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.json +156 -0
- package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.md +24 -0
- package/docs/images/wechat-qr.png +0 -0
- package/docs/integration-modes.md +529 -0
- package/docs/integration-philosophy.md +313 -0
- package/docs/knowledge-management-guide.md +263 -0
- package/docs/manual-workflows-guide.md +418 -0
- package/docs/moqui-capability-matrix.md +73 -0
- package/docs/moqui-template-core-library-playbook.md +109 -0
- package/docs/multi-agent-coordination-guide.md +553 -0
- package/docs/multi-repo-management-guide.md +1344 -0
- package/docs/quick-start-with-ai-tools.md +375 -0
- package/docs/quick-start.md +146 -0
- package/docs/release-checklist.md +121 -0
- package/docs/releases/README.md +13 -0
- package/docs/releases/v1.46.2-validation.md +45 -0
- package/docs/releases/v1.46.2.md +50 -0
- package/docs/scene-runtime-guide.md +347 -0
- package/docs/spec-collaboration-guide.md +369 -0
- package/docs/spec-locking-guide.md +225 -0
- package/docs/spec-numbering-guide.md +348 -0
- package/docs/spec-workflow.md +519 -0
- package/docs/steering-strategy-guide.md +196 -0
- package/docs/team-collaboration-guide.md +465 -0
- package/docs/testing-strategy.md +272 -0
- package/docs/tools/claude-guide.md +654 -0
- package/docs/tools/cursor-guide.md +706 -0
- package/docs/tools/generic-guide.md +446 -0
- package/docs/tools/kiro-guide.md +308 -0
- package/docs/tools/vscode-guide.md +445 -0
- package/docs/tools/windsurf-guide.md +391 -0
- package/docs/troubleshooting.md +1135 -0
- package/docs/upgrade-guide.md +639 -0
- package/docs/value-observability-guide.md +127 -0
- package/docs/zh/README.md +341 -0
- package/docs/zh/quick-start.md +764 -0
- package/docs/zh/release-checklist.md +121 -0
- package/docs/zh/releases/README.md +13 -0
- package/docs/zh/releases/v1.46.2-validation.md +45 -0
- package/docs/zh/releases/v1.46.2.md +50 -0
- package/docs/zh/spec-numbering-guide.md +348 -0
- package/docs/zh/tools/claude-guide.md +349 -0
- package/docs/zh/tools/cursor-guide.md +281 -0
- package/docs/zh/tools/generic-guide.md +499 -0
- package/docs/zh/tools/kiro-guide.md +342 -0
- package/docs/zh/tools/vscode-guide.md +449 -0
- package/docs/zh/tools/windsurf-guide.md +378 -0
- package/docs/zh/value-observability-guide.md +127 -0
- package/docs//344/272/244/344/273/230/346/270/205/345/215/225.md +75 -0
- package/lib/adoption/adoption-logger.js +487 -0
- package/lib/adoption/adoption-strategy.js +538 -0
- package/lib/adoption/backup-manager.js +420 -0
- package/lib/adoption/conflict-resolver.js +410 -0
- package/lib/adoption/detection-engine.js +275 -0
- package/lib/adoption/diff-viewer.js +226 -0
- package/lib/adoption/error-formatter.js +509 -0
- package/lib/adoption/file-classifier.js +385 -0
- package/lib/adoption/progress-reporter.js +534 -0
- package/lib/adoption/smart-orchestrator.js +470 -0
- package/lib/adoption/strategy-selector.js +218 -0
- package/lib/adoption/summary-generator.js +493 -0
- package/lib/adoption/template-sync.js +605 -0
- package/lib/auto/autonomous-engine.js +485 -0
- package/lib/auto/checkpoint-manager.js +300 -0
- package/lib/auto/close-loop-runner.js +2476 -0
- package/lib/auto/config-schema.js +176 -0
- package/lib/auto/decision-engine.js +344 -0
- package/lib/auto/error-recovery-manager.js +580 -0
- package/lib/auto/goal-decomposer.js +278 -0
- package/lib/auto/progress-tracker.js +502 -0
- package/lib/auto/safety-manager.js +186 -0
- package/lib/auto/semantic-decomposer.js +137 -0
- package/lib/auto/state-manager.js +126 -0
- package/lib/auto/task-queue-manager.js +340 -0
- package/lib/backup/backup-system.js +372 -0
- package/lib/backup/selective-backup.js +207 -0
- package/lib/collab/agent-registry.js +240 -0
- package/lib/collab/collab-manager.js +285 -0
- package/lib/collab/contract-manager.js +320 -0
- package/lib/collab/coordinator.js +370 -0
- package/lib/collab/dependency-manager.js +280 -0
- package/lib/collab/index.js +20 -0
- package/lib/collab/integration-manager.js +202 -0
- package/lib/collab/merge-coordinator.js +252 -0
- package/lib/collab/metadata-manager.js +233 -0
- package/lib/collab/multi-agent-config.js +120 -0
- package/lib/collab/spec-lifecycle-manager.js +304 -0
- package/lib/collab/sync-barrier.js +88 -0
- package/lib/collab/visualizer.js +208 -0
- package/lib/commands/adopt.js +749 -0
- package/lib/commands/auto.js +19559 -0
- package/lib/commands/collab.js +275 -0
- package/lib/commands/context.js +99 -0
- package/lib/commands/docs.js +808 -0
- package/lib/commands/doctor.js +273 -0
- package/lib/commands/env.js +420 -0
- package/lib/commands/knowledge.js +309 -0
- package/lib/commands/lock.js +235 -0
- package/lib/commands/ops.js +409 -0
- package/lib/commands/orchestrate.js +446 -0
- package/lib/commands/prompt.js +105 -0
- package/lib/commands/repo.js +118 -0
- package/lib/commands/rollback.js +219 -0
- package/lib/commands/scene.js +15549 -0
- package/lib/commands/spec-bootstrap.js +147 -0
- package/lib/commands/spec-gate.js +157 -0
- package/lib/commands/spec-pipeline.js +205 -0
- package/lib/commands/status.js +321 -0
- package/lib/commands/task.js +199 -0
- package/lib/commands/templates.js +654 -0
- package/lib/commands/upgrade.js +231 -0
- package/lib/commands/value.js +569 -0
- package/lib/commands/watch.js +684 -0
- package/lib/commands/workflows.js +240 -0
- package/lib/commands/workspace-multi.js +325 -0
- package/lib/commands/workspace.js +189 -0
- package/lib/context/context-exporter.js +378 -0
- package/lib/context/prompt-generator.js +482 -0
- package/lib/data/moqui-capability-lexicon.json +45 -0
- package/lib/environment/backup-system.js +189 -0
- package/lib/environment/environment-manager.js +379 -0
- package/lib/environment/environment-registry.js +168 -0
- package/lib/gitignore/gitignore-backup.js +229 -0
- package/lib/gitignore/gitignore-detector.js +239 -0
- package/lib/gitignore/gitignore-integration.js +267 -0
- package/lib/gitignore/gitignore-transformer.js +193 -0
- package/lib/gitignore/layered-rules-template.js +42 -0
- package/lib/governance/archive-tool.js +284 -0
- package/lib/governance/cleanup-tool.js +237 -0
- package/lib/governance/config-manager.js +186 -0
- package/lib/governance/diagnostic-engine.js +271 -0
- package/lib/governance/doc-reference-checker.js +200 -0
- package/lib/governance/execution-logger.js +243 -0
- package/lib/governance/file-scanner.js +285 -0
- package/lib/governance/hooks-manager.js +333 -0
- package/lib/governance/reporter.js +337 -0
- package/lib/governance/validation-engine.js +181 -0
- package/lib/i18n.js +79 -0
- package/lib/knowledge/entry-manager.js +208 -0
- package/lib/knowledge/index-manager.js +261 -0
- package/lib/knowledge/knowledge-manager.js +273 -0
- package/lib/knowledge/template-manager.js +191 -0
- package/lib/lock/index.js +21 -0
- package/lib/lock/lock-file.js +192 -0
- package/lib/lock/lock-manager.js +321 -0
- package/lib/lock/machine-identifier.js +135 -0
- package/lib/lock/steering-file-lock.js +207 -0
- package/lib/lock/task-lock-manager.js +345 -0
- package/lib/operations/audit-logger.js +293 -0
- package/lib/operations/feedback-manager.js +1147 -0
- package/lib/operations/index.js +23 -0
- package/lib/operations/models/index.js +170 -0
- package/lib/operations/operations-manager.js +151 -0
- package/lib/operations/operations-validator.js +280 -0
- package/lib/operations/permission-manager.js +354 -0
- package/lib/operations/template-loader.js +143 -0
- package/lib/orchestrator/agent-spawner.js +629 -0
- package/lib/orchestrator/bootstrap-prompt-builder.js +236 -0
- package/lib/orchestrator/index.js +19 -0
- package/lib/orchestrator/orchestration-engine.js +1270 -0
- package/lib/orchestrator/orchestrator-config.js +173 -0
- package/lib/orchestrator/status-monitor.js +591 -0
- package/lib/python-checker.js +209 -0
- package/lib/repo/config-manager.js +580 -0
- package/lib/repo/errors/config-error.js +13 -0
- package/lib/repo/errors/git-error.js +15 -0
- package/lib/repo/errors/repo-error.js +14 -0
- package/lib/repo/git-operations.js +181 -0
- package/lib/repo/handlers/.gitkeep +1 -0
- package/lib/repo/handlers/exec-handler.js +155 -0
- package/lib/repo/handlers/health-handler.js +169 -0
- package/lib/repo/handlers/init-handler.js +197 -0
- package/lib/repo/handlers/status-handler.js +176 -0
- package/lib/repo/output-formatter.js +184 -0
- package/lib/repo/path-resolver.js +178 -0
- package/lib/repo/repo-manager.js +514 -0
- package/lib/scene-runtime/audit-emitter.js +59 -0
- package/lib/scene-runtime/binding-plugin-loader.js +351 -0
- package/lib/scene-runtime/binding-registry.js +349 -0
- package/lib/scene-runtime/eval-bridge.js +44 -0
- package/lib/scene-runtime/index.js +19 -0
- package/lib/scene-runtime/moqui-adapter.js +620 -0
- package/lib/scene-runtime/moqui-client.js +606 -0
- package/lib/scene-runtime/moqui-extractor.js +2029 -0
- package/lib/scene-runtime/plan-compiler.js +208 -0
- package/lib/scene-runtime/policy-gate.js +58 -0
- package/lib/scene-runtime/runtime-executor.js +358 -0
- package/lib/scene-runtime/scene-loader.js +96 -0
- package/lib/scene-runtime/scene-ontology.js +959 -0
- package/lib/scene-runtime/scene-template-linter.js +852 -0
- package/lib/scene-runtime/templates/scene-template-erp-query-v0.1.yaml +28 -0
- package/lib/scene-runtime/templates/scene-template-hybrid-shadow-v0.1.yaml +34 -0
- package/lib/spec/bootstrap/context-collector.js +48 -0
- package/lib/spec/bootstrap/draft-generator.js +158 -0
- package/lib/spec/bootstrap/questionnaire-engine.js +70 -0
- package/lib/spec/bootstrap/trace-emitter.js +59 -0
- package/lib/spec/multi-spec-orchestrate.js +93 -0
- package/lib/spec/pipeline/constants.js +6 -0
- package/lib/spec/pipeline/stage-adapters.js +118 -0
- package/lib/spec/pipeline/stage-runner.js +146 -0
- package/lib/spec/pipeline/state-store.js +119 -0
- package/lib/spec-gate/engine/gate-engine.js +165 -0
- package/lib/spec-gate/policy/default-policy.js +22 -0
- package/lib/spec-gate/policy/policy-loader.js +103 -0
- package/lib/spec-gate/result-emitter.js +81 -0
- package/lib/spec-gate/rules/default-rules.js +156 -0
- package/lib/spec-gate/rules/rule-registry.js +51 -0
- package/lib/steering/adoption-config.js +164 -0
- package/lib/steering/compliance-auto-fixer.js +204 -0
- package/lib/steering/compliance-cache.js +99 -0
- package/lib/steering/compliance-error-reporter.js +70 -0
- package/lib/steering/context-sync-manager.js +273 -0
- package/lib/steering/index.js +92 -0
- package/lib/steering/spec-steering.js +230 -0
- package/lib/steering/steering-compliance-checker.js +73 -0
- package/lib/steering/steering-loader.js +144 -0
- package/lib/steering/steering-manager.js +289 -0
- package/lib/task/index.js +12 -0
- package/lib/task/task-claimer.js +489 -0
- package/lib/task/task-status-store.js +418 -0
- package/lib/templates/cache-manager.js +440 -0
- package/lib/templates/content-generalizer.js +247 -0
- package/lib/templates/frontmatter-generator.js +128 -0
- package/lib/templates/git-handler.js +471 -0
- package/lib/templates/metadata-collector.js +328 -0
- package/lib/templates/path-utils.js +144 -0
- package/lib/templates/registry-parser.js +505 -0
- package/lib/templates/spec-reader.js +216 -0
- package/lib/templates/template-applicator.js +249 -0
- package/lib/templates/template-creator.js +256 -0
- package/lib/templates/template-error.js +143 -0
- package/lib/templates/template-exporter.js +502 -0
- package/lib/templates/template-manager.js +782 -0
- package/lib/templates/template-validator.js +361 -0
- package/lib/upgrade/migration-engine.js +382 -0
- package/lib/upgrade/migrations/.gitkeep +52 -0
- package/lib/upgrade/migrations/1.0.0-to-1.1.0.js +78 -0
- package/lib/utils/file-diff.js +177 -0
- package/lib/utils/fs-utils.js +274 -0
- package/lib/utils/tool-detector.js +383 -0
- package/lib/utils/validation.js +324 -0
- package/lib/value/gate-summary-emitter.js +99 -0
- package/lib/value/metric-contract-loader.js +210 -0
- package/lib/value/risk-evaluator.js +117 -0
- package/lib/value/weekly-snapshot-builder.js +61 -0
- package/lib/version/version-checker.js +156 -0
- package/lib/version/version-manager.js +327 -0
- package/lib/watch/action-executor.js +458 -0
- package/lib/watch/event-debouncer.js +323 -0
- package/lib/watch/execution-logger.js +550 -0
- package/lib/watch/file-watcher.js +499 -0
- package/lib/watch/presets.js +266 -0
- package/lib/watch/watch-manager.js +533 -0
- package/lib/workspace/multi/global-config.js +150 -0
- package/lib/workspace/multi/index.js +22 -0
- package/lib/workspace/multi/path-utils.js +173 -0
- package/lib/workspace/multi/workspace-context-resolver.js +244 -0
- package/lib/workspace/multi/workspace-registry.js +196 -0
- package/lib/workspace/multi/workspace-state-manager.js +537 -0
- package/lib/workspace/multi/workspace.js +90 -0
- package/lib/workspace/workspace-manager.js +370 -0
- package/lib/workspace/workspace-sync.js +356 -0
- package/locales/en.json +114 -0
- package/locales/zh.json +114 -0
- package/package.json +102 -0
- package/template/.kiro/README.md +247 -0
- package/template/.kiro/hooks/check-spec-on-create.kiro.hook +17 -0
- package/template/.kiro/hooks/run-tests-on-save.kiro.hook +13 -0
- package/template/.kiro/hooks/sync-tasks-on-edit.kiro.hook +16 -0
- package/template/.kiro/specs/SPEC_WORKFLOW_GUIDE.md +134 -0
- package/template/.kiro/steering/CORE_PRINCIPLES.md +133 -0
- package/template/.kiro/steering/CURRENT_CONTEXT.md +30 -0
- package/template/.kiro/steering/ENVIRONMENT.md +35 -0
- package/template/.kiro/steering/RULES_GUIDE.md +46 -0
- package/template/.kiro/templates/operations/default/change-impact.md +112 -0
- package/template/.kiro/templates/operations/default/deployment.md +91 -0
- package/template/.kiro/templates/operations/default/feedback-response.md +269 -0
- package/template/.kiro/templates/operations/default/migration-plan.md +172 -0
- package/template/.kiro/templates/operations/default/monitoring.md +135 -0
- package/template/.kiro/templates/operations/default/operations.md +135 -0
- package/template/.kiro/templates/operations/default/rollback.md +143 -0
- package/template/.kiro/templates/operations/default/tools.yaml +364 -0
- package/template/.kiro/templates/operations/default/troubleshooting.md +123 -0
- package/template/.kiro/tools/backup_manager.py +295 -0
- package/template/.kiro/tools/configuration_manager.py +218 -0
- package/template/.kiro/tools/document_evaluator.py +550 -0
- package/template/.kiro/tools/enhancement_logger.py +168 -0
- package/template/.kiro/tools/error_handler.py +335 -0
- package/template/.kiro/tools/improvement_identifier.py +444 -0
- package/template/.kiro/tools/modification_applicator.py +737 -0
- package/template/.kiro/tools/quality_gate_enforcer.py +207 -0
- package/template/.kiro/tools/quality_scorer.py +305 -0
- package/template/.kiro/tools/report_generator.py +154 -0
- package/template/.kiro/tools/ultrawork_enhancer.py +676 -0
- package/template/.kiro/tools/ultrawork_enhancer_refactored.py +0 -0
- package/template/.kiro/tools/ultrawork_enhancer_v2.py +463 -0
- package/template/.kiro/tools/ultrawork_enhancer_v3.py +606 -0
- package/template/.kiro/tools/workflow_quality_gate.py +100 -0
- package/template/README.md +111 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class EvalBridge {
|
|
2
|
+
buildPayload({ sceneManifest, plan, runResult }) {
|
|
3
|
+
const metrics = {
|
|
4
|
+
success: runResult.status === 'success',
|
|
5
|
+
cycle_time_ms: runResult.duration_ms,
|
|
6
|
+
manual_takeover_rate: runResult.manual_takeover ? 1 : 0,
|
|
7
|
+
policy_violation_count: runResult.policy && runResult.policy.allowed ? 0 : 1,
|
|
8
|
+
node_failure_count: (runResult.node_results || []).filter((item) => item.status === 'failed').length
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
trace_id: runResult.trace_id,
|
|
13
|
+
scene_ref: sceneManifest.metadata.obj_id,
|
|
14
|
+
scene_version: sceneManifest.metadata.obj_version,
|
|
15
|
+
plan_id: plan.plan_id,
|
|
16
|
+
status: runResult.status,
|
|
17
|
+
metrics,
|
|
18
|
+
evidence_summary: {
|
|
19
|
+
node_count: plan.nodes.length,
|
|
20
|
+
evidence_count: (runResult.evidence || []).length
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
score(payload, target = {}) {
|
|
26
|
+
let score = 1;
|
|
27
|
+
|
|
28
|
+
if (target.max_cycle_time_ms && payload.metrics.cycle_time_ms > target.max_cycle_time_ms) {
|
|
29
|
+
score -= 0.2;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (payload.metrics.policy_violation_count > 0) {
|
|
33
|
+
score -= 0.5;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (payload.metrics.node_failure_count > 0) {
|
|
37
|
+
score -= 0.3;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return Math.max(0, Number(score.toFixed(2)));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = EvalBridge;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const SceneLoader = require('./scene-loader');
|
|
2
|
+
const PlanCompiler = require('./plan-compiler');
|
|
3
|
+
const PolicyGate = require('./policy-gate');
|
|
4
|
+
const AuditEmitter = require('./audit-emitter');
|
|
5
|
+
const EvalBridge = require('./eval-bridge');
|
|
6
|
+
const RuntimeExecutor = require('./runtime-executor');
|
|
7
|
+
const BindingRegistry = require('./binding-registry');
|
|
8
|
+
const BindingPluginLoader = require('./binding-plugin-loader');
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
SceneLoader,
|
|
12
|
+
PlanCompiler,
|
|
13
|
+
PolicyGate,
|
|
14
|
+
AuditEmitter,
|
|
15
|
+
EvalBridge,
|
|
16
|
+
RuntimeExecutor,
|
|
17
|
+
BindingRegistry,
|
|
18
|
+
BindingPluginLoader
|
|
19
|
+
};
|
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const MoquiClient = require('./moqui-client');
|
|
6
|
+
|
|
7
|
+
const DEFAULT_TIMEOUT = 30000;
|
|
8
|
+
const DEFAULT_RETRY_COUNT = 2;
|
|
9
|
+
const DEFAULT_RETRY_DELAY = 1000;
|
|
10
|
+
const DEFAULT_CONFIG_FILENAME = 'moqui-adapter.json';
|
|
11
|
+
|
|
12
|
+
const ENTITY_OPERATIONS = ['list', 'get', 'create', 'update', 'delete'];
|
|
13
|
+
const SERVICE_OPERATIONS = ['invoke', 'async', 'job-status'];
|
|
14
|
+
|
|
15
|
+
function resolveAdapterConfigPath(configPath, projectRoot) {
|
|
16
|
+
if (configPath) {
|
|
17
|
+
return path.resolve(projectRoot || process.cwd(), configPath);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return path.resolve(projectRoot || process.cwd(), DEFAULT_CONFIG_FILENAME);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function hasAdapterConfigFile(configPath, projectRoot) {
|
|
24
|
+
const resolvedPath = resolveAdapterConfigPath(configPath, projectRoot);
|
|
25
|
+
return fs.pathExistsSync(resolvedPath);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Load and validate adapter config from file.
|
|
30
|
+
* @param {string} [configPath] - Path to moqui-adapter.json
|
|
31
|
+
* @param {string} [projectRoot] - Project root for relative path resolution
|
|
32
|
+
* @returns {{ config: Object, error?: string }}
|
|
33
|
+
*/
|
|
34
|
+
function loadAdapterConfig(configPath, projectRoot) {
|
|
35
|
+
const resolvedPath = resolveAdapterConfigPath(configPath, projectRoot);
|
|
36
|
+
|
|
37
|
+
let rawContent;
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
rawContent = fs.readFileSync(resolvedPath, 'utf8');
|
|
41
|
+
} catch (err) {
|
|
42
|
+
return {
|
|
43
|
+
config: null,
|
|
44
|
+
error: `CONFIG_NOT_FOUND: Could not read config file at "${resolvedPath}": ${err.message}`
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let parsed;
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
parsed = JSON.parse(rawContent);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
return {
|
|
54
|
+
config: null,
|
|
55
|
+
error: `CONFIG_INVALID_JSON: Failed to parse JSON from "${resolvedPath}": ${err.message}`
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const config = applyConfigDefaults(parsed);
|
|
60
|
+
|
|
61
|
+
return { config };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Apply default values for optional config fields.
|
|
66
|
+
* @param {Object} config - Raw parsed config
|
|
67
|
+
* @returns {Object} Config with defaults applied
|
|
68
|
+
*/
|
|
69
|
+
function applyConfigDefaults(config) {
|
|
70
|
+
if (!config || typeof config !== 'object') {
|
|
71
|
+
return config;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
...config,
|
|
76
|
+
timeout: (config.timeout != null && typeof config.timeout === 'number') ? config.timeout : DEFAULT_TIMEOUT,
|
|
77
|
+
retryCount: (config.retryCount != null && typeof config.retryCount === 'number') ? config.retryCount : DEFAULT_RETRY_COUNT,
|
|
78
|
+
retryDelay: (config.retryDelay != null && typeof config.retryDelay === 'number') ? config.retryDelay : DEFAULT_RETRY_DELAY
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Validate adapter config object.
|
|
84
|
+
* Required: baseUrl, credentials.username, credentials.password
|
|
85
|
+
* @param {Object} config
|
|
86
|
+
* @returns {{ valid: boolean, errors: string[] }}
|
|
87
|
+
*/
|
|
88
|
+
function validateAdapterConfig(config) {
|
|
89
|
+
const errors = [];
|
|
90
|
+
|
|
91
|
+
if (!config || typeof config !== 'object') {
|
|
92
|
+
return { valid: false, errors: ['config must be a non-null object'] };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!config.baseUrl || typeof config.baseUrl !== 'string' || !config.baseUrl.trim()) {
|
|
96
|
+
errors.push('baseUrl is required');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!config.credentials || typeof config.credentials !== 'object') {
|
|
100
|
+
errors.push('credentials is required');
|
|
101
|
+
errors.push('credentials.username is required');
|
|
102
|
+
errors.push('credentials.password is required');
|
|
103
|
+
} else {
|
|
104
|
+
if (!config.credentials.username || typeof config.credentials.username !== 'string' || !config.credentials.username.trim()) {
|
|
105
|
+
errors.push('credentials.username is required');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!config.credentials.password || typeof config.credentials.password !== 'string' || !config.credentials.password.trim()) {
|
|
109
|
+
errors.push('credentials.password is required');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
valid: errors.length === 0,
|
|
115
|
+
errors
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Parse a binding ref into structured operation descriptor.
|
|
121
|
+
*
|
|
122
|
+
* Supported patterns:
|
|
123
|
+
* 'moqui.{Entity}.{op}' → { entity, operation }
|
|
124
|
+
* 'moqui.service.{Name}.invoke' → { service, operation: 'invoke' }
|
|
125
|
+
* 'moqui.service.{Name}.async' → { service, operation: 'invoke', mode: 'async' }
|
|
126
|
+
* 'moqui.service.{Name}.job-status' → { service, operation: 'job-status' }
|
|
127
|
+
* 'moqui.screen.catalog' → { operation: 'screen-catalog' }
|
|
128
|
+
* 'moqui.screen.{Path}' → { screen, operation: 'screen-definition' }
|
|
129
|
+
* 'spec.erp.{name}' → { service, operation: 'invoke' }
|
|
130
|
+
*
|
|
131
|
+
* @param {string} bindingRef
|
|
132
|
+
* @returns {{ entity?, service?, screen?, operation, mode? } | null}
|
|
133
|
+
*/
|
|
134
|
+
function parseBindingRef(bindingRef) {
|
|
135
|
+
if (!bindingRef || typeof bindingRef !== 'string') {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const ref = bindingRef.trim();
|
|
140
|
+
|
|
141
|
+
if (!ref) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Handle spec.erp.{name} pattern
|
|
146
|
+
if (ref.startsWith('spec.erp.')) {
|
|
147
|
+
const name = ref.slice('spec.erp.'.length);
|
|
148
|
+
|
|
149
|
+
if (!name) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return { service: name, operation: 'invoke' };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Handle moqui.* patterns
|
|
157
|
+
if (!ref.startsWith('moqui.')) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const parts = ref.slice('moqui.'.length).split('.');
|
|
162
|
+
|
|
163
|
+
if (parts.length < 1 || !parts[0]) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Handle moqui.service.{Name}.{mode} pattern
|
|
168
|
+
if (parts[0] === 'service') {
|
|
169
|
+
return parseServiceRef(parts.slice(1));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Handle moqui.screen.{path} pattern
|
|
173
|
+
if (parts[0] === 'screen') {
|
|
174
|
+
return parseScreenRef(parts.slice(1));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Handle moqui.{Entity}.{op} pattern
|
|
178
|
+
return parseEntityRef(parts);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Parse service binding ref parts: {Name}.{mode}
|
|
183
|
+
* @param {string[]} parts - Parts after 'moqui.service.'
|
|
184
|
+
* @returns {Object|null}
|
|
185
|
+
*/
|
|
186
|
+
function parseServiceRef(parts) {
|
|
187
|
+
if (parts.length < 2 || !parts[0]) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const serviceName = parts[0];
|
|
192
|
+
const mode = parts[1];
|
|
193
|
+
|
|
194
|
+
if (mode === 'invoke') {
|
|
195
|
+
return { service: serviceName, operation: 'invoke' };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (mode === 'async') {
|
|
199
|
+
return { service: serviceName, operation: 'invoke', mode: 'async' };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (mode === 'job-status') {
|
|
203
|
+
return { service: serviceName, operation: 'job-status' };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Parse screen binding ref parts: {path} or 'catalog'
|
|
211
|
+
* @param {string[]} parts - Parts after 'moqui.screen.'
|
|
212
|
+
* @returns {Object|null}
|
|
213
|
+
*/
|
|
214
|
+
function parseScreenRef(parts) {
|
|
215
|
+
if (parts.length < 1 || !parts[0]) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (parts[0] === 'catalog') {
|
|
220
|
+
return { operation: 'screen-catalog' };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const screenPath = parts.join('.');
|
|
224
|
+
|
|
225
|
+
return { screen: screenPath, operation: 'screen-definition' };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Parse entity binding ref parts: {Entity}.{op}
|
|
230
|
+
* @param {string[]} parts - Parts after 'moqui.'
|
|
231
|
+
* @returns {Object|null}
|
|
232
|
+
*/
|
|
233
|
+
function parseEntityRef(parts) {
|
|
234
|
+
if (parts.length < 2) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const entityName = parts[0];
|
|
239
|
+
const operation = parts[1];
|
|
240
|
+
|
|
241
|
+
if (!ENTITY_OPERATIONS.includes(operation)) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return { entity: entityName, operation };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Map Moqui API response to KSE Execution_Result.
|
|
250
|
+
* @param {Object} moquiResponse - { success, data, meta, error }
|
|
251
|
+
* @param {string} handlerId - Handler identifier (e.g., 'moqui.adapter')
|
|
252
|
+
* @param {string} bindingRef - Original binding ref string
|
|
253
|
+
* @returns {Object} Execution_Result
|
|
254
|
+
*/
|
|
255
|
+
function mapMoquiResponseToResult(moquiResponse, handlerId, bindingRef) {
|
|
256
|
+
if (!moquiResponse || typeof moquiResponse !== 'object') {
|
|
257
|
+
return {
|
|
258
|
+
status: 'failed',
|
|
259
|
+
handler_id: handlerId,
|
|
260
|
+
binding_ref: bindingRef,
|
|
261
|
+
error: {
|
|
262
|
+
code: 'INVALID_RESPONSE',
|
|
263
|
+
message: 'Moqui response is null or not an object',
|
|
264
|
+
details: null
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (moquiResponse.success) {
|
|
270
|
+
return {
|
|
271
|
+
status: 'success',
|
|
272
|
+
handler_id: handlerId,
|
|
273
|
+
binding_ref: bindingRef,
|
|
274
|
+
data: moquiResponse.data !== undefined ? moquiResponse.data : null,
|
|
275
|
+
meta: moquiResponse.meta !== undefined ? moquiResponse.meta : null
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const error = moquiResponse.error || {};
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
status: 'failed',
|
|
283
|
+
handler_id: handlerId,
|
|
284
|
+
binding_ref: bindingRef,
|
|
285
|
+
error: {
|
|
286
|
+
code: error.code || 'UNKNOWN_ERROR',
|
|
287
|
+
message: error.message || 'Unknown error occurred',
|
|
288
|
+
details: error.details !== undefined ? error.details : null
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Build HTTP request details (method + path + body/query) from a parsed binding ref descriptor.
|
|
295
|
+
* @param {Object} descriptor - Parsed binding ref descriptor from parseBindingRef
|
|
296
|
+
* @param {Object} [payload] - Execution payload with data, params, id, jobId, etc.
|
|
297
|
+
* @returns {{ method: string, path: string, body?: Object, query?: Object }}
|
|
298
|
+
*/
|
|
299
|
+
function buildHttpRequest(descriptor, payload = {}) {
|
|
300
|
+
const { entity, service, screen, operation, mode } = descriptor;
|
|
301
|
+
|
|
302
|
+
switch (operation) {
|
|
303
|
+
case 'list': {
|
|
304
|
+
const query = {};
|
|
305
|
+
|
|
306
|
+
if (payload.pageIndex != null) {
|
|
307
|
+
query.pageIndex = payload.pageIndex;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (payload.pageSize != null) {
|
|
311
|
+
query.pageSize = payload.pageSize;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (payload.filter != null) {
|
|
315
|
+
query.filter = payload.filter;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (payload.sort != null) {
|
|
319
|
+
query.sort = payload.sort;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
method: 'GET',
|
|
324
|
+
path: `/api/v1/entities/${entity}`,
|
|
325
|
+
query
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
case 'get': {
|
|
330
|
+
const id = payload.id || (payload.data && payload.data.id);
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
method: 'GET',
|
|
334
|
+
path: `/api/v1/entities/${entity}/${id}`
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
case 'create': {
|
|
339
|
+
return {
|
|
340
|
+
method: 'POST',
|
|
341
|
+
path: `/api/v1/entities/${entity}`,
|
|
342
|
+
body: payload.data || {}
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
case 'update': {
|
|
347
|
+
const id = payload.id || (payload.data && payload.data.id);
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
method: 'PUT',
|
|
351
|
+
path: `/api/v1/entities/${entity}/${id}`,
|
|
352
|
+
body: payload.data || {}
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
case 'delete': {
|
|
357
|
+
const id = payload.id || (payload.data && payload.data.id);
|
|
358
|
+
|
|
359
|
+
return {
|
|
360
|
+
method: 'DELETE',
|
|
361
|
+
path: `/api/v1/entities/${entity}/${id}`
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
case 'invoke': {
|
|
366
|
+
const body = payload.params || payload.data || {};
|
|
367
|
+
|
|
368
|
+
if (mode === 'async') {
|
|
369
|
+
body.async = true;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
method: 'POST',
|
|
374
|
+
path: `/api/v1/services/${service}`,
|
|
375
|
+
body
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
case 'job-status': {
|
|
380
|
+
const jobId = payload.jobId;
|
|
381
|
+
|
|
382
|
+
return {
|
|
383
|
+
method: 'GET',
|
|
384
|
+
path: `/api/v1/services/${service}/jobs/${jobId}`
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
case 'screen-catalog': {
|
|
389
|
+
return {
|
|
390
|
+
method: 'GET',
|
|
391
|
+
path: '/api/v1/screens'
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
case 'screen-definition': {
|
|
396
|
+
return {
|
|
397
|
+
method: 'GET',
|
|
398
|
+
path: `/api/v1/screens/${screen}`
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
default: {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Create a MoquiAdapter handler object for BindingRegistry.register().
|
|
410
|
+
* @param {Object} [options] - { configPath, projectRoot, client }
|
|
411
|
+
* @param {string} [options.configPath] - Path to moqui-adapter.json
|
|
412
|
+
* @param {string} [options.projectRoot] - Project root for relative path resolution
|
|
413
|
+
* @param {Object} [options.client] - Pre-configured MoquiClient instance (for testing/DI)
|
|
414
|
+
* @returns {Object} handler with { id, match, execute, readiness }
|
|
415
|
+
*/
|
|
416
|
+
function createMoquiAdapterHandler(options = {}) {
|
|
417
|
+
const HANDLER_ID = 'moqui.adapter';
|
|
418
|
+
const allowSpecErpFallback = options.allowSpecErpFallback !== false;
|
|
419
|
+
const strictMatch = options.strictMatch === true;
|
|
420
|
+
|
|
421
|
+
let client = options.client || null;
|
|
422
|
+
let configLoaded = false;
|
|
423
|
+
let loadedConfig = null;
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Ensure the MoquiClient is initialized.
|
|
427
|
+
* Loads config and creates client if not already done.
|
|
428
|
+
* @returns {{ client: Object, error?: string }}
|
|
429
|
+
*/
|
|
430
|
+
function ensureClient() {
|
|
431
|
+
if (client) {
|
|
432
|
+
return { client };
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (!configLoaded) {
|
|
436
|
+
const result = loadAdapterConfig(options.configPath, options.projectRoot);
|
|
437
|
+
|
|
438
|
+
if (result.error) {
|
|
439
|
+
return { client: null, error: result.error };
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const validation = validateAdapterConfig(result.config);
|
|
443
|
+
|
|
444
|
+
if (!validation.valid) {
|
|
445
|
+
return { client: null, error: `CONFIG_VALIDATION: ${validation.errors.join(', ')}` };
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
loadedConfig = result.config;
|
|
449
|
+
configLoaded = true;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
client = new MoquiClient(loadedConfig);
|
|
453
|
+
|
|
454
|
+
return { client };
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function shouldHandleBindingRef(bindingRef) {
|
|
458
|
+
const ref = String(bindingRef || '').trim();
|
|
459
|
+
|
|
460
|
+
if (!ref) {
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (ref.startsWith('moqui.')) {
|
|
465
|
+
return true;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (!ref.startsWith('spec.erp.')) {
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (strictMatch || !allowSpecErpFallback) {
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (client) {
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return hasAdapterConfigFile(options.configPath, options.projectRoot);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
return {
|
|
484
|
+
id: HANDLER_ID,
|
|
485
|
+
|
|
486
|
+
match: (node = {}) => shouldHandleBindingRef(node.binding_ref || node.ref),
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Execute a binding node against the Moqui REST API.
|
|
490
|
+
* @param {Object} node - Binding node with binding_ref or ref
|
|
491
|
+
* @param {Object} [payload] - Execution payload
|
|
492
|
+
* @returns {Promise<Object>} Execution_Result
|
|
493
|
+
*/
|
|
494
|
+
execute: async (node, payload = {}) => {
|
|
495
|
+
const bindingRef = node.binding_ref || node.ref;
|
|
496
|
+
|
|
497
|
+
// Parse the binding ref
|
|
498
|
+
const descriptor = parseBindingRef(bindingRef);
|
|
499
|
+
|
|
500
|
+
if (!descriptor) {
|
|
501
|
+
return {
|
|
502
|
+
status: 'failed',
|
|
503
|
+
handler_id: HANDLER_ID,
|
|
504
|
+
binding_ref: bindingRef,
|
|
505
|
+
error: {
|
|
506
|
+
code: 'INVALID_BINDING_REF',
|
|
507
|
+
message: `Failed to parse binding ref: "${bindingRef}"`,
|
|
508
|
+
details: null
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Ensure client is ready
|
|
514
|
+
const clientResult = ensureClient();
|
|
515
|
+
|
|
516
|
+
if (clientResult.error) {
|
|
517
|
+
return {
|
|
518
|
+
status: 'failed',
|
|
519
|
+
handler_id: HANDLER_ID,
|
|
520
|
+
binding_ref: bindingRef,
|
|
521
|
+
error: {
|
|
522
|
+
code: 'CLIENT_INIT_ERROR',
|
|
523
|
+
message: clientResult.error,
|
|
524
|
+
details: null
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Build HTTP request from descriptor
|
|
530
|
+
const httpRequest = buildHttpRequest(descriptor, payload);
|
|
531
|
+
|
|
532
|
+
if (!httpRequest) {
|
|
533
|
+
return {
|
|
534
|
+
status: 'failed',
|
|
535
|
+
handler_id: HANDLER_ID,
|
|
536
|
+
binding_ref: bindingRef,
|
|
537
|
+
error: {
|
|
538
|
+
code: 'UNSUPPORTED_OPERATION',
|
|
539
|
+
message: `Unsupported operation: "${descriptor.operation}"`,
|
|
540
|
+
details: null
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Execute the request via MoquiClient
|
|
546
|
+
const requestOptions = {};
|
|
547
|
+
|
|
548
|
+
if (httpRequest.body !== undefined) {
|
|
549
|
+
requestOptions.body = httpRequest.body;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (httpRequest.query !== undefined) {
|
|
553
|
+
requestOptions.query = httpRequest.query;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const moquiResponse = await clientResult.client.request(
|
|
557
|
+
httpRequest.method,
|
|
558
|
+
httpRequest.path,
|
|
559
|
+
requestOptions
|
|
560
|
+
);
|
|
561
|
+
|
|
562
|
+
// Map Moqui response to KSE Execution_Result
|
|
563
|
+
return mapMoquiResponseToResult(moquiResponse, HANDLER_ID, bindingRef);
|
|
564
|
+
},
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Check readiness by verifying Moqui connectivity and authentication.
|
|
568
|
+
* @param {Object} node - Binding node
|
|
569
|
+
* @param {Object} [payload] - Execution payload
|
|
570
|
+
* @returns {Promise<{ passed: boolean, reason: string }>}
|
|
571
|
+
*/
|
|
572
|
+
readiness: async (node, payload = {}) => {
|
|
573
|
+
// Ensure config is loaded and client is created
|
|
574
|
+
const clientResult = ensureClient();
|
|
575
|
+
|
|
576
|
+
if (clientResult.error) {
|
|
577
|
+
return { passed: false, reason: 'moqui-config-error' };
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Attempt login to verify connectivity and authentication
|
|
581
|
+
try {
|
|
582
|
+
const loginResult = await clientResult.client.login();
|
|
583
|
+
|
|
584
|
+
if (loginResult.success) {
|
|
585
|
+
return { passed: true, reason: 'moqui-ready' };
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// Distinguish between network errors and auth errors
|
|
589
|
+
const errorMsg = loginResult.error || '';
|
|
590
|
+
|
|
591
|
+
if (errorMsg.includes('Network error') || errorMsg.includes('ECONNREFUSED') || errorMsg.includes('ENOTFOUND')) {
|
|
592
|
+
return { passed: false, reason: 'moqui-unreachable' };
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return { passed: false, reason: 'moqui-auth-failed' };
|
|
596
|
+
} catch (error) {
|
|
597
|
+
// Network-level errors indicate unreachable
|
|
598
|
+
return { passed: false, reason: 'moqui-unreachable' };
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
module.exports = {
|
|
605
|
+
loadAdapterConfig,
|
|
606
|
+
validateAdapterConfig,
|
|
607
|
+
parseBindingRef,
|
|
608
|
+
mapMoquiResponseToResult,
|
|
609
|
+
buildHttpRequest,
|
|
610
|
+
createMoquiAdapterHandler,
|
|
611
|
+
resolveAdapterConfigPath,
|
|
612
|
+
hasAdapterConfigFile,
|
|
613
|
+
// Exported for testing
|
|
614
|
+
applyConfigDefaults,
|
|
615
|
+
DEFAULT_TIMEOUT,
|
|
616
|
+
DEFAULT_RETRY_COUNT,
|
|
617
|
+
DEFAULT_RETRY_DELAY,
|
|
618
|
+
DEFAULT_CONFIG_FILENAME,
|
|
619
|
+
ENTITY_OPERATIONS
|
|
620
|
+
};
|