@amsterdamdatalabs/enact-factory 0.1.1
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/LICENSE +674 -0
- package/README.md +566 -0
- package/dist/adapters/agenticLoop.d.ts +90 -0
- package/dist/adapters/agenticLoop.d.ts.map +1 -0
- package/dist/adapters/agenticLoop.js +219 -0
- package/dist/adapters/agenticLoop.js.map +1 -0
- package/dist/adapters/base.d.ts +16 -0
- package/dist/adapters/base.d.ts.map +1 -0
- package/dist/adapters/base.js +135 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/claude.d.ts +13 -0
- package/dist/adapters/claude.d.ts.map +1 -0
- package/dist/adapters/claude.js +318 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/codex.d.ts +14 -0
- package/dist/adapters/codex.d.ts.map +1 -0
- package/dist/adapters/codex.js +366 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/cryptoQuantAdapter.d.ts +85 -0
- package/dist/adapters/cryptoQuantAdapter.d.ts.map +1 -0
- package/dist/adapters/cryptoQuantAdapter.js +238 -0
- package/dist/adapters/cryptoQuantAdapter.js.map +1 -0
- package/dist/adapters/cursor.d.ts +13 -0
- package/dist/adapters/cursor.d.ts.map +1 -0
- package/dist/adapters/cursor.js +300 -0
- package/dist/adapters/cursor.js.map +1 -0
- package/dist/adapters/envPath.d.ts +20 -0
- package/dist/adapters/envPath.d.ts.map +1 -0
- package/dist/adapters/envPath.js +49 -0
- package/dist/adapters/envPath.js.map +1 -0
- package/dist/adapters/hermes.d.ts +13 -0
- package/dist/adapters/hermes.d.ts.map +1 -0
- package/dist/adapters/hermes.js +283 -0
- package/dist/adapters/hermes.js.map +1 -0
- package/dist/adapters/index.d.ts +18 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +56 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/opencode.d.ts +13 -0
- package/dist/adapters/opencode.d.ts.map +1 -0
- package/dist/adapters/opencode.js +282 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/adapters/processRegistry.d.ts +38 -0
- package/dist/adapters/processRegistry.d.ts.map +1 -0
- package/dist/adapters/processRegistry.js +147 -0
- package/dist/adapters/processRegistry.js.map +1 -0
- package/dist/adapters/responses.d.ts +16 -0
- package/dist/adapters/responses.d.ts.map +1 -0
- package/dist/adapters/responses.js +244 -0
- package/dist/adapters/responses.js.map +1 -0
- package/dist/adapters/streamBuffer.d.ts +59 -0
- package/dist/adapters/streamBuffer.d.ts.map +1 -0
- package/dist/adapters/streamBuffer.js +123 -0
- package/dist/adapters/streamBuffer.js.map +1 -0
- package/dist/adapters/tools.d.ts +30 -0
- package/dist/adapters/tools.d.ts.map +1 -0
- package/dist/adapters/tools.js +219 -0
- package/dist/adapters/tools.js.map +1 -0
- package/dist/adapters/types.d.ts +82 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +6 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/agents/agentBus.d.ts +160 -0
- package/dist/agents/agentBus.d.ts.map +1 -0
- package/dist/agents/agentBus.js +350 -0
- package/dist/agents/agentBus.js.map +1 -0
- package/dist/agents/agentPair.d.ts +215 -0
- package/dist/agents/agentPair.d.ts.map +1 -0
- package/dist/agents/agentPair.js +456 -0
- package/dist/agents/agentPair.js.map +1 -0
- package/dist/agents/auditor.d.ts +27 -0
- package/dist/agents/auditor.d.ts.map +1 -0
- package/dist/agents/auditor.js +238 -0
- package/dist/agents/auditor.js.map +1 -0
- package/dist/agents/cliStreamParser.d.ts +18 -0
- package/dist/agents/cliStreamParser.d.ts.map +1 -0
- package/dist/agents/cliStreamParser.js +156 -0
- package/dist/agents/cliStreamParser.js.map +1 -0
- package/dist/agents/documenter.d.ts +31 -0
- package/dist/agents/documenter.d.ts.map +1 -0
- package/dist/agents/documenter.js +286 -0
- package/dist/agents/documenter.js.map +1 -0
- package/dist/agents/draftAnalyzer.d.ts +50 -0
- package/dist/agents/draftAnalyzer.d.ts.map +1 -0
- package/dist/agents/draftAnalyzer.js +289 -0
- package/dist/agents/draftAnalyzer.js.map +1 -0
- package/dist/agents/evaluator.d.ts +61 -0
- package/dist/agents/evaluator.d.ts.map +1 -0
- package/dist/agents/evaluator.js +338 -0
- package/dist/agents/evaluator.js.map +1 -0
- package/dist/agents/executor.d.ts +33 -0
- package/dist/agents/executor.d.ts.map +1 -0
- package/dist/agents/executor.js +130 -0
- package/dist/agents/executor.js.map +1 -0
- package/dist/agents/index.d.ts +10 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +10 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/pairMetrics.d.ts +63 -0
- package/dist/agents/pairMetrics.d.ts.map +1 -0
- package/dist/agents/pairMetrics.js +232 -0
- package/dist/agents/pairMetrics.js.map +1 -0
- package/dist/agents/pairPipeline.d.ts +184 -0
- package/dist/agents/pairPipeline.d.ts.map +1 -0
- package/dist/agents/pairPipeline.js +934 -0
- package/dist/agents/pairPipeline.js.map +1 -0
- package/dist/agents/pairWebhook.d.ts +59 -0
- package/dist/agents/pairWebhook.d.ts.map +1 -0
- package/dist/agents/pairWebhook.js +242 -0
- package/dist/agents/pairWebhook.js.map +1 -0
- package/dist/agents/pipelineFormat.d.ts +8 -0
- package/dist/agents/pipelineFormat.d.ts.map +1 -0
- package/dist/agents/pipelineFormat.js +65 -0
- package/dist/agents/pipelineFormat.js.map +1 -0
- package/dist/agents/pipelineGuards.d.ts +23 -0
- package/dist/agents/pipelineGuards.d.ts.map +1 -0
- package/dist/agents/pipelineGuards.js +257 -0
- package/dist/agents/pipelineGuards.js.map +1 -0
- package/dist/agents/reviewer.d.ts +37 -0
- package/dist/agents/reviewer.d.ts.map +1 -0
- package/dist/agents/reviewer.js +214 -0
- package/dist/agents/reviewer.js.map +1 -0
- package/dist/agents/skillDocumenter.d.ts +23 -0
- package/dist/agents/skillDocumenter.d.ts.map +1 -0
- package/dist/agents/skillDocumenter.js +219 -0
- package/dist/agents/skillDocumenter.js.map +1 -0
- package/dist/agents/tester.d.ts +37 -0
- package/dist/agents/tester.d.ts.map +1 -0
- package/dist/agents/tester.js +309 -0
- package/dist/agents/tester.js.map +1 -0
- package/dist/automation/autonomousRunner.d.ts +145 -0
- package/dist/automation/autonomousRunner.d.ts.map +1 -0
- package/dist/automation/autonomousRunner.js +1272 -0
- package/dist/automation/autonomousRunner.js.map +1 -0
- package/dist/automation/dailyReporter.d.ts +26 -0
- package/dist/automation/dailyReporter.d.ts.map +1 -0
- package/dist/automation/dailyReporter.js +130 -0
- package/dist/automation/dailyReporter.js.map +1 -0
- package/dist/automation/index.d.ts +5 -0
- package/dist/automation/index.d.ts.map +1 -0
- package/dist/automation/index.js +5 -0
- package/dist/automation/index.js.map +1 -0
- package/dist/automation/longRunningMonitor.d.ts +26 -0
- package/dist/automation/longRunningMonitor.d.ts.map +1 -0
- package/dist/automation/longRunningMonitor.js +356 -0
- package/dist/automation/longRunningMonitor.js.map +1 -0
- package/dist/automation/prOwnership.d.ts +18 -0
- package/dist/automation/prOwnership.d.ts.map +1 -0
- package/dist/automation/prOwnership.js +61 -0
- package/dist/automation/prOwnership.js.map +1 -0
- package/dist/automation/runnerExecution.d.ts +57 -0
- package/dist/automation/runnerExecution.d.ts.map +1 -0
- package/dist/automation/runnerExecution.js +701 -0
- package/dist/automation/runnerExecution.js.map +1 -0
- package/dist/automation/runnerState.d.ts +170 -0
- package/dist/automation/runnerState.d.ts.map +1 -0
- package/dist/automation/runnerState.js +496 -0
- package/dist/automation/runnerState.js.map +1 -0
- package/dist/automation/runnerTypes.d.ts +57 -0
- package/dist/automation/runnerTypes.d.ts.map +1 -0
- package/dist/automation/runnerTypes.js +5 -0
- package/dist/automation/runnerTypes.js.map +1 -0
- package/dist/automation/scheduler.d.ts +75 -0
- package/dist/automation/scheduler.d.ts.map +1 -0
- package/dist/automation/scheduler.js +402 -0
- package/dist/automation/scheduler.js.map +1 -0
- package/dist/azdo/azdo.d.ts +70 -0
- package/dist/azdo/azdo.d.ts.map +1 -0
- package/dist/azdo/azdo.js +328 -0
- package/dist/azdo/azdo.js.map +1 -0
- package/dist/azdo/index.d.ts +3 -0
- package/dist/azdo/index.d.ts.map +1 -0
- package/dist/azdo/index.js +3 -0
- package/dist/azdo/index.js.map +1 -0
- package/dist/azdo/projectUpdater.d.ts +13 -0
- package/dist/azdo/projectUpdater.d.ts.map +1 -0
- package/dist/azdo/projectUpdater.js +155 -0
- package/dist/azdo/projectUpdater.js.map +1 -0
- package/dist/azureDevOps/client.d.ts +75 -0
- package/dist/azureDevOps/client.d.ts.map +1 -0
- package/dist/azureDevOps/client.js +150 -0
- package/dist/azureDevOps/client.js.map +1 -0
- package/dist/azureDevOps/hierarchy.d.ts +119 -0
- package/dist/azureDevOps/hierarchy.d.ts.map +1 -0
- package/dist/azureDevOps/hierarchy.js +470 -0
- package/dist/azureDevOps/hierarchy.js.map +1 -0
- package/dist/azureDevOps/mapper.d.ts +101 -0
- package/dist/azureDevOps/mapper.d.ts.map +1 -0
- package/dist/azureDevOps/mapper.js +438 -0
- package/dist/azureDevOps/mapper.js.map +1 -0
- package/dist/azureDevOps/stateMapping.d.ts +15 -0
- package/dist/azureDevOps/stateMapping.d.ts.map +1 -0
- package/dist/azureDevOps/stateMapping.js +141 -0
- package/dist/azureDevOps/stateMapping.js.map +1 -0
- package/dist/cli/authHandler.d.ts +13 -0
- package/dist/cli/authHandler.d.ts.map +1 -0
- package/dist/cli/authHandler.js +70 -0
- package/dist/cli/authHandler.js.map +1 -0
- package/dist/cli/checkHandler.d.ts +27 -0
- package/dist/cli/checkHandler.d.ts.map +1 -0
- package/dist/cli/checkHandler.js +560 -0
- package/dist/cli/checkHandler.js.map +1 -0
- package/dist/cli/daemon.d.ts +30 -0
- package/dist/cli/daemon.d.ts.map +1 -0
- package/dist/cli/daemon.js +141 -0
- package/dist/cli/daemon.js.map +1 -0
- package/dist/cli/factoryCommands.d.ts +3 -0
- package/dist/cli/factoryCommands.d.ts.map +1 -0
- package/dist/cli/factoryCommands.js +165 -0
- package/dist/cli/factoryCommands.js.map +1 -0
- package/dist/cli/promptHandler.d.ts +13 -0
- package/dist/cli/promptHandler.d.ts.map +1 -0
- package/dist/cli/promptHandler.js +193 -0
- package/dist/cli/promptHandler.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +320 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/agentLifecycle.d.ts +322 -0
- package/dist/core/agentLifecycle.d.ts.map +1 -0
- package/dist/core/agentLifecycle.js +230 -0
- package/dist/core/agentLifecycle.js.map +1 -0
- package/dist/core/areaMapping.d.ts +9 -0
- package/dist/core/areaMapping.d.ts.map +1 -0
- package/dist/core/areaMapping.js +37 -0
- package/dist/core/areaMapping.js.map +1 -0
- package/dist/core/config.d.ts +469 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +780 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/dashboardContract.d.ts +204 -0
- package/dist/core/dashboardContract.d.ts.map +1 -0
- package/dist/core/dashboardContract.js +205 -0
- package/dist/core/dashboardContract.js.map +1 -0
- package/dist/core/devopsModel.d.ts +138 -0
- package/dist/core/devopsModel.d.ts.map +1 -0
- package/dist/core/devopsModel.js +137 -0
- package/dist/core/devopsModel.js.map +1 -0
- package/dist/core/envFile.d.ts +11 -0
- package/dist/core/envFile.d.ts.map +1 -0
- package/dist/core/envFile.js +104 -0
- package/dist/core/envFile.js.map +1 -0
- package/dist/core/eventHub.d.ts +220 -0
- package/dist/core/eventHub.d.ts.map +1 -0
- package/dist/core/eventHub.js +136 -0
- package/dist/core/eventHub.js.map +1 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +7 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/laneExecutionState.d.ts +29 -0
- package/dist/core/laneExecutionState.d.ts.map +1 -0
- package/dist/core/laneExecutionState.js +18 -0
- package/dist/core/laneExecutionState.js.map +1 -0
- package/dist/core/laneStatus.d.ts +49 -0
- package/dist/core/laneStatus.d.ts.map +1 -0
- package/dist/core/laneStatus.js +153 -0
- package/dist/core/laneStatus.js.map +1 -0
- package/dist/core/prSidecar.d.ts +96 -0
- package/dist/core/prSidecar.d.ts.map +1 -0
- package/dist/core/prSidecar.js +33 -0
- package/dist/core/prSidecar.js.map +1 -0
- package/dist/core/runtimeConfig.d.ts +6 -0
- package/dist/core/runtimeConfig.d.ts.map +1 -0
- package/dist/core/runtimeConfig.js +24 -0
- package/dist/core/runtimeConfig.js.map +1 -0
- package/dist/core/scmProvider.d.ts +19 -0
- package/dist/core/scmProvider.d.ts.map +1 -0
- package/dist/core/scmProvider.js +38 -0
- package/dist/core/scmProvider.js.map +1 -0
- package/dist/core/service.d.ts +10 -0
- package/dist/core/service.d.ts.map +1 -0
- package/dist/core/service.js +297 -0
- package/dist/core/service.js.map +1 -0
- package/dist/core/traceCollector.d.ts +105 -0
- package/dist/core/traceCollector.d.ts.map +1 -0
- package/dist/core/traceCollector.js +141 -0
- package/dist/core/traceCollector.js.map +1 -0
- package/dist/core/types.d.ts +432 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/workItemMapper.d.ts +39 -0
- package/dist/core/workItemMapper.d.ts.map +1 -0
- package/dist/core/workItemMapper.js +427 -0
- package/dist/core/workItemMapper.js.map +1 -0
- package/dist/core/workItemModel.d.ts +120 -0
- package/dist/core/workItemModel.d.ts.map +1 -0
- package/dist/core/workItemModel.js +104 -0
- package/dist/core/workItemModel.js.map +1 -0
- package/dist/core/workItemPayload.d.ts +195 -0
- package/dist/core/workItemPayload.d.ts.map +1 -0
- package/dist/core/workItemPayload.js +24 -0
- package/dist/core/workItemPayload.js.map +1 -0
- package/dist/core/workspaceConfig.d.ts +57 -0
- package/dist/core/workspaceConfig.d.ts.map +1 -0
- package/dist/core/workspaceConfig.js +184 -0
- package/dist/core/workspaceConfig.js.map +1 -0
- package/dist/doctor.d.ts +18 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +34 -0
- package/dist/doctor.js.map +1 -0
- package/dist/factory/activeSkill.d.ts +11 -0
- package/dist/factory/activeSkill.d.ts.map +1 -0
- package/dist/factory/activeSkill.js +44 -0
- package/dist/factory/activeSkill.js.map +1 -0
- package/dist/factory/assignment.d.ts +54 -0
- package/dist/factory/assignment.d.ts.map +1 -0
- package/dist/factory/assignment.js +94 -0
- package/dist/factory/assignment.js.map +1 -0
- package/dist/factory/auditLog.d.ts +10 -0
- package/dist/factory/auditLog.d.ts.map +1 -0
- package/dist/factory/auditLog.js +38 -0
- package/dist/factory/auditLog.js.map +1 -0
- package/dist/factory/closureRequirements.d.ts +12 -0
- package/dist/factory/closureRequirements.d.ts.map +1 -0
- package/dist/factory/closureRequirements.js +30 -0
- package/dist/factory/closureRequirements.js.map +1 -0
- package/dist/factory/delegationPrompt.d.ts +3 -0
- package/dist/factory/delegationPrompt.d.ts.map +1 -0
- package/dist/factory/delegationPrompt.js +16 -0
- package/dist/factory/delegationPrompt.js.map +1 -0
- package/dist/factory/http.d.ts +3 -0
- package/dist/factory/http.d.ts.map +1 -0
- package/dist/factory/http.js +555 -0
- package/dist/factory/http.js.map +1 -0
- package/dist/factory/lifecyclePushMap.d.ts +4 -0
- package/dist/factory/lifecyclePushMap.d.ts.map +1 -0
- package/dist/factory/lifecyclePushMap.js +7 -0
- package/dist/factory/lifecyclePushMap.js.map +1 -0
- package/dist/factory/missions.d.ts +125 -0
- package/dist/factory/missions.d.ts.map +1 -0
- package/dist/factory/missions.js +304 -0
- package/dist/factory/missions.js.map +1 -0
- package/dist/factory/mode.d.ts +9 -0
- package/dist/factory/mode.d.ts.map +1 -0
- package/dist/factory/mode.js +30 -0
- package/dist/factory/mode.js.map +1 -0
- package/dist/factory/operatorActiveSkill.d.ts +15 -0
- package/dist/factory/operatorActiveSkill.d.ts.map +1 -0
- package/dist/factory/operatorActiveSkill.js +95 -0
- package/dist/factory/operatorActiveSkill.js.map +1 -0
- package/dist/factory/paseoDispatcher.d.ts +52 -0
- package/dist/factory/paseoDispatcher.d.ts.map +1 -0
- package/dist/factory/paseoDispatcher.js +122 -0
- package/dist/factory/paseoDispatcher.js.map +1 -0
- package/dist/factory/paseoLifecycle.d.ts +32 -0
- package/dist/factory/paseoLifecycle.d.ts.map +1 -0
- package/dist/factory/paseoLifecycle.js +260 -0
- package/dist/factory/paseoLifecycle.js.map +1 -0
- package/dist/factory/paths.d.ts +31 -0
- package/dist/factory/paths.d.ts.map +1 -0
- package/dist/factory/paths.js +139 -0
- package/dist/factory/paths.js.map +1 -0
- package/dist/factory/progressWatchdog.d.ts +58 -0
- package/dist/factory/progressWatchdog.d.ts.map +1 -0
- package/dist/factory/progressWatchdog.js +160 -0
- package/dist/factory/progressWatchdog.js.map +1 -0
- package/dist/factory/roster.d.ts +59 -0
- package/dist/factory/roster.d.ts.map +1 -0
- package/dist/factory/roster.js +116 -0
- package/dist/factory/roster.js.map +1 -0
- package/dist/factory/runtime.d.ts +44 -0
- package/dist/factory/runtime.d.ts.map +1 -0
- package/dist/factory/runtime.js +238 -0
- package/dist/factory/runtime.js.map +1 -0
- package/dist/factory/sync.d.ts +29 -0
- package/dist/factory/sync.d.ts.map +1 -0
- package/dist/factory/sync.js +77 -0
- package/dist/factory/sync.js.map +1 -0
- package/dist/factory/workitemQueues.d.ts +37 -0
- package/dist/factory/workitemQueues.d.ts.map +1 -0
- package/dist/factory/workitemQueues.js +99 -0
- package/dist/factory/workitemQueues.js.map +1 -0
- package/dist/factory/workitemTriage.d.ts +9 -0
- package/dist/factory/workitemTriage.d.ts.map +1 -0
- package/dist/factory/workitemTriage.js +81 -0
- package/dist/factory/workitemTriage.js.map +1 -0
- package/dist/hooks.d.ts +18 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +96 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +90 -0
- package/dist/index.js.map +1 -0
- package/dist/install/agentCatalog.d.ts +7 -0
- package/dist/install/agentCatalog.d.ts.map +1 -0
- package/dist/install/agentCatalog.js +28 -0
- package/dist/install/agentCatalog.js.map +1 -0
- package/dist/install/bundlePaths.d.ts +10 -0
- package/dist/install/bundlePaths.d.ts.map +1 -0
- package/dist/install/bundlePaths.js +30 -0
- package/dist/install/bundlePaths.js.map +1 -0
- package/dist/install/codex.d.ts +43 -0
- package/dist/install/codex.d.ts.map +1 -0
- package/dist/install/codex.js +207 -0
- package/dist/install/codex.js.map +1 -0
- package/dist/install/enactHome.d.ts +37 -0
- package/dist/install/enactHome.d.ts.map +1 -0
- package/dist/install/enactHome.js +152 -0
- package/dist/install/enactHome.js.map +1 -0
- package/dist/install/plugins.d.ts +115 -0
- package/dist/install/plugins.d.ts.map +1 -0
- package/dist/install/plugins.js +259 -0
- package/dist/install/plugins.js.map +1 -0
- package/dist/install/setup.d.ts +33 -0
- package/dist/install/setup.d.ts.map +1 -0
- package/dist/install/setup.js +167 -0
- package/dist/install/setup.js.map +1 -0
- package/dist/locale/en.d.ts +3 -0
- package/dist/locale/en.d.ts.map +1 -0
- package/dist/locale/en.js +435 -0
- package/dist/locale/en.js.map +1 -0
- package/dist/locale/index.d.ts +28 -0
- package/dist/locale/index.d.ts.map +1 -0
- package/dist/locale/index.js +84 -0
- package/dist/locale/index.js.map +1 -0
- package/dist/locale/prompts/en.d.ts +3 -0
- package/dist/locale/prompts/en.d.ts.map +1 -0
- package/dist/locale/prompts/en.js +254 -0
- package/dist/locale/prompts/en.js.map +1 -0
- package/dist/locale/types.d.ts +433 -0
- package/dist/locale/types.d.ts.map +1 -0
- package/dist/locale/types.js +5 -0
- package/dist/locale/types.js.map +1 -0
- package/dist/mcp/server.d.ts +489 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +597 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/orchestration/decisionEngine.d.ts +175 -0
- package/dist/orchestration/decisionEngine.d.ts.map +1 -0
- package/dist/orchestration/decisionEngine.js +471 -0
- package/dist/orchestration/decisionEngine.js.map +1 -0
- package/dist/orchestration/index.d.ts +5 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +5 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/workItemParser.d.ts +67 -0
- package/dist/orchestration/workItemParser.d.ts.map +1 -0
- package/dist/orchestration/workItemParser.js +560 -0
- package/dist/orchestration/workItemParser.js.map +1 -0
- package/dist/orchestration/workItemScheduler.d.ts +141 -0
- package/dist/orchestration/workItemScheduler.d.ts.map +1 -0
- package/dist/orchestration/workItemScheduler.js +317 -0
- package/dist/orchestration/workItemScheduler.js.map +1 -0
- package/dist/orchestration/workflow.d.ts +145 -0
- package/dist/orchestration/workflow.d.ts.map +1 -0
- package/dist/orchestration/workflow.js +301 -0
- package/dist/orchestration/workflow.js.map +1 -0
- package/dist/providers/codexSessions.d.ts +93 -0
- package/dist/providers/codexSessions.d.ts.map +1 -0
- package/dist/providers/codexSessions.js +366 -0
- package/dist/providers/codexSessions.js.map +1 -0
- package/dist/registry/bsDetector.d.ts +24 -0
- package/dist/registry/bsDetector.d.ts.map +1 -0
- package/dist/registry/bsDetector.js +276 -0
- package/dist/registry/bsDetector.js.map +1 -0
- package/dist/registry/entityScanner.d.ts +36 -0
- package/dist/registry/entityScanner.d.ts.map +1 -0
- package/dist/registry/entityScanner.js +693 -0
- package/dist/registry/entityScanner.js.map +1 -0
- package/dist/registry/index.d.ts +9 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +13 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/schema.d.ts +307 -0
- package/dist/registry/schema.d.ts.map +1 -0
- package/dist/registry/schema.js +139 -0
- package/dist/registry/schema.js.map +1 -0
- package/dist/registry/sqliteStore.d.ts +101 -0
- package/dist/registry/sqliteStore.d.ts.map +1 -0
- package/dist/registry/sqliteStore.js +688 -0
- package/dist/registry/sqliteStore.js.map +1 -0
- package/dist/registry/workItemBridge.d.ts +8 -0
- package/dist/registry/workItemBridge.d.ts.map +1 -0
- package/dist/registry/workItemBridge.js +30 -0
- package/dist/registry/workItemBridge.js.map +1 -0
- package/dist/runners/cliRunner.d.ts +11 -0
- package/dist/runners/cliRunner.d.ts.map +1 -0
- package/dist/runners/cliRunner.js +193 -0
- package/dist/runners/cliRunner.js.map +1 -0
- package/dist/support/apiCache.d.ts +85 -0
- package/dist/support/apiCache.d.ts.map +1 -0
- package/dist/support/apiCache.js +163 -0
- package/dist/support/apiCache.js.map +1 -0
- package/dist/support/chat.d.ts +3 -0
- package/dist/support/chat.d.ts.map +1 -0
- package/dist/support/chat.js +305 -0
- package/dist/support/chat.js.map +1 -0
- package/dist/support/chatBackend.d.ts +25 -0
- package/dist/support/chatBackend.d.ts.map +1 -0
- package/dist/support/chatBackend.js +289 -0
- package/dist/support/chatBackend.js.map +1 -0
- package/dist/support/chatTui.d.ts +3 -0
- package/dist/support/chatTui.d.ts.map +1 -0
- package/dist/support/chatTui.js +1082 -0
- package/dist/support/chatTui.js.map +1 -0
- package/dist/support/costTracker.d.ts +29 -0
- package/dist/support/costTracker.d.ts.map +1 -0
- package/dist/support/costTracker.js +113 -0
- package/dist/support/costTracker.js.map +1 -0
- package/dist/support/dashboardHtml.d.ts +5 -0
- package/dist/support/dashboardHtml.d.ts.map +1 -0
- package/dist/support/dashboardHtml.js +2629 -0
- package/dist/support/dashboardHtml.js.map +1 -0
- package/dist/support/dev.d.ts +55 -0
- package/dist/support/dev.d.ts.map +1 -0
- package/dist/support/dev.js +298 -0
- package/dist/support/dev.js.map +1 -0
- package/dist/support/editParser.d.ts +37 -0
- package/dist/support/editParser.d.ts.map +1 -0
- package/dist/support/editParser.js +365 -0
- package/dist/support/editParser.js.map +1 -0
- package/dist/support/ghosttyThemeCatalog.generated.d.ts +2 -0
- package/dist/support/ghosttyThemeCatalog.generated.d.ts.map +1 -0
- package/dist/support/ghosttyThemeCatalog.generated.js +11116 -0
- package/dist/support/ghosttyThemeCatalog.generated.js.map +1 -0
- package/dist/support/gitStatus.d.ts +21 -0
- package/dist/support/gitStatus.d.ts.map +1 -0
- package/dist/support/gitStatus.js +108 -0
- package/dist/support/gitStatus.js.map +1 -0
- package/dist/support/gitTracker.d.ts +30 -0
- package/dist/support/gitTracker.d.ts.map +1 -0
- package/dist/support/gitTracker.js +143 -0
- package/dist/support/gitTracker.js.map +1 -0
- package/dist/support/index.d.ts +12 -0
- package/dist/support/index.d.ts.map +1 -0
- package/dist/support/index.js +12 -0
- package/dist/support/index.js.map +1 -0
- package/dist/support/planner.d.ts +64 -0
- package/dist/support/planner.d.ts.map +1 -0
- package/dist/support/planner.js +396 -0
- package/dist/support/planner.js.map +1 -0
- package/dist/support/projectMapper.d.ts +46 -0
- package/dist/support/projectMapper.d.ts.map +1 -0
- package/dist/support/projectMapper.js +273 -0
- package/dist/support/projectMapper.js.map +1 -0
- package/dist/support/pty-helper.py +117 -0
- package/dist/support/quotaTracker.d.ts +29 -0
- package/dist/support/quotaTracker.d.ts.map +1 -0
- package/dist/support/quotaTracker.js +89 -0
- package/dist/support/quotaTracker.js.map +1 -0
- package/dist/support/rateLimiter.d.ts +101 -0
- package/dist/support/rateLimiter.d.ts.map +1 -0
- package/dist/support/rateLimiter.js +219 -0
- package/dist/support/rateLimiter.js.map +1 -0
- package/dist/support/rollback.d.ts +61 -0
- package/dist/support/rollback.d.ts.map +1 -0
- package/dist/support/rollback.js +329 -0
- package/dist/support/rollback.js.map +1 -0
- package/dist/support/sharedShell.d.ts +17 -0
- package/dist/support/sharedShell.d.ts.map +1 -0
- package/dist/support/sharedShell.js +439 -0
- package/dist/support/sharedShell.js.map +1 -0
- package/dist/support/stuckDetector.d.ts +68 -0
- package/dist/support/stuckDetector.d.ts.map +1 -0
- package/dist/support/stuckDetector.js +174 -0
- package/dist/support/stuckDetector.js.map +1 -0
- package/dist/support/terminalBridge.d.ts +18 -0
- package/dist/support/terminalBridge.d.ts.map +1 -0
- package/dist/support/terminalBridge.js +553 -0
- package/dist/support/terminalBridge.js.map +1 -0
- package/dist/support/timeWindow.d.ts +60 -0
- package/dist/support/timeWindow.d.ts.map +1 -0
- package/dist/support/timeWindow.js +236 -0
- package/dist/support/timeWindow.js.map +1 -0
- package/dist/support/uiThemes.d.ts +44 -0
- package/dist/support/uiThemes.d.ts.map +1 -0
- package/dist/support/uiThemes.js +290 -0
- package/dist/support/uiThemes.js.map +1 -0
- package/dist/support/web.d.ts +29 -0
- package/dist/support/web.d.ts.map +1 -0
- package/dist/support/web.js +1097 -0
- package/dist/support/web.js.map +1 -0
- package/dist/support/worktreeManager.d.ts +20 -0
- package/dist/support/worktreeManager.d.ts.map +1 -0
- package/dist/support/worktreeManager.js +140 -0
- package/dist/support/worktreeManager.js.map +1 -0
- package/dist/task_state_model.py +55 -0
- package/dist/workItemState/store.d.ts +122 -0
- package/dist/workItemState/store.d.ts.map +1 -0
- package/dist/workItemState/store.js +438 -0
- package/dist/workItemState/store.js.map +1 -0
- package/dist/workItems/azdoBridge.d.ts +42 -0
- package/dist/workItems/azdoBridge.d.ts.map +1 -0
- package/dist/workItems/azdoBridge.js +143 -0
- package/dist/workItems/azdoBridge.js.map +1 -0
- package/dist/workItems/azdoSyncRuntime.d.ts +28 -0
- package/dist/workItems/azdoSyncRuntime.d.ts.map +1 -0
- package/dist/workItems/azdoSyncRuntime.js +158 -0
- package/dist/workItems/azdoSyncRuntime.js.map +1 -0
- package/dist/workItems/azureDevOpsSync.d.ts +128 -0
- package/dist/workItems/azureDevOpsSync.d.ts.map +1 -0
- package/dist/workItems/azureDevOpsSync.js +748 -0
- package/dist/workItems/azureDevOpsSync.js.map +1 -0
- package/dist/workItems/helpers.d.ts +11 -0
- package/dist/workItems/helpers.d.ts.map +1 -0
- package/dist/workItems/helpers.js +17 -0
- package/dist/workItems/helpers.js.map +1 -0
- package/dist/workItems/index.d.ts +21 -0
- package/dist/workItems/index.d.ts.map +1 -0
- package/dist/workItems/index.js +89 -0
- package/dist/workItems/index.js.map +1 -0
- package/dist/workItems/localWorkItemFetcher.d.ts +55 -0
- package/dist/workItems/localWorkItemFetcher.d.ts.map +1 -0
- package/dist/workItems/localWorkItemFetcher.js +209 -0
- package/dist/workItems/localWorkItemFetcher.js.map +1 -0
- package/dist/workItems/migrations/001_rename_workItem_to_work_item.sql +10 -0
- package/dist/workItems/postgresStore.d.ts +78 -0
- package/dist/workItems/postgresStore.d.ts.map +1 -0
- package/dist/workItems/postgresStore.js +937 -0
- package/dist/workItems/postgresStore.js.map +1 -0
- package/dist/workItems/schema.d.ts +257 -0
- package/dist/workItems/schema.d.ts.map +1 -0
- package/dist/workItems/schema.js +176 -0
- package/dist/workItems/schema.js.map +1 -0
- package/dist/workItems/sqliteStore.d.ts +124 -0
- package/dist/workItems/sqliteStore.d.ts.map +1 -0
- package/dist/workItems/sqliteStore.js +713 -0
- package/dist/workItems/sqliteStore.js.map +1 -0
- package/dist/workItems/workItemBoardHtml.d.ts +5 -0
- package/dist/workItems/workItemBoardHtml.d.ts.map +1 -0
- package/dist/workItems/workItemBoardHtml.js +2192 -0
- package/dist/workItems/workItemBoardHtml.js.map +1 -0
- package/package.json +99 -0
- package/templates/AGENTS.md +432 -0
- package/templates/BOOT.md +25 -0
- package/templates/BOOTSTRAP.md +50 -0
- package/templates/CHANGELOG_AUDIT.md +74 -0
- package/templates/HEARTBEAT.md +86 -0
- package/templates/IDENTITY.md +27 -0
- package/templates/PR_LAND.md +75 -0
- package/templates/PR_REVIEW.md +97 -0
- package/templates/SOUL.dev.md +52 -0
- package/templates/SOUL.md +81 -0
- package/templates/TOOLS.md +52 -0
- package/templates/USER.md +22 -0
- package/templates/WORKITEM_ANALYSIS.md +31 -0
- package/templates/agents/executor.md +26 -0
- package/templates/agents/plan.md +22 -0
- package/templates/agents/ralph.md +37 -0
- package/templates/agents/review.md +22 -0
- package/templates/agents/team.md +39 -0
|
@@ -0,0 +1,937 @@
|
|
|
1
|
+
// ============================================
|
|
2
|
+
// Enact Factory - PostgreSQL WorkItem Store
|
|
3
|
+
// Alternative to SQLite for multi-instance deployments
|
|
4
|
+
// ============================================
|
|
5
|
+
import { Pool } from 'pg';
|
|
6
|
+
import { nanoid } from 'nanoid';
|
|
7
|
+
export class PostgresWorkItemStore {
|
|
8
|
+
pool;
|
|
9
|
+
schema;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
const defaultPort = 45432;
|
|
12
|
+
const defaultDatabase = 'enact_factory_dev';
|
|
13
|
+
const poolConfig = config.connectionString
|
|
14
|
+
? { connectionString: config.connectionString }
|
|
15
|
+
: {
|
|
16
|
+
host: config.host ?? 'localhost',
|
|
17
|
+
port: config.port ?? defaultPort,
|
|
18
|
+
database: config.database ?? defaultDatabase,
|
|
19
|
+
user: config.user ?? 'postgres',
|
|
20
|
+
password: config.password ?? '',
|
|
21
|
+
max: config.maxConnections ?? 10,
|
|
22
|
+
};
|
|
23
|
+
this.pool = new Pool(poolConfig);
|
|
24
|
+
this.schema = config.schema ?? 'public';
|
|
25
|
+
// Handle pool errors
|
|
26
|
+
this.pool.on('error', (err) => {
|
|
27
|
+
console.error('[PostgresStore] Unexpected pool error:', err);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async init() {
|
|
31
|
+
await this.migrate();
|
|
32
|
+
}
|
|
33
|
+
async close() {
|
|
34
|
+
await this.pool.end();
|
|
35
|
+
}
|
|
36
|
+
async migrate() {
|
|
37
|
+
const client = await this.pool.connect();
|
|
38
|
+
try {
|
|
39
|
+
// Create schema if not exists
|
|
40
|
+
await client.query(`CREATE SCHEMA IF NOT EXISTS ${this.schema}`);
|
|
41
|
+
// Create workItems table
|
|
42
|
+
await client.query(`
|
|
43
|
+
CREATE TABLE IF NOT EXISTS ${this.schema}.work_items (
|
|
44
|
+
id TEXT PRIMARY KEY,
|
|
45
|
+
project_id TEXT NOT NULL,
|
|
46
|
+
title TEXT NOT NULL,
|
|
47
|
+
description TEXT DEFAULT '',
|
|
48
|
+
status TEXT,
|
|
49
|
+
priority TEXT,
|
|
50
|
+
source TEXT,
|
|
51
|
+
kind TEXT,
|
|
52
|
+
area TEXT,
|
|
53
|
+
review_state TEXT,
|
|
54
|
+
resolution TEXT,
|
|
55
|
+
assignee TEXT,
|
|
56
|
+
milestone TEXT,
|
|
57
|
+
estimate_minutes INTEGER,
|
|
58
|
+
complexity TEXT,
|
|
59
|
+
parent_id TEXT REFERENCES ${this.schema}.work_items(id) ON DELETE SET NULL,
|
|
60
|
+
azdo_id TEXT,
|
|
61
|
+
azdo_identifier TEXT,
|
|
62
|
+
azdo_url TEXT,
|
|
63
|
+
payload_json JSONB,
|
|
64
|
+
operator_session_id TEXT,
|
|
65
|
+
operator_lane TEXT,
|
|
66
|
+
is_session_root BOOLEAN DEFAULT FALSE,
|
|
67
|
+
external_work_item_id TEXT,
|
|
68
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
69
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
70
|
+
closed_at TIMESTAMPTZ
|
|
71
|
+
)
|
|
72
|
+
`);
|
|
73
|
+
// Add azdo columns if they don't exist (idempotent migration for existing schemas)
|
|
74
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ADD COLUMN IF NOT EXISTS azdo_id TEXT`);
|
|
75
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ADD COLUMN IF NOT EXISTS azdo_identifier TEXT`);
|
|
76
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ADD COLUMN IF NOT EXISTS azdo_url TEXT`);
|
|
77
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ADD COLUMN IF NOT EXISTS operator_session_id TEXT`);
|
|
78
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ADD COLUMN IF NOT EXISTS operator_lane TEXT`);
|
|
79
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ADD COLUMN IF NOT EXISTS is_session_root BOOLEAN DEFAULT FALSE`);
|
|
80
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ADD COLUMN IF NOT EXISTS external_work_item_id TEXT`);
|
|
81
|
+
// Drop content-field DEFAULTs on existing DBs so real Azure DevOps values (or NULL) persist
|
|
82
|
+
// instead of being silently replaced by fabricated literals. DROP DEFAULT is idempotent.
|
|
83
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ALTER COLUMN status DROP DEFAULT`);
|
|
84
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ALTER COLUMN priority DROP DEFAULT`);
|
|
85
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ALTER COLUMN source DROP DEFAULT`);
|
|
86
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ALTER COLUMN kind DROP DEFAULT`);
|
|
87
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ALTER COLUMN area DROP DEFAULT`);
|
|
88
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ALTER COLUMN review_state DROP DEFAULT`);
|
|
89
|
+
await client.query(`ALTER TABLE ${this.schema}.work_items ALTER COLUMN resolution DROP DEFAULT`);
|
|
90
|
+
// Create sync_meta KV table for sync watermarks
|
|
91
|
+
await client.query(`
|
|
92
|
+
CREATE TABLE IF NOT EXISTS ${this.schema}.sync_meta (
|
|
93
|
+
key TEXT PRIMARY KEY,
|
|
94
|
+
value TEXT NOT NULL,
|
|
95
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
96
|
+
)
|
|
97
|
+
`);
|
|
98
|
+
await client.query(`
|
|
99
|
+
CREATE TABLE IF NOT EXISTS ${this.schema}.projects (
|
|
100
|
+
name TEXT PRIMARY KEY,
|
|
101
|
+
path TEXT NOT NULL UNIQUE,
|
|
102
|
+
heartbeat_ms INTEGER NOT NULL,
|
|
103
|
+
azdo_label TEXT,
|
|
104
|
+
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|
105
|
+
paused BOOLEAN NOT NULL DEFAULT FALSE,
|
|
106
|
+
operators JSONB NOT NULL DEFAULT '[]'::jsonb
|
|
107
|
+
)
|
|
108
|
+
`);
|
|
109
|
+
// Create labels table
|
|
110
|
+
await client.query(`
|
|
111
|
+
CREATE TABLE IF NOT EXISTS ${this.schema}.labels (
|
|
112
|
+
id TEXT PRIMARY KEY,
|
|
113
|
+
name TEXT NOT NULL UNIQUE,
|
|
114
|
+
color TEXT DEFAULT '#6B7280',
|
|
115
|
+
description TEXT
|
|
116
|
+
)
|
|
117
|
+
`);
|
|
118
|
+
// Create work_item_labels junction table
|
|
119
|
+
await client.query(`
|
|
120
|
+
CREATE TABLE IF NOT EXISTS ${this.schema}.work_item_labels (
|
|
121
|
+
work_item_id TEXT NOT NULL REFERENCES ${this.schema}.work_items(id) ON DELETE CASCADE,
|
|
122
|
+
label_id TEXT NOT NULL REFERENCES ${this.schema}.labels(id) ON DELETE CASCADE,
|
|
123
|
+
PRIMARY KEY (work_item_id, label_id)
|
|
124
|
+
)
|
|
125
|
+
`);
|
|
126
|
+
// Create work_item_dependencies table
|
|
127
|
+
await client.query(`
|
|
128
|
+
CREATE TABLE IF NOT EXISTS ${this.schema}.work_item_dependencies (
|
|
129
|
+
work_item_id TEXT NOT NULL REFERENCES ${this.schema}.work_items(id) ON DELETE CASCADE,
|
|
130
|
+
depends_on_id TEXT NOT NULL REFERENCES ${this.schema}.work_items(id) ON DELETE CASCADE,
|
|
131
|
+
PRIMARY KEY (work_item_id, depends_on_id)
|
|
132
|
+
)
|
|
133
|
+
`);
|
|
134
|
+
// Create work_item_relevant_files table
|
|
135
|
+
await client.query(`
|
|
136
|
+
CREATE TABLE IF NOT EXISTS ${this.schema}.work_item_relevant_files (
|
|
137
|
+
work_item_id TEXT NOT NULL REFERENCES ${this.schema}.work_items(id) ON DELETE CASCADE,
|
|
138
|
+
file_path TEXT NOT NULL,
|
|
139
|
+
PRIMARY KEY (work_item_id, file_path)
|
|
140
|
+
)
|
|
141
|
+
`);
|
|
142
|
+
// Create work_item_acceptance_criteria table
|
|
143
|
+
await client.query(`
|
|
144
|
+
CREATE TABLE IF NOT EXISTS ${this.schema}.work_item_acceptance_criteria (
|
|
145
|
+
work_item_id TEXT NOT NULL REFERENCES ${this.schema}.work_items(id) ON DELETE CASCADE,
|
|
146
|
+
criterion TEXT NOT NULL,
|
|
147
|
+
sort_order INTEGER DEFAULT 0
|
|
148
|
+
)
|
|
149
|
+
`);
|
|
150
|
+
// Create work_item_memory_links table
|
|
151
|
+
await client.query(`
|
|
152
|
+
CREATE TABLE IF NOT EXISTS ${this.schema}.work_item_memory_links (
|
|
153
|
+
work_item_id TEXT NOT NULL REFERENCES ${this.schema}.work_items(id) ON DELETE CASCADE,
|
|
154
|
+
memory_id TEXT NOT NULL,
|
|
155
|
+
linked_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
156
|
+
PRIMARY KEY (work_item_id, memory_id)
|
|
157
|
+
)
|
|
158
|
+
`);
|
|
159
|
+
// Create work_item_events table
|
|
160
|
+
await client.query(`
|
|
161
|
+
CREATE TABLE IF NOT EXISTS ${this.schema}.work_item_events (
|
|
162
|
+
id TEXT PRIMARY KEY,
|
|
163
|
+
work_item_id TEXT NOT NULL REFERENCES ${this.schema}.work_items(id) ON DELETE CASCADE,
|
|
164
|
+
type TEXT NOT NULL,
|
|
165
|
+
old_value TEXT,
|
|
166
|
+
new_value TEXT,
|
|
167
|
+
content TEXT,
|
|
168
|
+
memory_id TEXT,
|
|
169
|
+
actor TEXT DEFAULT 'system',
|
|
170
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
171
|
+
)
|
|
172
|
+
`);
|
|
173
|
+
// Create milestones table
|
|
174
|
+
await client.query(`
|
|
175
|
+
CREATE TABLE IF NOT EXISTS ${this.schema}.milestones (
|
|
176
|
+
id TEXT PRIMARY KEY,
|
|
177
|
+
name TEXT NOT NULL,
|
|
178
|
+
description TEXT,
|
|
179
|
+
due_date TIMESTAMPTZ,
|
|
180
|
+
status TEXT DEFAULT 'active',
|
|
181
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
182
|
+
)
|
|
183
|
+
`);
|
|
184
|
+
// Create indexes
|
|
185
|
+
await client.query(`CREATE INDEX IF NOT EXISTS idx_work_items_project ON ${this.schema}.work_items(project_id)`);
|
|
186
|
+
await client.query(`CREATE INDEX IF NOT EXISTS idx_work_items_status ON ${this.schema}.work_items(status)`);
|
|
187
|
+
await client.query(`CREATE INDEX IF NOT EXISTS idx_work_items_priority ON ${this.schema}.work_items(priority)`);
|
|
188
|
+
await client.query(`CREATE INDEX IF NOT EXISTS idx_work_items_parent ON ${this.schema}.work_items(parent_id)`);
|
|
189
|
+
await client.query(`CREATE INDEX IF NOT EXISTS idx_work_items_azdo ON ${this.schema}.work_items(azdo_id)`);
|
|
190
|
+
await client.query(`CREATE INDEX IF NOT EXISTS idx_work_item_events_item ON ${this.schema}.work_item_events(work_item_id)`);
|
|
191
|
+
await client.query(`CREATE INDEX IF NOT EXISTS idx_work_item_events_created ON ${this.schema}.work_item_events(created_at)`);
|
|
192
|
+
// Create full-text search index (using tsvector for Postgres)
|
|
193
|
+
await client.query(`
|
|
194
|
+
CREATE INDEX IF NOT EXISTS idx_work_items_fts ON ${this.schema}.work_items
|
|
195
|
+
USING gin(to_tsvector('english', title || ' ' || COALESCE(description, '')))
|
|
196
|
+
`);
|
|
197
|
+
// Drop the legacy updated_at auto-update trigger. It force-overwrote updated_at = NOW()
|
|
198
|
+
// on every UPDATE, which made persisting a real System.ChangedDate impossible.
|
|
199
|
+
// updated_at is now written explicitly by each write path.
|
|
200
|
+
await client.query(`DROP TRIGGER IF EXISTS update_work_items_updated_at ON ${this.schema}.work_items`);
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
client.release();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// ============ WorkItem CRUD ============
|
|
207
|
+
async createWorkItem(input) {
|
|
208
|
+
const id = input.id ?? nanoid(12);
|
|
209
|
+
const now = new Date().toISOString();
|
|
210
|
+
const workItem = {
|
|
211
|
+
id,
|
|
212
|
+
projectId: input.projectId,
|
|
213
|
+
title: input.title,
|
|
214
|
+
description: input.description ?? '',
|
|
215
|
+
// No content-field fabrication: the caller's value (or undefined → SQL NULL) passes
|
|
216
|
+
// straight through. WorkItemRecord types these as required, so we assert here; a missing
|
|
217
|
+
// value surfaces as NULL in the DB and fails loudly at any call site that assumes a value.
|
|
218
|
+
status: input.status,
|
|
219
|
+
priority: input.priority,
|
|
220
|
+
source: input.source,
|
|
221
|
+
kind: input.kind,
|
|
222
|
+
area: input.area,
|
|
223
|
+
reviewState: input.reviewState,
|
|
224
|
+
resolution: input.resolution,
|
|
225
|
+
assignee: input.assignee ?? undefined,
|
|
226
|
+
milestone: input.milestone,
|
|
227
|
+
labels: input.labels ?? [],
|
|
228
|
+
dependencies: input.dependencies ?? [],
|
|
229
|
+
relevantFiles: input.relevantFiles ?? [],
|
|
230
|
+
acceptanceCriteria: input.acceptanceCriteria ?? [],
|
|
231
|
+
estimateMinutes: input.estimateMinutes,
|
|
232
|
+
complexity: input.complexity,
|
|
233
|
+
parentId: input.parentId,
|
|
234
|
+
azdoId: input.azdoId,
|
|
235
|
+
azdoIdentifier: input.azdoIdentifier,
|
|
236
|
+
azdoUrl: input.azdoUrl,
|
|
237
|
+
memoryIds: [],
|
|
238
|
+
childIds: [],
|
|
239
|
+
operatorLane: input.operatorLane,
|
|
240
|
+
isSessionRoot: input.isSessionRoot ?? false,
|
|
241
|
+
externalWorkItemId: input.externalWorkItemId,
|
|
242
|
+
createdAt: input.createdAt ?? now,
|
|
243
|
+
updatedAt: input.updatedAt ?? now,
|
|
244
|
+
closedAt: input.closedAt ?? undefined,
|
|
245
|
+
};
|
|
246
|
+
await this.createWorkItemAsync(workItem, input);
|
|
247
|
+
return workItem;
|
|
248
|
+
}
|
|
249
|
+
async createWorkItemAsync(workItem, input) {
|
|
250
|
+
const client = await this.pool.connect();
|
|
251
|
+
try {
|
|
252
|
+
await client.query('BEGIN');
|
|
253
|
+
// Insert workItem
|
|
254
|
+
await client.query(`
|
|
255
|
+
INSERT INTO ${this.schema}.work_items (id, project_id, title, description, status, priority, source,
|
|
256
|
+
kind, area, review_state, resolution, assignee, milestone, estimate_minutes, complexity,
|
|
257
|
+
parent_id, azdo_id, azdo_identifier, azdo_url,
|
|
258
|
+
operator_lane, is_session_root, external_work_item_id,
|
|
259
|
+
created_at, updated_at, closed_at)
|
|
260
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25)
|
|
261
|
+
`, [
|
|
262
|
+
workItem.id, workItem.projectId, workItem.title, workItem.description, workItem.status ?? null,
|
|
263
|
+
workItem.priority ?? null, workItem.source ?? null, workItem.kind ?? null, workItem.area ?? null,
|
|
264
|
+
workItem.reviewState ?? null, workItem.resolution ?? null, workItem.assignee, workItem.milestone,
|
|
265
|
+
workItem.estimateMinutes, workItem.complexity, workItem.parentId, workItem.azdoId, workItem.azdoIdentifier, workItem.azdoUrl,
|
|
266
|
+
workItem.operatorLane ?? null,
|
|
267
|
+
workItem.isSessionRoot ?? false,
|
|
268
|
+
workItem.externalWorkItemId ?? null,
|
|
269
|
+
workItem.createdAt, workItem.updatedAt, workItem.closedAt ?? null,
|
|
270
|
+
]);
|
|
271
|
+
// Insert labels
|
|
272
|
+
if (input.labels?.length) {
|
|
273
|
+
for (const labelId of input.labels) {
|
|
274
|
+
await client.query(`
|
|
275
|
+
INSERT INTO ${this.schema}.work_item_labels (work_item_id, label_id)
|
|
276
|
+
VALUES ($1, $2)
|
|
277
|
+
ON CONFLICT DO NOTHING
|
|
278
|
+
`, [workItem.id, labelId]);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// Insert dependencies
|
|
282
|
+
if (input.dependencies?.length) {
|
|
283
|
+
for (const depId of input.dependencies) {
|
|
284
|
+
await client.query(`
|
|
285
|
+
INSERT INTO ${this.schema}.work_item_dependencies (work_item_id, depends_on_id)
|
|
286
|
+
VALUES ($1, $2)
|
|
287
|
+
ON CONFLICT DO NOTHING
|
|
288
|
+
`, [workItem.id, depId]);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// Insert relevant files
|
|
292
|
+
if (input.relevantFiles?.length) {
|
|
293
|
+
for (const file of input.relevantFiles) {
|
|
294
|
+
await client.query(`
|
|
295
|
+
INSERT INTO ${this.schema}.work_item_relevant_files (work_item_id, file_path)
|
|
296
|
+
VALUES ($1, $2)
|
|
297
|
+
ON CONFLICT DO NOTHING
|
|
298
|
+
`, [workItem.id, file]);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Insert acceptance criteria
|
|
302
|
+
if (input.acceptanceCriteria?.length) {
|
|
303
|
+
for (const [idx, criterion] of input.acceptanceCriteria.entries()) {
|
|
304
|
+
await client.query(`
|
|
305
|
+
INSERT INTO ${this.schema}.work_item_acceptance_criteria (work_item_id, criterion, sort_order)
|
|
306
|
+
VALUES ($1, $2, $3)
|
|
307
|
+
`, [workItem.id, criterion, idx]);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
await client.query('COMMIT');
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
await client.query('ROLLBACK');
|
|
314
|
+
throw err;
|
|
315
|
+
}
|
|
316
|
+
finally {
|
|
317
|
+
client.release();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async getWorkItem(id) {
|
|
321
|
+
return this.getWorkItemAsync(id);
|
|
322
|
+
}
|
|
323
|
+
async getWorkItemAsync(id) {
|
|
324
|
+
const result = await this.pool.query(`
|
|
325
|
+
SELECT * FROM ${this.schema}.work_items WHERE id = $1
|
|
326
|
+
`, [id]);
|
|
327
|
+
if (result.rows.length === 0)
|
|
328
|
+
return null;
|
|
329
|
+
const row = result.rows[0];
|
|
330
|
+
return this.rowToWorkItem(row);
|
|
331
|
+
}
|
|
332
|
+
async updateWorkItem(id, patch) {
|
|
333
|
+
return this.updateWorkItemAsync(id, patch);
|
|
334
|
+
}
|
|
335
|
+
async updateWorkItemAsync(id, patch) {
|
|
336
|
+
const client = await this.pool.connect();
|
|
337
|
+
try {
|
|
338
|
+
await client.query('BEGIN');
|
|
339
|
+
// Build update query dynamically
|
|
340
|
+
const updates = [];
|
|
341
|
+
const values = [];
|
|
342
|
+
let paramIdx = 1;
|
|
343
|
+
if (patch.title !== undefined) {
|
|
344
|
+
updates.push(`title = $${paramIdx++}`);
|
|
345
|
+
values.push(patch.title);
|
|
346
|
+
}
|
|
347
|
+
if (patch.description !== undefined) {
|
|
348
|
+
updates.push(`description = $${paramIdx++}`);
|
|
349
|
+
values.push(patch.description);
|
|
350
|
+
}
|
|
351
|
+
if (patch.status !== undefined) {
|
|
352
|
+
updates.push(`status = $${paramIdx++}`);
|
|
353
|
+
values.push(patch.status);
|
|
354
|
+
}
|
|
355
|
+
if (patch.priority !== undefined) {
|
|
356
|
+
updates.push(`priority = $${paramIdx++}`);
|
|
357
|
+
values.push(patch.priority);
|
|
358
|
+
}
|
|
359
|
+
if (patch.source !== undefined) {
|
|
360
|
+
updates.push(`source = $${paramIdx++}`);
|
|
361
|
+
values.push(patch.source);
|
|
362
|
+
}
|
|
363
|
+
if (patch.kind !== undefined) {
|
|
364
|
+
updates.push(`kind = $${paramIdx++}`);
|
|
365
|
+
values.push(patch.kind);
|
|
366
|
+
}
|
|
367
|
+
if (patch.area !== undefined) {
|
|
368
|
+
updates.push(`area = $${paramIdx++}`);
|
|
369
|
+
values.push(patch.area);
|
|
370
|
+
}
|
|
371
|
+
if (patch.reviewState !== undefined) {
|
|
372
|
+
updates.push(`review_state = $${paramIdx++}`);
|
|
373
|
+
values.push(patch.reviewState);
|
|
374
|
+
}
|
|
375
|
+
if (patch.resolution !== undefined) {
|
|
376
|
+
updates.push(`resolution = $${paramIdx++}`);
|
|
377
|
+
values.push(patch.resolution);
|
|
378
|
+
}
|
|
379
|
+
if (patch.assignee !== undefined) {
|
|
380
|
+
updates.push(`assignee = $${paramIdx++}`);
|
|
381
|
+
values.push(patch.assignee);
|
|
382
|
+
}
|
|
383
|
+
if (patch.milestone !== undefined) {
|
|
384
|
+
updates.push(`milestone = $${paramIdx++}`);
|
|
385
|
+
values.push(patch.milestone);
|
|
386
|
+
}
|
|
387
|
+
if (patch.estimateMinutes !== undefined) {
|
|
388
|
+
updates.push(`estimate_minutes = $${paramIdx++}`);
|
|
389
|
+
values.push(patch.estimateMinutes);
|
|
390
|
+
}
|
|
391
|
+
if (patch.complexity !== undefined) {
|
|
392
|
+
updates.push(`complexity = $${paramIdx++}`);
|
|
393
|
+
values.push(patch.complexity);
|
|
394
|
+
}
|
|
395
|
+
if (patch.parentId !== undefined) {
|
|
396
|
+
updates.push(`parent_id = $${paramIdx++}`);
|
|
397
|
+
values.push(patch.parentId);
|
|
398
|
+
}
|
|
399
|
+
if (patch.operatorLane !== undefined) {
|
|
400
|
+
updates.push(`operator_lane = $${paramIdx++}`);
|
|
401
|
+
values.push(patch.operatorLane);
|
|
402
|
+
}
|
|
403
|
+
if (patch.isSessionRoot !== undefined) {
|
|
404
|
+
updates.push(`is_session_root = $${paramIdx++}`);
|
|
405
|
+
values.push(patch.isSessionRoot);
|
|
406
|
+
}
|
|
407
|
+
if (patch.externalWorkItemId !== undefined) {
|
|
408
|
+
updates.push(`external_work_item_id = $${paramIdx++}`);
|
|
409
|
+
values.push(patch.externalWorkItemId);
|
|
410
|
+
}
|
|
411
|
+
if (patch.createdAt !== undefined) {
|
|
412
|
+
updates.push(`created_at = $${paramIdx++}`);
|
|
413
|
+
values.push(patch.createdAt);
|
|
414
|
+
}
|
|
415
|
+
if (patch.closedAt !== undefined) {
|
|
416
|
+
updates.push(`closed_at = $${paramIdx++}`);
|
|
417
|
+
values.push(patch.closedAt);
|
|
418
|
+
}
|
|
419
|
+
// The legacy trigger that auto-bumped updated_at is gone, so write it explicitly here.
|
|
420
|
+
// A caller-supplied updatedAt (e.g. a real System.ChangedDate from sync) wins; otherwise
|
|
421
|
+
// a normal local edit bumps to NOW(). updated_at is always written on update.
|
|
422
|
+
if (patch.updatedAt !== undefined) {
|
|
423
|
+
updates.push(`updated_at = $${paramIdx++}`);
|
|
424
|
+
values.push(patch.updatedAt);
|
|
425
|
+
}
|
|
426
|
+
else {
|
|
427
|
+
updates.push(`updated_at = NOW()`);
|
|
428
|
+
}
|
|
429
|
+
if (updates.length > 0) {
|
|
430
|
+
values.push(id);
|
|
431
|
+
await client.query(`
|
|
432
|
+
UPDATE ${this.schema}.work_items
|
|
433
|
+
SET ${updates.join(', ')}
|
|
434
|
+
WHERE id = $${paramIdx}
|
|
435
|
+
`, values);
|
|
436
|
+
}
|
|
437
|
+
await client.query('COMMIT');
|
|
438
|
+
return this.getWorkItemAsync(id);
|
|
439
|
+
}
|
|
440
|
+
catch (err) {
|
|
441
|
+
await client.query('ROLLBACK');
|
|
442
|
+
throw err;
|
|
443
|
+
}
|
|
444
|
+
finally {
|
|
445
|
+
client.release();
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
async deleteWorkItem(id) {
|
|
449
|
+
return this.deleteWorkItemAsync(id);
|
|
450
|
+
}
|
|
451
|
+
async deleteWorkItemAsync(id) {
|
|
452
|
+
const result = await this.pool.query(`
|
|
453
|
+
DELETE FROM ${this.schema}.work_items WHERE id = $1
|
|
454
|
+
`, [id]);
|
|
455
|
+
return (result.rowCount ?? 0) > 0;
|
|
456
|
+
}
|
|
457
|
+
async listWorkItems(filter) {
|
|
458
|
+
return this.listWorkItemsAsync(filter);
|
|
459
|
+
}
|
|
460
|
+
async listWorkItemsAsync(filter) {
|
|
461
|
+
const where = ['1=1'];
|
|
462
|
+
const params = [];
|
|
463
|
+
let paramIdx = 1;
|
|
464
|
+
if (filter?.projectId) {
|
|
465
|
+
where.push(`project_id = $${paramIdx++}`);
|
|
466
|
+
params.push(filter.projectId);
|
|
467
|
+
}
|
|
468
|
+
if (filter?.status?.length) {
|
|
469
|
+
where.push(`status = ANY($${paramIdx++})`);
|
|
470
|
+
params.push(filter.status);
|
|
471
|
+
}
|
|
472
|
+
if (filter?.priority?.length) {
|
|
473
|
+
where.push(`priority = ANY($${paramIdx++})`);
|
|
474
|
+
params.push(filter.priority);
|
|
475
|
+
}
|
|
476
|
+
if (filter?.assignee) {
|
|
477
|
+
where.push(`assignee = $${paramIdx++}`);
|
|
478
|
+
params.push(filter.assignee);
|
|
479
|
+
}
|
|
480
|
+
if (filter?.source) {
|
|
481
|
+
where.push(`source = $${paramIdx++}`);
|
|
482
|
+
params.push(filter.source);
|
|
483
|
+
}
|
|
484
|
+
if (filter?.search) {
|
|
485
|
+
where.push(`(
|
|
486
|
+
to_tsvector('english', title || ' ' || COALESCE(description, '')) @@ plainto_tsquery('english', $${paramIdx++})
|
|
487
|
+
OR title ILIKE $${paramIdx++}
|
|
488
|
+
)`);
|
|
489
|
+
params.push(filter.search, `%${filter.search}%`);
|
|
490
|
+
}
|
|
491
|
+
const limit = filter?.limit ?? 50;
|
|
492
|
+
const offset = filter?.offset ?? 0;
|
|
493
|
+
// Get total count
|
|
494
|
+
const countResult = await this.pool.query(`
|
|
495
|
+
SELECT COUNT(*) as total FROM ${this.schema}.work_items WHERE ${where.join(' AND ')}
|
|
496
|
+
`, params);
|
|
497
|
+
const total = parseInt(countResult.rows[0].total, 10);
|
|
498
|
+
// Get workItems
|
|
499
|
+
const result = await this.pool.query(`
|
|
500
|
+
SELECT * FROM ${this.schema}.work_items
|
|
501
|
+
WHERE ${where.join(' AND ')}
|
|
502
|
+
ORDER BY created_at DESC
|
|
503
|
+
LIMIT $${paramIdx++} OFFSET $${paramIdx++}
|
|
504
|
+
`, [...params, limit, offset]);
|
|
505
|
+
const workItems = await Promise.all(result.rows.map((row) => this.loadWorkItemDetails(row)));
|
|
506
|
+
return { workItems, total };
|
|
507
|
+
}
|
|
508
|
+
async loadWorkItemDetails(row) {
|
|
509
|
+
const client = await this.pool.connect();
|
|
510
|
+
try {
|
|
511
|
+
const workItem = this.rowToWorkItem(row);
|
|
512
|
+
// Load labels
|
|
513
|
+
const labelsResult = await client.query(`
|
|
514
|
+
SELECT l.name FROM ${this.schema}.labels l
|
|
515
|
+
JOIN ${this.schema}.work_item_labels il ON l.id = il.label_id
|
|
516
|
+
WHERE il.work_item_id = $1
|
|
517
|
+
`, [workItem.id]);
|
|
518
|
+
workItem.labels = labelsResult.rows.map((r) => r.name);
|
|
519
|
+
// Load dependencies
|
|
520
|
+
const depsResult = await client.query(`
|
|
521
|
+
SELECT depends_on_id FROM ${this.schema}.work_item_dependencies WHERE work_item_id = $1
|
|
522
|
+
`, [workItem.id]);
|
|
523
|
+
workItem.dependencies = depsResult.rows.map((r) => r.depends_on_id);
|
|
524
|
+
// Load relevant files
|
|
525
|
+
const filesResult = await client.query(`
|
|
526
|
+
SELECT file_path FROM ${this.schema}.work_item_relevant_files WHERE work_item_id = $1
|
|
527
|
+
`, [workItem.id]);
|
|
528
|
+
workItem.relevantFiles = filesResult.rows.map((r) => r.file_path);
|
|
529
|
+
// Load acceptance criteria
|
|
530
|
+
const acResult = await client.query(`
|
|
531
|
+
SELECT criterion FROM ${this.schema}.work_item_acceptance_criteria
|
|
532
|
+
WHERE work_item_id = $1 ORDER BY sort_order
|
|
533
|
+
`, [workItem.id]);
|
|
534
|
+
workItem.acceptanceCriteria = acResult.rows.map((r) => r.criterion);
|
|
535
|
+
// Load memory links
|
|
536
|
+
const memResult = await client.query(`
|
|
537
|
+
SELECT memory_id FROM ${this.schema}.work_item_memory_links WHERE work_item_id = $1
|
|
538
|
+
`, [workItem.id]);
|
|
539
|
+
workItem.memoryIds = memResult.rows.map((r) => r.memory_id);
|
|
540
|
+
return workItem;
|
|
541
|
+
}
|
|
542
|
+
finally {
|
|
543
|
+
client.release();
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
rowToWorkItem(row) {
|
|
547
|
+
return {
|
|
548
|
+
id: row.id,
|
|
549
|
+
projectId: row.project_id,
|
|
550
|
+
title: row.title,
|
|
551
|
+
description: row.description ?? '',
|
|
552
|
+
status: row.status,
|
|
553
|
+
priority: row.priority,
|
|
554
|
+
source: row.source,
|
|
555
|
+
kind: row.kind ?? undefined,
|
|
556
|
+
area: row.area ?? undefined,
|
|
557
|
+
reviewState: row.review_state ?? undefined,
|
|
558
|
+
resolution: row.resolution ?? undefined,
|
|
559
|
+
labels: [],
|
|
560
|
+
assignee: row.assignee ?? undefined,
|
|
561
|
+
milestone: row.milestone ?? undefined,
|
|
562
|
+
relevantFiles: [],
|
|
563
|
+
acceptanceCriteria: [],
|
|
564
|
+
estimateMinutes: row.estimate_minutes ?? undefined,
|
|
565
|
+
complexity: row.complexity ?? undefined,
|
|
566
|
+
dependencies: [],
|
|
567
|
+
parentId: row.parent_id ?? undefined,
|
|
568
|
+
childIds: [],
|
|
569
|
+
azdoId: row.azdo_id ?? undefined,
|
|
570
|
+
azdoIdentifier: row.azdo_identifier ?? undefined,
|
|
571
|
+
azdoUrl: row.azdo_url ?? undefined,
|
|
572
|
+
operatorSessionId: row.operator_session_id ?? undefined,
|
|
573
|
+
operatorLane: row.operator_lane ?? undefined,
|
|
574
|
+
isSessionRoot: row.is_session_root === true || row.is_session_root === 't' || row.is_session_root === 1,
|
|
575
|
+
externalWorkItemId: row.external_work_item_id ?? undefined,
|
|
576
|
+
memoryIds: [],
|
|
577
|
+
createdAt: row.created_at instanceof Date
|
|
578
|
+
? row.created_at.toISOString()
|
|
579
|
+
: row.created_at,
|
|
580
|
+
updatedAt: row.updated_at instanceof Date
|
|
581
|
+
? row.updated_at.toISOString()
|
|
582
|
+
: row.updated_at,
|
|
583
|
+
closedAt: row.closed_at instanceof Date
|
|
584
|
+
? row.closed_at.toISOString()
|
|
585
|
+
: (row.closed_at ?? undefined),
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
// ============ Status Changes ============
|
|
589
|
+
async changeStatus(id, status, actor) {
|
|
590
|
+
return this.changeStatusAsync(id, status, actor);
|
|
591
|
+
}
|
|
592
|
+
async changeStatusAsync(id, status, actor) {
|
|
593
|
+
const closedAt = status === 'done' || status === 'cancelled' ? new Date().toISOString() : null;
|
|
594
|
+
await this.pool.query(`
|
|
595
|
+
UPDATE ${this.schema}.work_items
|
|
596
|
+
SET status = $1, closed_at = $2, updated_at = NOW()
|
|
597
|
+
WHERE id = $3
|
|
598
|
+
`, [status, closedAt, id]);
|
|
599
|
+
// Add event
|
|
600
|
+
await this.addEvent(id, 'status_changed', {
|
|
601
|
+
newValue: status,
|
|
602
|
+
actor,
|
|
603
|
+
});
|
|
604
|
+
return this.getWorkItemAsync(id);
|
|
605
|
+
}
|
|
606
|
+
// ============ Events ============
|
|
607
|
+
async addEvent(workItemId, type, data) {
|
|
608
|
+
const event = {
|
|
609
|
+
id: nanoid(12),
|
|
610
|
+
workItemId,
|
|
611
|
+
type,
|
|
612
|
+
oldValue: data?.oldValue,
|
|
613
|
+
newValue: data?.newValue,
|
|
614
|
+
content: data?.content,
|
|
615
|
+
memoryId: data?.memoryId,
|
|
616
|
+
actor: data?.actor ?? 'system',
|
|
617
|
+
createdAt: new Date().toISOString(),
|
|
618
|
+
};
|
|
619
|
+
await this.addEventAsync(event);
|
|
620
|
+
return event;
|
|
621
|
+
}
|
|
622
|
+
async addEventAsync(event) {
|
|
623
|
+
await this.pool.query(`
|
|
624
|
+
INSERT INTO ${this.schema}.work_item_events (id, work_item_id, type, old_value, new_value, content, memory_id, actor, created_at)
|
|
625
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
626
|
+
`, [
|
|
627
|
+
event.id, event.workItemId, event.type, event.oldValue, event.newValue,
|
|
628
|
+
event.content, event.memoryId, event.actor, event.createdAt,
|
|
629
|
+
]);
|
|
630
|
+
}
|
|
631
|
+
async getEvents(workItemId, limit) {
|
|
632
|
+
return this.getEventsAsync(workItemId, limit);
|
|
633
|
+
}
|
|
634
|
+
async getEventsAsync(workItemId, limit) {
|
|
635
|
+
const result = await this.pool.query(`
|
|
636
|
+
SELECT * FROM ${this.schema}.work_item_events
|
|
637
|
+
WHERE work_item_id = $1
|
|
638
|
+
ORDER BY created_at DESC
|
|
639
|
+
LIMIT $2
|
|
640
|
+
`, [workItemId, limit ?? 50]);
|
|
641
|
+
return result.rows.map((row) => ({
|
|
642
|
+
id: row.id,
|
|
643
|
+
workItemId: row.work_item_id,
|
|
644
|
+
type: row.type,
|
|
645
|
+
oldValue: row.old_value ?? undefined,
|
|
646
|
+
newValue: row.new_value ?? undefined,
|
|
647
|
+
content: row.content ?? undefined,
|
|
648
|
+
memoryId: row.memory_id ?? undefined,
|
|
649
|
+
actor: row.actor,
|
|
650
|
+
createdAt: row.created_at instanceof Date
|
|
651
|
+
? row.created_at.toISOString()
|
|
652
|
+
: row.created_at,
|
|
653
|
+
}));
|
|
654
|
+
}
|
|
655
|
+
async getRecentEvents(limit) {
|
|
656
|
+
return this.getRecentEventsAsync(limit);
|
|
657
|
+
}
|
|
658
|
+
async getRecentEventsAsync(limit) {
|
|
659
|
+
const result = await this.pool.query(`
|
|
660
|
+
SELECT * FROM ${this.schema}.work_item_events
|
|
661
|
+
ORDER BY created_at DESC
|
|
662
|
+
LIMIT $1
|
|
663
|
+
`, [limit ?? 50]);
|
|
664
|
+
return result.rows.map((row) => ({
|
|
665
|
+
id: row.id,
|
|
666
|
+
workItemId: row.work_item_id,
|
|
667
|
+
type: row.type,
|
|
668
|
+
oldValue: row.old_value ?? undefined,
|
|
669
|
+
newValue: row.new_value ?? undefined,
|
|
670
|
+
content: row.content ?? undefined,
|
|
671
|
+
memoryId: row.memory_id ?? undefined,
|
|
672
|
+
actor: row.actor,
|
|
673
|
+
createdAt: row.created_at instanceof Date
|
|
674
|
+
? row.created_at.toISOString()
|
|
675
|
+
: row.created_at,
|
|
676
|
+
}));
|
|
677
|
+
}
|
|
678
|
+
// ============ Labels ============
|
|
679
|
+
async createLabel(name, color, description) {
|
|
680
|
+
const label = {
|
|
681
|
+
id: nanoid(12),
|
|
682
|
+
name,
|
|
683
|
+
color: color ?? '#6B7280',
|
|
684
|
+
description,
|
|
685
|
+
};
|
|
686
|
+
await this.createLabelAsync(label);
|
|
687
|
+
return label;
|
|
688
|
+
}
|
|
689
|
+
async createLabelAsync(label) {
|
|
690
|
+
await this.pool.query(`
|
|
691
|
+
INSERT INTO ${this.schema}.labels (id, name, color, description)
|
|
692
|
+
VALUES ($1, $2, $3, $4)
|
|
693
|
+
ON CONFLICT (name) DO NOTHING
|
|
694
|
+
`, [label.id, label.name, label.color, label.description]);
|
|
695
|
+
}
|
|
696
|
+
async listLabels() {
|
|
697
|
+
return this.listLabelsAsync();
|
|
698
|
+
}
|
|
699
|
+
async listLabelsAsync() {
|
|
700
|
+
const result = await this.pool.query(`SELECT * FROM ${this.schema}.labels`);
|
|
701
|
+
return result.rows.map((row) => ({
|
|
702
|
+
id: row.id,
|
|
703
|
+
name: row.name,
|
|
704
|
+
color: row.color,
|
|
705
|
+
description: row.description ?? undefined,
|
|
706
|
+
}));
|
|
707
|
+
}
|
|
708
|
+
async deleteLabel(id) {
|
|
709
|
+
return this.deleteLabelAsync(id);
|
|
710
|
+
}
|
|
711
|
+
async deleteLabelAsync(id) {
|
|
712
|
+
const result = await this.pool.query(`
|
|
713
|
+
DELETE FROM ${this.schema}.labels WHERE id = $1
|
|
714
|
+
`, [id]);
|
|
715
|
+
return (result.rowCount ?? 0) > 0;
|
|
716
|
+
}
|
|
717
|
+
// ============ Milestones ============
|
|
718
|
+
async createMilestone(name, description, dueDate) {
|
|
719
|
+
const milestone = {
|
|
720
|
+
id: nanoid(12),
|
|
721
|
+
name,
|
|
722
|
+
description,
|
|
723
|
+
dueDate,
|
|
724
|
+
status: 'active',
|
|
725
|
+
createdAt: new Date().toISOString(),
|
|
726
|
+
};
|
|
727
|
+
await this.createMilestoneAsync(milestone);
|
|
728
|
+
return milestone;
|
|
729
|
+
}
|
|
730
|
+
async createMilestoneAsync(milestone) {
|
|
731
|
+
await this.pool.query(`
|
|
732
|
+
INSERT INTO ${this.schema}.milestones (id, name, description, due_date, status, created_at)
|
|
733
|
+
VALUES ($1, $2, $3, $4, $5, $6)
|
|
734
|
+
`, [
|
|
735
|
+
milestone.id, milestone.name, milestone.description,
|
|
736
|
+
milestone.dueDate, milestone.status, milestone.createdAt,
|
|
737
|
+
]);
|
|
738
|
+
}
|
|
739
|
+
async listMilestones() {
|
|
740
|
+
return this.listMilestonesAsync();
|
|
741
|
+
}
|
|
742
|
+
async listMilestonesAsync() {
|
|
743
|
+
const result = await this.pool.query(`
|
|
744
|
+
SELECT * FROM ${this.schema}.milestones WHERE status = 'active'
|
|
745
|
+
`);
|
|
746
|
+
return result.rows.map((row) => ({
|
|
747
|
+
id: row.id,
|
|
748
|
+
name: row.name,
|
|
749
|
+
description: row.description ?? undefined,
|
|
750
|
+
dueDate: row.due_date ?? undefined,
|
|
751
|
+
status: row.status,
|
|
752
|
+
createdAt: row.created_at instanceof Date
|
|
753
|
+
? row.created_at.toISOString()
|
|
754
|
+
: row.created_at,
|
|
755
|
+
}));
|
|
756
|
+
}
|
|
757
|
+
// ============ Memory Links ============
|
|
758
|
+
async linkMemory(workItemId, memoryId) {
|
|
759
|
+
await this.linkMemoryAsync(workItemId, memoryId);
|
|
760
|
+
}
|
|
761
|
+
async linkMemoryAsync(workItemId, memoryId) {
|
|
762
|
+
await this.pool.query(`
|
|
763
|
+
INSERT INTO ${this.schema}.work_item_memory_links (work_item_id, memory_id, linked_at)
|
|
764
|
+
VALUES ($1, $2, NOW())
|
|
765
|
+
ON CONFLICT DO NOTHING
|
|
766
|
+
`, [workItemId, memoryId]);
|
|
767
|
+
}
|
|
768
|
+
async getLinkedMemories(workItemId) {
|
|
769
|
+
return this.getLinkedMemoriesAsync(workItemId);
|
|
770
|
+
}
|
|
771
|
+
async getLinkedMemoriesAsync(workItemId) {
|
|
772
|
+
const result = await this.pool.query(`
|
|
773
|
+
SELECT memory_id FROM ${this.schema}.work_item_memory_links WHERE work_item_id = $1
|
|
774
|
+
`, [workItemId]);
|
|
775
|
+
return result.rows.map((r) => r.memory_id);
|
|
776
|
+
}
|
|
777
|
+
// ============ Stats ============
|
|
778
|
+
async getStats() {
|
|
779
|
+
return this.getStatsAsync();
|
|
780
|
+
}
|
|
781
|
+
async getStatsAsync() {
|
|
782
|
+
const client = await this.pool.connect();
|
|
783
|
+
try {
|
|
784
|
+
// Total count
|
|
785
|
+
const totalResult = await client.query(`SELECT COUNT(*) as count FROM ${this.schema}.work_items`);
|
|
786
|
+
const total = parseInt(totalResult.rows[0].count, 10);
|
|
787
|
+
// By status
|
|
788
|
+
const statusResult = await client.query(`
|
|
789
|
+
SELECT status, COUNT(*) as count FROM ${this.schema}.work_items GROUP BY status
|
|
790
|
+
`);
|
|
791
|
+
const byStatus = {};
|
|
792
|
+
for (const row of statusResult.rows) {
|
|
793
|
+
byStatus[row.status] = parseInt(row.count, 10);
|
|
794
|
+
}
|
|
795
|
+
// By priority
|
|
796
|
+
const priorityResult = await client.query(`
|
|
797
|
+
SELECT priority, COUNT(*) as count FROM ${this.schema}.work_items GROUP BY priority
|
|
798
|
+
`);
|
|
799
|
+
const byPriority = {};
|
|
800
|
+
for (const row of priorityResult.rows) {
|
|
801
|
+
byPriority[row.priority] = parseInt(row.count, 10);
|
|
802
|
+
}
|
|
803
|
+
// By project
|
|
804
|
+
const projectResult = await client.query(`
|
|
805
|
+
SELECT project_id, COUNT(*) as count FROM ${this.schema}.work_items GROUP BY project_id
|
|
806
|
+
`);
|
|
807
|
+
const byProject = {};
|
|
808
|
+
for (const row of projectResult.rows) {
|
|
809
|
+
byProject[row.project_id] = parseInt(row.count, 10);
|
|
810
|
+
}
|
|
811
|
+
// Recently created (7 days)
|
|
812
|
+
const createdResult = await client.query(`
|
|
813
|
+
SELECT COUNT(*) as count FROM ${this.schema}.work_items
|
|
814
|
+
WHERE created_at > NOW() - INTERVAL '7 days'
|
|
815
|
+
`);
|
|
816
|
+
const recentlyCreated = parseInt(createdResult.rows[0].count, 10);
|
|
817
|
+
// Recently closed (7 days)
|
|
818
|
+
const closedResult = await client.query(`
|
|
819
|
+
SELECT COUNT(*) as count FROM ${this.schema}.work_items
|
|
820
|
+
WHERE closed_at > NOW() - INTERVAL '7 days'
|
|
821
|
+
`);
|
|
822
|
+
const recentlyClosed = parseInt(closedResult.rows[0].count, 10);
|
|
823
|
+
return {
|
|
824
|
+
total,
|
|
825
|
+
byStatus,
|
|
826
|
+
byPriority,
|
|
827
|
+
byProject,
|
|
828
|
+
recentlyCreated,
|
|
829
|
+
recentlyClosed,
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
finally {
|
|
833
|
+
client.release();
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
// ============ AzDO mirror payload (sync stubs — not yet wired to pool) ============
|
|
837
|
+
async setPayloadJson(workItemId, json) {
|
|
838
|
+
await this.pool.query(`UPDATE ${this.schema}.work_items SET payload_json = $1::jsonb WHERE id = $2`, [json, workItemId]);
|
|
839
|
+
}
|
|
840
|
+
async getPayloadJson(workItemId) {
|
|
841
|
+
const result = await this.pool.query(`SELECT payload_json FROM ${this.schema}.work_items WHERE id = $1`, [workItemId]);
|
|
842
|
+
if (result.rows.length === 0)
|
|
843
|
+
return null;
|
|
844
|
+
const value = result.rows[0].payload_json;
|
|
845
|
+
return value == null ? null : JSON.stringify(value);
|
|
846
|
+
}
|
|
847
|
+
async updateOperatorSessionId(workItemId, sessionId) {
|
|
848
|
+
await this.pool.query(`UPDATE ${this.schema}.work_items SET operator_session_id = $1, updated_at = NOW() WHERE id = $2`, [sessionId, workItemId]);
|
|
849
|
+
}
|
|
850
|
+
async pruneOrphans(source, keepIds) {
|
|
851
|
+
const result = await this.pool.query(`SELECT id FROM ${this.schema}.work_items WHERE source = $1`, [source]);
|
|
852
|
+
const ids = result.rows.map((row) => row.id);
|
|
853
|
+
const toDelete = ids.filter((id) => !keepIds.has(id));
|
|
854
|
+
if (toDelete.length === 0)
|
|
855
|
+
return 0;
|
|
856
|
+
await this.pool.query(`DELETE FROM ${this.schema}.work_items WHERE id = ANY($1::text[])`, [toDelete]);
|
|
857
|
+
return toDelete.length;
|
|
858
|
+
}
|
|
859
|
+
// ============ Sync watermarks ============
|
|
860
|
+
async getSyncMeta(key) {
|
|
861
|
+
const result = await this.pool.query(`SELECT value FROM ${this.schema}.sync_meta WHERE key = $1`, [key]);
|
|
862
|
+
return result.rows[0]?.value ?? null;
|
|
863
|
+
}
|
|
864
|
+
async setSyncMeta(key, value) {
|
|
865
|
+
await this.pool.query(`INSERT INTO ${this.schema}.sync_meta (key, value)
|
|
866
|
+
VALUES ($1, $2)
|
|
867
|
+
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW()`, [key, value]);
|
|
868
|
+
}
|
|
869
|
+
async getProjectConfigs() {
|
|
870
|
+
const result = await this.pool.query(`SELECT name, path, heartbeat_ms, azdo_label, enabled, paused, operators
|
|
871
|
+
FROM ${this.schema}.projects
|
|
872
|
+
ORDER BY name ASC`);
|
|
873
|
+
return result.rows.map((row) => ({
|
|
874
|
+
name: String(row.name),
|
|
875
|
+
path: String(row.path),
|
|
876
|
+
heartbeatMs: Number(row.heartbeat_ms),
|
|
877
|
+
azdoLabel: row.azdo_label ? String(row.azdo_label) : undefined,
|
|
878
|
+
enabled: Boolean(row.enabled),
|
|
879
|
+
paused: Boolean(row.paused),
|
|
880
|
+
operators: Array.isArray(row.operators)
|
|
881
|
+
? row.operators.map((value) => String(value))
|
|
882
|
+
: [],
|
|
883
|
+
}));
|
|
884
|
+
}
|
|
885
|
+
async seedProjectConfigsIfEmpty(projects) {
|
|
886
|
+
if (projects.length === 0) {
|
|
887
|
+
return this.getProjectConfigs();
|
|
888
|
+
}
|
|
889
|
+
const client = await this.pool.connect();
|
|
890
|
+
try {
|
|
891
|
+
await client.query('BEGIN');
|
|
892
|
+
const countResult = await client.query(`SELECT COUNT(*)::int AS count FROM ${this.schema}.projects`);
|
|
893
|
+
const count = Number(countResult.rows[0]?.count ?? 0);
|
|
894
|
+
if (count === 0) {
|
|
895
|
+
for (const project of projects) {
|
|
896
|
+
await client.query(`INSERT INTO ${this.schema}.projects
|
|
897
|
+
(name, path, heartbeat_ms, azdo_label, enabled, paused, operators)
|
|
898
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`, [
|
|
899
|
+
project.name,
|
|
900
|
+
project.path,
|
|
901
|
+
project.heartbeatMs,
|
|
902
|
+
project.azdoLabel ?? null,
|
|
903
|
+
project.enabled,
|
|
904
|
+
project.paused,
|
|
905
|
+
JSON.stringify(project.operators ?? []),
|
|
906
|
+
]);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
await client.query('COMMIT');
|
|
910
|
+
}
|
|
911
|
+
catch (error) {
|
|
912
|
+
await client.query('ROLLBACK');
|
|
913
|
+
throw error;
|
|
914
|
+
}
|
|
915
|
+
finally {
|
|
916
|
+
client.release();
|
|
917
|
+
}
|
|
918
|
+
return this.getProjectConfigs();
|
|
919
|
+
}
|
|
920
|
+
// ============ Sync interface (compatibility) ============
|
|
921
|
+
// These methods ensure interface compatibility but log warnings
|
|
922
|
+
async syncListWorkItems(filter) {
|
|
923
|
+
return this.listWorkItemsAsync(filter);
|
|
924
|
+
}
|
|
925
|
+
async syncGetStats() {
|
|
926
|
+
return this.getStatsAsync();
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
// Factory function to create appropriate store based on config
|
|
930
|
+
export function createWorkItemStore(config) {
|
|
931
|
+
if (config.type === 'postgres') {
|
|
932
|
+
return new PostgresWorkItemStore(config.postgres ?? {});
|
|
933
|
+
}
|
|
934
|
+
// Return SQLite store via the config-aware index, not sqliteStore directly
|
|
935
|
+
throw new Error('Use openSqliteWorkItemStore() from sqliteStore.js for SQLite directly, or getWorkItemStore() from workItems/index.js');
|
|
936
|
+
}
|
|
937
|
+
//# sourceMappingURL=postgresStore.js.map
|