@bpmsoftwaresolutions/ai-engine-client 1.1.35 → 1.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/package.json +1 -1
- package/src/index.js +167 -1
package/README.md
CHANGED
|
@@ -374,7 +374,7 @@ await client.importImplementationPacket({
|
|
|
374
374
|
});
|
|
375
375
|
```
|
|
376
376
|
|
|
377
|
-
The package does not auto-convert nested human planning structures like `tasks` and `subtasks` into durable implementation-item tasks. To
|
|
377
|
+
The package does not auto-convert nested human planning structures like `tasks` and `subtasks` into durable implementation-item tasks. To import a packet and immediately materialize a visible roadmap surface, use `importImplementationPacketAndMaterializeRoadmap()`. If you only need the task records, use `ensureProjectRoadmapTaskSurface()` or `createImplementationTask()`.
|
|
378
378
|
|
|
379
379
|
A copyable example payload is packaged at `examples/implementation-plan-packet.minimal.json`.
|
|
380
380
|
|
|
@@ -587,6 +587,7 @@ Generated scripts are ephemeral helpers, not source-of-truth. The server keeps S
|
|
|
587
587
|
| `getProjectImplementationRoadmapReport(projectId)` | Get the SQL-backed implementation roadmap report payload. |
|
|
588
588
|
| `downloadProjectImplementationRoadmapReportMarkdown(projectId)` | Download the implementation roadmap markdown report. |
|
|
589
589
|
| `ensureProjectRoadmapTaskSurface(projectId, { requestedBy, assignedTo, createAcceptanceSubtasks })` | Materialize the active roadmap item's parent task and acceptance subtasks. |
|
|
590
|
+
| `importImplementationPacketAndMaterializeRoadmap(packetPayload, { importedBy, requestedBy, createdBy, workflowId, bindingRole, assignedTo, notes, createAcceptanceSubtasks })` | Import a governed implementation packet, bind it to the project workflow, and materialize the roadmap projection. |
|
|
590
591
|
| `listProjectOpenTasks(projectId)` | Open tasks for a project. |
|
|
591
592
|
| `getProjectPerformanceMetrics(projectId, { workflowId, workflowRunId, sinceUtc })` | Performance metrics. |
|
|
592
593
|
|
|
@@ -618,6 +619,7 @@ Current package version: `1.0.0-beta.13`.
|
|
|
618
619
|
| `updateAcceptanceCheckStatus(itemId, checkId, body)` | Update acceptance check. |
|
|
619
620
|
| `createImplementationPacketGateDecision(packetId, body)` | Record gate decision. |
|
|
620
621
|
| `bindImplementationPacketToWorkflow(workflowId, body)` | Bind packet to workflow. |
|
|
622
|
+
| `importImplementationPacketAndMaterializeRoadmap(packetPayload, { importedBy, requestedBy, createdBy, workflowId, bindingRole, assignedTo, notes, createAcceptanceSubtasks })` | Import, bind, materialize tasks, and read back roadmap counts in one call. |
|
|
621
623
|
| `getWorkflowImplementationRoadmap(workflowId)` | Workflow-linked roadmap. |
|
|
622
624
|
| `getWorkflowResumeContext(workflowId)` | Resume context. |
|
|
623
625
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const DEFAULT_TIMEOUT_MS = 30000;
|
|
2
|
-
export const AI_ENGINE_CLIENT_VERSION = '1.1.
|
|
2
|
+
export const AI_ENGINE_CLIENT_VERSION = '1.1.36';
|
|
3
3
|
export const GOVERNED_MUTATION_REQUIRED_CAPABILITIES = [
|
|
4
4
|
'executeVerifiedMutation',
|
|
5
5
|
'post_mutation_verification',
|
|
@@ -114,6 +114,32 @@ function cleanText(value) {
|
|
|
114
114
|
return text || null;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
function countRoadmapProjectionLines(markdown) {
|
|
118
|
+
const lines = [];
|
|
119
|
+
let inSummary = false;
|
|
120
|
+
for (const line of String(markdown || '').split(/\r?\n/)) {
|
|
121
|
+
if (line.startsWith('## Roadmap Summary')) {
|
|
122
|
+
inSummary = true;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (inSummary && line.startsWith('## ')) {
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
if (inSummary && line.startsWith('- ')) {
|
|
129
|
+
lines.push(line);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const wanted = [
|
|
133
|
+
'Total Items',
|
|
134
|
+
'Total Tasks',
|
|
135
|
+
'Total Subtasks',
|
|
136
|
+
'Total Acceptance Checks',
|
|
137
|
+
'Open Acceptance Checks',
|
|
138
|
+
'Completion Percentage',
|
|
139
|
+
];
|
|
140
|
+
return lines.filter((line) => wanted.some((label) => line.startsWith(`- ${label}:`)));
|
|
141
|
+
}
|
|
142
|
+
|
|
117
143
|
function cleanList(value) {
|
|
118
144
|
if (!Array.isArray(value)) return [];
|
|
119
145
|
return value.map((item) => cleanText(item)).filter(Boolean);
|
|
@@ -1626,6 +1652,100 @@ export class AIEngineClient {
|
|
|
1626
1652
|
});
|
|
1627
1653
|
}
|
|
1628
1654
|
|
|
1655
|
+
async importImplementationPacketAndMaterializeRoadmap(packetPayload, {
|
|
1656
|
+
importedBy,
|
|
1657
|
+
requestedBy,
|
|
1658
|
+
createdBy,
|
|
1659
|
+
workflowId,
|
|
1660
|
+
bindingRole = 'active',
|
|
1661
|
+
assignedTo,
|
|
1662
|
+
notes,
|
|
1663
|
+
createAcceptanceSubtasks = true,
|
|
1664
|
+
} = {}) {
|
|
1665
|
+
if (!isPlainObject(packetPayload)) {
|
|
1666
|
+
throw new Error('packetPayload must be a JSON object.');
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
const normalizedImportedBy = cleanText(importedBy) || cleanText(requestedBy) || this.actorId;
|
|
1670
|
+
const normalizedRequestedBy = cleanText(requestedBy) || normalizedImportedBy;
|
|
1671
|
+
const normalizedCreatedBy = cleanText(createdBy) || normalizedRequestedBy;
|
|
1672
|
+
|
|
1673
|
+
const importedPacket = await this.importImplementationPacket({
|
|
1674
|
+
...packetPayload,
|
|
1675
|
+
imported_by: normalizedImportedBy,
|
|
1676
|
+
});
|
|
1677
|
+
const projectReference = this._resolveImplementationPacketProjectReference(packetPayload);
|
|
1678
|
+
if (!projectReference) {
|
|
1679
|
+
throw new Error('Could not resolve a project reference from the packet payload.');
|
|
1680
|
+
}
|
|
1681
|
+
const projectPayload = await this.getProject(projectReference);
|
|
1682
|
+
const projectSummary = isPlainObject(projectPayload?.summary) ? projectPayload.summary : {};
|
|
1683
|
+
const projectId = cleanText(projectSummary.project_id);
|
|
1684
|
+
if (!projectId) {
|
|
1685
|
+
throw new Error('Project id could not be resolved.');
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
const workflowReference = this._resolveImplementationPacketWorkflowReference(packetPayload, {
|
|
1689
|
+
projectSummary,
|
|
1690
|
+
workflowIdOverride: cleanText(workflowId),
|
|
1691
|
+
});
|
|
1692
|
+
if (!workflowReference) {
|
|
1693
|
+
throw new Error('Could not resolve a workflow reference from the packet payload or project summary.');
|
|
1694
|
+
}
|
|
1695
|
+
const resolvedWorkflowId = await this._resolveImplementationPacketWorkflowId(workflowReference);
|
|
1696
|
+
const workflowSlug = cleanText(projectSummary.workflow_slug);
|
|
1697
|
+
const packetId = cleanText(importedPacket?.packet_id || importedPacket?.packetId || importedPacket?.implementation_packet_key || importedPacket?.implementationPacketKey || packetPayload.packetId || packetPayload.packet_id);
|
|
1698
|
+
const implementationPacketId = cleanText(importedPacket?.implementation_packet_id || importedPacket?.implementationPacketId || packetId);
|
|
1699
|
+
|
|
1700
|
+
const binding = await this.bindImplementationPacketToWorkflow(resolvedWorkflowId, {
|
|
1701
|
+
packet_id: packetId,
|
|
1702
|
+
binding_role: cleanText(bindingRole) || 'active',
|
|
1703
|
+
created_by: normalizedCreatedBy,
|
|
1704
|
+
notes: cleanText(notes),
|
|
1705
|
+
});
|
|
1706
|
+
|
|
1707
|
+
const taskSurface = await this.ensureProjectRoadmapTaskSurface(projectId, {
|
|
1708
|
+
requestedBy: normalizedRequestedBy,
|
|
1709
|
+
assignedTo,
|
|
1710
|
+
createAcceptanceSubtasks,
|
|
1711
|
+
});
|
|
1712
|
+
|
|
1713
|
+
const roadmapReport = await this.getProjectImplementationRoadmapReport(projectId);
|
|
1714
|
+
const roadmapMarkdown = await this.downloadProjectImplementationRoadmapReportMarkdown(projectId);
|
|
1715
|
+
const phases = Array.isArray(packetPayload.phases) ? packetPayload.phases.filter(isPlainObject) : [];
|
|
1716
|
+
const roadmapItems = phases.flatMap((phase) => (
|
|
1717
|
+
Array.isArray(phase.items) ? phase.items.filter(isPlainObject) : []
|
|
1718
|
+
));
|
|
1719
|
+
const taskRows = Array.isArray(taskSurface?.task_surfaces) ? taskSurface.task_surfaces.filter(isPlainObject) : [];
|
|
1720
|
+
const subtaskRows = taskRows.filter((task) => cleanText(task.parent_task_id) !== null);
|
|
1721
|
+
const acceptanceCheckCount = roadmapItems.reduce(
|
|
1722
|
+
(total, item) => total + (Array.isArray(item.acceptanceChecks) ? item.acceptanceChecks.filter(Boolean).length : 0),
|
|
1723
|
+
0,
|
|
1724
|
+
);
|
|
1725
|
+
|
|
1726
|
+
return {
|
|
1727
|
+
status: 'materialized',
|
|
1728
|
+
project_id: projectId,
|
|
1729
|
+
project_slug: cleanText(projectSummary.project_slug),
|
|
1730
|
+
workflow_id: resolvedWorkflowId,
|
|
1731
|
+
workflow_slug: workflowSlug,
|
|
1732
|
+
implementation_packet_id: implementationPacketId,
|
|
1733
|
+
implementation_packet_key: packetId,
|
|
1734
|
+
binding,
|
|
1735
|
+
task_surface: taskSurface,
|
|
1736
|
+
roadmap_projection: {
|
|
1737
|
+
report: roadmapReport,
|
|
1738
|
+
markdown: roadmapMarkdown,
|
|
1739
|
+
count_lines: countRoadmapProjectionLines(roadmapMarkdown),
|
|
1740
|
+
phase_count: phases.length,
|
|
1741
|
+
roadmap_item_count: roadmapItems.length,
|
|
1742
|
+
task_count: taskRows.length,
|
|
1743
|
+
subtask_count: subtaskRows.length,
|
|
1744
|
+
acceptance_check_count: acceptanceCheckCount,
|
|
1745
|
+
},
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1629
1749
|
async listProjectOpenTasks(projectId) {
|
|
1630
1750
|
return this._request(`/api/operator/projects/${projectId}/open-tasks`);
|
|
1631
1751
|
}
|
|
@@ -1636,6 +1756,52 @@ export class AIEngineClient {
|
|
|
1636
1756
|
});
|
|
1637
1757
|
}
|
|
1638
1758
|
|
|
1759
|
+
_resolveImplementationPacketProjectReference(packetPayload) {
|
|
1760
|
+
return cleanText(packetPayload.projectId)
|
|
1761
|
+
|| cleanText(packetPayload.project_id)
|
|
1762
|
+
|| cleanText(packetPayload.projectSlug)
|
|
1763
|
+
|| cleanText(packetPayload.project_slug)
|
|
1764
|
+
|| cleanText(packetPayload?.scope?.projectId)
|
|
1765
|
+
|| cleanText(packetPayload?.scope?.project_id)
|
|
1766
|
+
|| cleanText(packetPayload?.scope?.projectSlug)
|
|
1767
|
+
|| cleanText(packetPayload?.scope?.project_slug)
|
|
1768
|
+
|| cleanText(packetPayload?.system?.slug);
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
_resolveImplementationPacketWorkflowReference(packetPayload, { projectSummary, workflowIdOverride } = {}) {
|
|
1772
|
+
if (workflowIdOverride) return workflowIdOverride;
|
|
1773
|
+
return cleanText(packetPayload.workflowId)
|
|
1774
|
+
|| cleanText(packetPayload.workflow_id)
|
|
1775
|
+
|| cleanText(packetPayload.workflowSlug)
|
|
1776
|
+
|| cleanText(packetPayload.workflow_slug)
|
|
1777
|
+
|| cleanText(packetPayload?.scope?.workflowId)
|
|
1778
|
+
|| cleanText(packetPayload?.scope?.workflow_id)
|
|
1779
|
+
|| cleanText(packetPayload?.scope?.workflowSlug)
|
|
1780
|
+
|| cleanText(packetPayload?.scope?.workflow_slug)
|
|
1781
|
+
|| cleanText(projectSummary?.workflow_id)
|
|
1782
|
+
|| cleanText(projectSummary?.workflow_slug);
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
async _resolveImplementationPacketWorkflowId(workflowReference) {
|
|
1786
|
+
const normalized = cleanText(workflowReference);
|
|
1787
|
+
if (!normalized) {
|
|
1788
|
+
throw new Error('workflow reference is required.');
|
|
1789
|
+
}
|
|
1790
|
+
const workflow = await this.getWorkflow(normalized);
|
|
1791
|
+
if (workflow) {
|
|
1792
|
+
return cleanText(workflow.workflow_id) || cleanText(workflow.workflowId) || normalized;
|
|
1793
|
+
}
|
|
1794
|
+
const workflowList = await this.listWorkflows();
|
|
1795
|
+
const workflows = Array.isArray(workflowList) ? workflowList : workflowList?.workflows;
|
|
1796
|
+
const matches = Array.isArray(workflows)
|
|
1797
|
+
? workflows.filter((item) => cleanText(item?.slug) === normalized)
|
|
1798
|
+
: [];
|
|
1799
|
+
if (matches.length === 1) {
|
|
1800
|
+
return cleanText(matches[0].workflow_id) || cleanText(matches[0].workflowId) || normalized;
|
|
1801
|
+
}
|
|
1802
|
+
throw new Error(`Workflow not found: ${normalized}`);
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1639
1805
|
// ─── Implementation Tasks ──────────────────────────────────────────────────
|
|
1640
1806
|
|
|
1641
1807
|
async createImplementationTask(implementationItemId, {
|