engineering-memory 1.11.16 → 1.11.17
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/package.json +1 -1
- package/runtime/build.json +1 -1
- package/runtime/dist/src/config.js +1 -0
- package/runtime/dist/src/mcp/tool-annotations.js +1 -0
- package/runtime/dist/src/mcp/tool-definitions.js +14 -2
- package/runtime/dist/src/runtime/api-client.js +1 -0
- package/runtime/dist/src/runtime/bridge-service.js +20 -18
- package/skill/references/lifecycle.md +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "engineering-memory",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.17",
|
|
4
4
|
"description": "Installs the Engineering Memory skill and its local MCP bridge. Sign in after installing; your organization and project are resolved from your account.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
package/runtime/build.json
CHANGED
|
@@ -77,6 +77,7 @@ export const endpoints = {
|
|
|
77
77
|
projectRestore: (projectId) => `/projects/${projectId}/restore`,
|
|
78
78
|
projectMemberAdd: (projectId) => `/projects/${projectId}/members`,
|
|
79
79
|
projectMemberList: (projectId) => `/projects/${projectId}/members`,
|
|
80
|
+
workItemStatuses: (projectId) => `/projects/${projectId}/work-items/statuses`,
|
|
80
81
|
workItemList: (projectId) => `/projects/${projectId}/work-items`,
|
|
81
82
|
workItemGet: (projectId, workItemId) => `/projects/${projectId}/work-items/${workItemId}`,
|
|
82
83
|
projectLink: '/projects/link',
|
|
@@ -130,6 +130,7 @@ export const engineeringMemoryToolNames = [
|
|
|
130
130
|
'work_item.plan',
|
|
131
131
|
'work_item.confirm_plan',
|
|
132
132
|
'project.update',
|
|
133
|
+
'work_item.statuses',
|
|
133
134
|
'work_item.list',
|
|
134
135
|
'work_item.get',
|
|
135
136
|
'project.clone',
|
|
@@ -932,7 +933,7 @@ export function registerEngineeringMemoryTools(server, service) {
|
|
|
932
933
|
}),
|
|
933
934
|
}, async (input) => toolResult(await service.workItemCreate(input)));
|
|
934
935
|
server.registerTool('work_item.update', {
|
|
935
|
-
description:
|
|
936
|
+
description: 'Edit or assign a work item at its current version. Assignees must already be active project members; this does not grant project access. Read work_item.statuses before changing status. Send the actual project catalogue slug and follow its user-defined meaning, entryRule and flags; never infer workflow from a status name.',
|
|
936
937
|
inputSchema: z.object({
|
|
937
938
|
...workItemLocator,
|
|
938
939
|
data: z.object({
|
|
@@ -1015,11 +1016,22 @@ export function registerEngineeringMemoryTools(server, service) {
|
|
|
1015
1016
|
}),
|
|
1016
1017
|
}),
|
|
1017
1018
|
}, async (input) => toolResult(await service.projectUpdate(input)));
|
|
1019
|
+
server.registerTool('work_item.statuses', {
|
|
1020
|
+
description: 'Read the project status catalogue before choosing a work item status. Follow the user-defined meaning, entryRule and flags; never infer workflow from status names. Page with offset and limit (defaults 0 and 50, maximum 100). Archived statuses are excluded unless includeArchived is true.',
|
|
1021
|
+
inputSchema: z.object({
|
|
1022
|
+
projectId: z.string().uuid(),
|
|
1023
|
+
offset: z.number().int().min(0).optional(),
|
|
1024
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
1025
|
+
includeArchived: z.boolean().optional(),
|
|
1026
|
+
}),
|
|
1027
|
+
}, async (input) => toolResult(await service.workItemStatuses(input)));
|
|
1018
1028
|
server.registerTool('work_item.list', {
|
|
1019
|
-
description:
|
|
1029
|
+
description: 'List selectable work items for a project before opening an engineering run in this chat. Read work_item.statuses for the actual project catalogue slugs and user-defined meanings; never infer workflow from status names. The status filter matches an actual slug, including a retained archived status; an unknown slug returns an empty page.',
|
|
1020
1030
|
inputSchema: z.object({
|
|
1021
1031
|
projectId: z.string().uuid(),
|
|
1022
1032
|
status: z.string().trim().min(1).max(64).optional(),
|
|
1033
|
+
offset: z.number().int().min(0).optional(),
|
|
1034
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
1023
1035
|
priority: z.enum(['lowest', 'low', 'medium', 'high', 'highest']).optional(),
|
|
1024
1036
|
assigneeUserId: z.string().uuid().optional(),
|
|
1025
1037
|
includeArchived: z.boolean().optional(),
|
|
@@ -3077,6 +3077,19 @@ export class BridgeService {
|
|
|
3077
3077
|
});
|
|
3078
3078
|
});
|
|
3079
3079
|
}
|
|
3080
|
+
async workItemStatuses(input) {
|
|
3081
|
+
return this.execute(async () => {
|
|
3082
|
+
const query = new URLSearchParams({
|
|
3083
|
+
offset: String(input.offset ?? 0),
|
|
3084
|
+
limit: String(input.limit ?? 50),
|
|
3085
|
+
});
|
|
3086
|
+
if (input.includeArchived !== undefined) {
|
|
3087
|
+
query.set('includeArchived', String(input.includeArchived));
|
|
3088
|
+
}
|
|
3089
|
+
const response = await this.dependencies.client.request(`${endpoints.workItemStatuses(input.projectId)}?${query.toString()}`);
|
|
3090
|
+
return asJsonValue(response.data);
|
|
3091
|
+
});
|
|
3092
|
+
}
|
|
3080
3093
|
async workItemList(input) {
|
|
3081
3094
|
return await this.execute(async () => {
|
|
3082
3095
|
const query = new URLSearchParams();
|
|
@@ -3089,6 +3102,10 @@ export class BridgeService {
|
|
|
3089
3102
|
}
|
|
3090
3103
|
if (input.includeArchived)
|
|
3091
3104
|
query.set('includeArchived', 'true');
|
|
3105
|
+
if (input.offset !== undefined)
|
|
3106
|
+
query.set('offset', String(input.offset));
|
|
3107
|
+
if (input.limit !== undefined)
|
|
3108
|
+
query.set('limit', String(input.limit));
|
|
3092
3109
|
const suffix = query.size > 0 ? `?${query.toString()}` : '';
|
|
3093
3110
|
const response = await this.dependencies.client.request(`${endpoints.workItemList(input.projectId)}${suffix}`);
|
|
3094
3111
|
return asJsonValue({
|
|
@@ -3551,30 +3568,15 @@ export class BridgeService {
|
|
|
3551
3568
|
}
|
|
3552
3569
|
}
|
|
3553
3570
|
async actionableWorkItems(projectId) {
|
|
3554
|
-
const path = `${endpoints.workItemList(projectId)}?limit=100`;
|
|
3555
3571
|
try {
|
|
3556
|
-
const
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
throw error;
|
|
3560
|
-
});
|
|
3561
|
-
if (chosen && chosen.length > 0)
|
|
3562
|
-
return chosen;
|
|
3563
|
-
const every = await this.workItemPage(path);
|
|
3564
|
-
if (chosen && every.some((entry) => objectValue(objectValue(entry)?.projectStatus) !== null))
|
|
3565
|
-
return [];
|
|
3566
|
-
const actionable = new Set(['backlog', 'ready', 'in_progress', 'in_review']);
|
|
3567
|
-
return every.filter((entry) => actionable.has(String(objectValue(entry)?.status)));
|
|
3572
|
+
const response = await this.dependencies.client.request(`${endpoints.workItemList(projectId)}?limit=100&actionable=true`);
|
|
3573
|
+
const items = objectValue(response.data)?.items;
|
|
3574
|
+
return Array.isArray(items) ? items : [];
|
|
3568
3575
|
}
|
|
3569
3576
|
catch {
|
|
3570
3577
|
return [];
|
|
3571
3578
|
}
|
|
3572
3579
|
}
|
|
3573
|
-
async workItemPage(path) {
|
|
3574
|
-
const response = await this.dependencies.client.request(path);
|
|
3575
|
-
const items = objectValue(response.data)?.items;
|
|
3576
|
-
return Array.isArray(items) ? items : [];
|
|
3577
|
-
}
|
|
3578
3580
|
async clientUpdate(authenticated) {
|
|
3579
3581
|
const installed = this.dependencies.clientVersion;
|
|
3580
3582
|
if (!authenticated) {
|
|
@@ -73,6 +73,14 @@ One WorkItem UUID coordinates independent EngineeringTask runs, one per selected
|
|
|
73
73
|
|
|
74
74
|
Open each side with the same workItemId and its own repository binding when work reaches that side. Each side has its own lease, reconciliation, verify, close and commit gate. Check `work_item.runs` and sibling checkpoints when handing off; one side completing does not prove all selected projects are complete. A plan's scope and branch cannot change while an implementation run is active. Read-only analysis does not acquire application write rights; its later write transition must satisfy discipline and the confirmed plan.
|
|
75
75
|
|
|
76
|
+
### Work item statuses
|
|
77
|
+
|
|
78
|
+
Read `work_item.statuses` before choosing a status for `work_item.update` or filtering `work_item.list`. The catalogue belongs to the project: follow its user-defined `meaning`, `entryRule` and flags. Never infer workflow from a name or translate statuses into the old six-value set. Send the actual catalogue slug. A work item's `status` is that slug, or null when its status link is invalid.
|
|
79
|
+
|
|
80
|
+
The catalogue returns `items`, `total`, `offset` and `limit`. Page with `offset` (default 0) and `limit` (default 50, maximum 100); use `includeArchived: true` to inspect retained archived statuses. Each row includes `id`, `slug`, `name`, `category`, `isInitial`, `isActionable`, `isParked`, `isTerminal`, `archivedAt`, `meaning`, `entryRule`, `position` and `lockVersion`. The work item's nested `projectStatus` remains its compact nine-field summary. `work_item.list` also accepts `offset` and `limit`; a status filter matches the actual slug, including retained archived statuses, and an unknown slug returns an empty page. Its `includeArchived` option concerns work items.
|
|
81
|
+
|
|
82
|
+
Session entry uses the backend's actionable selection. An empty page remains empty, and a failed lookup offers no work items; never retry an unfiltered list to classify statuses locally. Reuse existing user choices. Any unresolved workflow choice must use the native questionnaire.
|
|
83
|
+
|
|
76
84
|
### Administration, product management and QA
|
|
77
85
|
|
|
78
86
|
Administrative authority and work discipline are independent. Organization admins can manage projects, assignments, repository URLs and work items in their organization. A global admin has those rights only in organizations they actively belong to. Ordinary users need a live explicit project assignment. Active organization administrators, including a global admin with live membership in that organization, inherit contributor access to its projects without a separate project grant. Fullstack/backend/web/mobile/frontend disciplines still govern implementation, while project overrides do not grant administration.
|