metheus-governance-mcp-cli 0.2.151 → 0.2.152
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/cli.mjs +31 -34
- package/lib/local-project-dispatch.mjs +0 -12
- package/lib/runner-data.mjs +88 -0
- package/lib/runner-orchestration.mjs +87 -0
- package/lib/selftest-runner-scenarios.mjs +20 -1
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -130,10 +130,12 @@ import {
|
|
|
130
130
|
printRunnerResult,
|
|
131
131
|
} from "./lib/runner-helpers.mjs";
|
|
132
132
|
import {
|
|
133
|
+
createProjectEvidence as createProjectEvidenceImpl,
|
|
133
134
|
createProjectWorkItem as createProjectWorkItemImpl,
|
|
134
135
|
createThreadComment as createThreadCommentImpl,
|
|
135
136
|
createWorkItemThread as createWorkItemThreadImpl,
|
|
136
137
|
discoverArchiveThreadForDestination as discoverArchiveThreadForDestinationImpl,
|
|
138
|
+
linkWorkItemEvidence as linkWorkItemEvidenceImpl,
|
|
137
139
|
listProjectChatDestinations as listProjectChatDestinationsImpl,
|
|
138
140
|
listThreadComments as listThreadCommentsImpl,
|
|
139
141
|
listUserBotsForRunner as listUserBotsForRunnerImpl,
|
|
@@ -1362,7 +1364,6 @@ function loadBotRunnerWorkspaceRegistry(options = {}) {
|
|
|
1362
1364
|
}
|
|
1363
1365
|
|
|
1364
1366
|
function saveBotRunnerConfig(nextConfig, filePath = botRunnerConfigFilePath()) {
|
|
1365
|
-
saveBotRunnerWorkspaceRegistry(safeObject(nextConfig).projectMappings);
|
|
1366
1367
|
const payload = serializeBotRunnerConfig(nextConfig);
|
|
1367
1368
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
1368
1369
|
fs.writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
@@ -1523,6 +1524,9 @@ function loadBotRunnerConfig(options = {}) {
|
|
|
1523
1524
|
normalized.projectMappings = mergedProjectMappings;
|
|
1524
1525
|
normalized.workspaceRegistryFilePath = workspaceRegistry.filePath;
|
|
1525
1526
|
if (persistIfNeeded && (normalized.migrated || !fs.existsSync(filePath) || registryChanged || legacyProjectMappingsPresent)) {
|
|
1527
|
+
if (registryChanged || legacyProjectMappingsPresent) {
|
|
1528
|
+
saveBotRunnerWorkspaceRegistry(mergedProjectMappings, workspaceRegistry.filePath);
|
|
1529
|
+
}
|
|
1526
1530
|
saveBotRunnerConfig(normalized, filePath);
|
|
1527
1531
|
normalized.migrated = false;
|
|
1528
1532
|
}
|
|
@@ -1626,24 +1630,22 @@ function rememberProjectWorkspaceMapping({ projectID, workspaceDir, source }) {
|
|
|
1626
1630
|
reason: "existing workspace mapping preserved over unrelated automatic signal",
|
|
1627
1631
|
};
|
|
1628
1632
|
}
|
|
1629
|
-
const
|
|
1630
|
-
...config,
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
source: normalizedSource,
|
|
1637
|
-
updatedAt: new Date().toISOString(),
|
|
1638
|
-
},
|
|
1633
|
+
const nextProjectMappings = {
|
|
1634
|
+
...safeObject(config.projectMappings),
|
|
1635
|
+
[projectID]: {
|
|
1636
|
+
projectID,
|
|
1637
|
+
workspaceDir: normalizedWorkspaceDir,
|
|
1638
|
+
source: normalizedSource,
|
|
1639
|
+
updatedAt: new Date().toISOString(),
|
|
1639
1640
|
},
|
|
1640
1641
|
};
|
|
1641
|
-
const
|
|
1642
|
+
const workspaceRegistryFilePath = config.workspaceRegistryFilePath || botRunnerWorkspaceRegistryFilePath();
|
|
1643
|
+
saveBotRunnerWorkspaceRegistry(nextProjectMappings, workspaceRegistryFilePath);
|
|
1642
1644
|
return {
|
|
1643
1645
|
ok: true,
|
|
1644
1646
|
updated: true,
|
|
1645
|
-
filePath,
|
|
1646
|
-
workspaceRegistryFilePath
|
|
1647
|
+
filePath: config.filePath,
|
|
1648
|
+
workspaceRegistryFilePath,
|
|
1647
1649
|
projectID,
|
|
1648
1650
|
workspaceDir: normalizedWorkspaceDir,
|
|
1649
1651
|
};
|
|
@@ -3286,10 +3288,18 @@ async function createProjectWorkItem(params) {
|
|
|
3286
3288
|
return createProjectWorkItemImpl(params, buildRunnerDataDeps());
|
|
3287
3289
|
}
|
|
3288
3290
|
|
|
3291
|
+
async function createProjectEvidence(params) {
|
|
3292
|
+
return createProjectEvidenceImpl(params, buildRunnerDataDeps());
|
|
3293
|
+
}
|
|
3294
|
+
|
|
3289
3295
|
async function createWorkItemThread(params) {
|
|
3290
3296
|
return createWorkItemThreadImpl(params, buildRunnerDataDeps());
|
|
3291
3297
|
}
|
|
3292
3298
|
|
|
3299
|
+
async function linkWorkItemEvidence(params) {
|
|
3300
|
+
return linkWorkItemEvidenceImpl(params, buildRunnerDataDeps());
|
|
3301
|
+
}
|
|
3302
|
+
|
|
3293
3303
|
function buildRunnerDeliveryDeps() {
|
|
3294
3304
|
return {
|
|
3295
3305
|
listProjectChatDestinations,
|
|
@@ -3324,8 +3334,10 @@ function buildRunnerExecutionDeps() {
|
|
|
3324
3334
|
resolveRunnerExecutionPlanForRole,
|
|
3325
3335
|
validateWorkspaceArtifacts,
|
|
3326
3336
|
tryJsonParse,
|
|
3337
|
+
createProjectEvidence,
|
|
3327
3338
|
createProjectWorkItem,
|
|
3328
3339
|
createWorkItemThread,
|
|
3340
|
+
linkWorkItemEvidence,
|
|
3329
3341
|
replaceProjectCtxpackFiles,
|
|
3330
3342
|
};
|
|
3331
3343
|
}
|
|
@@ -7380,13 +7392,6 @@ function syncCtxpackToLocalCache({
|
|
|
7380
7392
|
} catch {
|
|
7381
7393
|
// Best-effort metadata refresh for workspace-root auto-detection.
|
|
7382
7394
|
}
|
|
7383
|
-
if (!isHomeFallback) {
|
|
7384
|
-
rememberProjectWorkspaceMapping({
|
|
7385
|
-
projectID,
|
|
7386
|
-
workspaceDir: resolvedWorkspaceDir,
|
|
7387
|
-
source: "ctxpack_sync_current",
|
|
7388
|
-
});
|
|
7389
|
-
}
|
|
7390
7395
|
return {
|
|
7391
7396
|
sync_status: isHomeFallback ? "home_fallback" : "current",
|
|
7392
7397
|
sync_message: isHomeFallback
|
|
@@ -7410,14 +7415,6 @@ function syncCtxpackToLocalCache({
|
|
|
7410
7415
|
|
|
7411
7416
|
fs.writeFileSync(metaPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
7412
7417
|
fs.writeFileSync(workspaceMetaPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
7413
|
-
if (!isHomeFallback) {
|
|
7414
|
-
rememberProjectWorkspaceMapping({
|
|
7415
|
-
projectID,
|
|
7416
|
-
workspaceDir: resolvedWorkspaceDir,
|
|
7417
|
-
source: "ctxpack_sync_write",
|
|
7418
|
-
});
|
|
7419
|
-
}
|
|
7420
|
-
|
|
7421
7418
|
return {
|
|
7422
7419
|
sync_status: isHomeFallback ? "home_fallback" : (previousMeta ? "updated" : "downloaded"),
|
|
7423
7420
|
sync_message: isHomeFallback
|
|
@@ -8505,14 +8502,14 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
|
|
|
8505
8502
|
safeObject(runnerConfigAfterProjectTool.projectMappings)?.[selftestProjectID]?.workspaceDir || "";
|
|
8506
8503
|
const projectToolWorkspaceSignalOk =
|
|
8507
8504
|
String(safeObject(response).error || "").trim() === ""
|
|
8508
|
-
&&
|
|
8505
|
+
&& !String(storedProjectToolWorkspace || "").trim();
|
|
8509
8506
|
push(
|
|
8510
|
-
"
|
|
8507
|
+
"project_summary_workspace_signal_does_not_update_runner_mapping",
|
|
8511
8508
|
projectToolWorkspaceSignalOk,
|
|
8512
8509
|
`workspace=${storedProjectToolWorkspace || "(none)"} source=${String(safeObject(runnerConfigAfterProjectTool.projectMappings)?.[selftestProjectID]?.source || "(none)")}`,
|
|
8513
8510
|
);
|
|
8514
8511
|
} catch (err) {
|
|
8515
|
-
push("
|
|
8512
|
+
push("project_summary_workspace_signal_does_not_update_runner_mapping", false, String(err?.message || err));
|
|
8516
8513
|
} finally {
|
|
8517
8514
|
if (previousProjectToolUserProfile === undefined) delete process.env.USERPROFILE;
|
|
8518
8515
|
else process.env.USERPROFILE = previousProjectToolUserProfile;
|
|
@@ -8582,12 +8579,12 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
|
|
|
8582
8579
|
const storedWorkspaceAfterDrift =
|
|
8583
8580
|
safeObject(runnerConfigAfterProjectToolDrift.projectMappings)?.[selftestProjectID]?.workspaceDir || "";
|
|
8584
8581
|
push(
|
|
8585
|
-
"
|
|
8582
|
+
"project_summary_workspace_signal_preserves_existing_manual_mapping",
|
|
8586
8583
|
normalizedPathForCompare(storedWorkspaceAfterDrift) === normalizedPathForCompare(stableWorkspaceDir),
|
|
8587
8584
|
`stored=${storedWorkspaceAfterDrift || "(none)"} stable=${stableWorkspaceDir}`,
|
|
8588
8585
|
);
|
|
8589
8586
|
} catch (err) {
|
|
8590
|
-
push("
|
|
8587
|
+
push("project_summary_workspace_signal_preserves_existing_manual_mapping", false, String(err?.message || err));
|
|
8591
8588
|
} finally {
|
|
8592
8589
|
if (previousProjectToolDriftUserProfile === undefined) delete process.env.USERPROFILE;
|
|
8593
8590
|
else process.env.USERPROFILE = previousProjectToolDriftUserProfile;
|
|
@@ -49,7 +49,6 @@ export async function handleLocalProjectToolDispatch(
|
|
|
49
49
|
const normalizeMergeAction = requireDependency(deps, "normalizeMergeAction");
|
|
50
50
|
const executeCtxpackMergeActionForTool = requireDependency(deps, "executeCtxpackMergeActionForTool");
|
|
51
51
|
const buildCtxpackMergeExecuteText = requireDependency(deps, "buildCtxpackMergeExecuteText");
|
|
52
|
-
const rememberProjectWorkspaceMapping = requireDependency(deps, "rememberProjectWorkspaceMapping");
|
|
53
52
|
const jsonRpcError = requireDependency(deps, "jsonRpcError");
|
|
54
53
|
const jsonRpcResult = requireDependency(deps, "jsonRpcResult");
|
|
55
54
|
|
|
@@ -91,17 +90,6 @@ export async function handleLocalProjectToolDispatch(
|
|
|
91
90
|
workspaceDir,
|
|
92
91
|
workspaceSignalTrusted,
|
|
93
92
|
});
|
|
94
|
-
if (workspaceSignalTrusted && String(workspaceDir || "").trim()) {
|
|
95
|
-
try {
|
|
96
|
-
rememberProjectWorkspaceMapping({
|
|
97
|
-
projectID,
|
|
98
|
-
workspaceDir,
|
|
99
|
-
source: "project_tool_workspace_signal",
|
|
100
|
-
});
|
|
101
|
-
} catch {
|
|
102
|
-
// Best-effort persistence only. The project summary response itself should still succeed.
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
93
|
const text = buildProjectSummaryText(summary);
|
|
106
94
|
return jsonRpcResult(requestObj, {
|
|
107
95
|
content: [{ type: "text", text }],
|
package/lib/runner-data.mjs
CHANGED
|
@@ -281,6 +281,94 @@ export async function createWorkItemThread(
|
|
|
281
281
|
return safeObject(parseJSONText(responseText));
|
|
282
282
|
}
|
|
283
283
|
|
|
284
|
+
export async function createProjectEvidence(
|
|
285
|
+
{
|
|
286
|
+
siteBaseURL,
|
|
287
|
+
token,
|
|
288
|
+
timeoutSeconds,
|
|
289
|
+
actorUserID,
|
|
290
|
+
projectID,
|
|
291
|
+
type,
|
|
292
|
+
uri = "",
|
|
293
|
+
source = "",
|
|
294
|
+
credibility = "",
|
|
295
|
+
sensitivity = "",
|
|
296
|
+
reproducibility = "",
|
|
297
|
+
version = "",
|
|
298
|
+
hash = "",
|
|
299
|
+
storage = "",
|
|
300
|
+
repoURL = "",
|
|
301
|
+
commitSHA = "",
|
|
302
|
+
repoPath = "",
|
|
303
|
+
blobSHA = "",
|
|
304
|
+
sha256 = "",
|
|
305
|
+
sizeBytes,
|
|
306
|
+
mimeType = "",
|
|
307
|
+
},
|
|
308
|
+
deps,
|
|
309
|
+
) {
|
|
310
|
+
const postJSONWithAuthHeaders = requireDependency(deps, "postJSONWithAuthHeaders");
|
|
311
|
+
const parseJSONText = requireDependency(deps, "parseJSONText");
|
|
312
|
+
const payload = {
|
|
313
|
+
project_id: projectID,
|
|
314
|
+
type,
|
|
315
|
+
...(uri ? { uri } : {}),
|
|
316
|
+
...(source ? { source } : {}),
|
|
317
|
+
...(credibility ? { credibility } : {}),
|
|
318
|
+
...(sensitivity ? { sensitivity } : {}),
|
|
319
|
+
...(reproducibility ? { reproducibility } : {}),
|
|
320
|
+
...(version ? { version } : {}),
|
|
321
|
+
...(hash ? { hash } : {}),
|
|
322
|
+
...(storage ? { storage } : {}),
|
|
323
|
+
...(repoURL ? { repo_url: repoURL } : {}),
|
|
324
|
+
...(commitSHA ? { commit_sha: commitSHA } : {}),
|
|
325
|
+
...(repoPath ? { repo_path: repoPath } : {}),
|
|
326
|
+
...(blobSHA ? { blob_sha: blobSHA } : {}),
|
|
327
|
+
...(sha256 ? { sha256 } : {}),
|
|
328
|
+
...(Number.isFinite(Number(sizeBytes)) ? { size_bytes: Number(sizeBytes) } : {}),
|
|
329
|
+
...(mimeType ? { mime_type: mimeType } : {}),
|
|
330
|
+
};
|
|
331
|
+
const responseText = await postJSONWithAuthHeaders(
|
|
332
|
+
`${siteBaseURL}/api/v1/evidence`,
|
|
333
|
+
timeoutSeconds,
|
|
334
|
+
token,
|
|
335
|
+
payload,
|
|
336
|
+
{
|
|
337
|
+
"X-Actor-User-Id": actorUserID,
|
|
338
|
+
},
|
|
339
|
+
);
|
|
340
|
+
return safeObject(parseJSONText(responseText));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export async function linkWorkItemEvidence(
|
|
344
|
+
{
|
|
345
|
+
siteBaseURL,
|
|
346
|
+
token,
|
|
347
|
+
timeoutSeconds,
|
|
348
|
+
actorUserID,
|
|
349
|
+
workItemID,
|
|
350
|
+
evidenceID,
|
|
351
|
+
relationNote = "",
|
|
352
|
+
},
|
|
353
|
+
deps,
|
|
354
|
+
) {
|
|
355
|
+
const postJSONWithAuthHeaders = requireDependency(deps, "postJSONWithAuthHeaders");
|
|
356
|
+
const parseJSONText = requireDependency(deps, "parseJSONText");
|
|
357
|
+
const responseText = await postJSONWithAuthHeaders(
|
|
358
|
+
`${siteBaseURL}/api/v1/workitems/${encodeURIComponent(workItemID)}/evidence`,
|
|
359
|
+
timeoutSeconds,
|
|
360
|
+
token,
|
|
361
|
+
{
|
|
362
|
+
evidence_id: evidenceID,
|
|
363
|
+
relation_note: relationNote,
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"X-Actor-User-Id": actorUserID,
|
|
367
|
+
},
|
|
368
|
+
);
|
|
369
|
+
return safeObject(parseJSONText(responseText));
|
|
370
|
+
}
|
|
371
|
+
|
|
284
372
|
export async function discoverArchiveThreadForDestination(
|
|
285
373
|
{
|
|
286
374
|
siteBaseURL,
|
|
@@ -586,7 +586,14 @@ async function materializeExecutionWorkItems({
|
|
|
586
586
|
const createWorkItemThread = typeof executionDeps.createWorkItemThread === "function"
|
|
587
587
|
? executionDeps.createWorkItemThread
|
|
588
588
|
: null;
|
|
589
|
+
const createProjectEvidence = typeof executionDeps.createProjectEvidence === "function"
|
|
590
|
+
? executionDeps.createProjectEvidence
|
|
591
|
+
: null;
|
|
592
|
+
const linkWorkItemEvidence = typeof executionDeps.linkWorkItemEvidence === "function"
|
|
593
|
+
? executionDeps.linkWorkItemEvidence
|
|
594
|
+
: null;
|
|
589
595
|
const createdWorkItems = [];
|
|
596
|
+
const createdEvidenceItems = [];
|
|
590
597
|
const errors = [];
|
|
591
598
|
for (const item of requestedWorkItems) {
|
|
592
599
|
try {
|
|
@@ -634,8 +641,66 @@ async function materializeExecutionWorkItems({
|
|
|
634
641
|
errors.push(`failed to create work item "${item.title}": ${String(err?.message || err)}`);
|
|
635
642
|
}
|
|
636
643
|
}
|
|
644
|
+
if (requiresEvidenceLinkForExecutionStep(step) && createdWorkItems.length > 0) {
|
|
645
|
+
if (!createProjectEvidence || !linkWorkItemEvidence) {
|
|
646
|
+
errors.push("runner execution deps missing evidence creation/link helpers");
|
|
647
|
+
} else if (ensureArray(validatedArtifacts).length === 0) {
|
|
648
|
+
errors.push(`could not link evidence for execution step "${String(safeObject(step).goal || "").trim() || "unnamed"}" because no validated project artifacts were produced`);
|
|
649
|
+
} else {
|
|
650
|
+
for (const artifactRaw of ensureArray(validatedArtifacts)) {
|
|
651
|
+
const artifact = safeObject(artifactRaw);
|
|
652
|
+
const artifactPath = String(artifact.relativePath || artifact.path || "").trim();
|
|
653
|
+
if (!artifactPath) {
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
try {
|
|
657
|
+
const createdEvidence = safeObject(await createProjectEvidence({
|
|
658
|
+
siteBaseURL: runtime.baseURL,
|
|
659
|
+
token: runtime.token,
|
|
660
|
+
timeoutSeconds: runtime.timeoutSeconds,
|
|
661
|
+
actorUserID: safeObject(runtime.actor).user_id,
|
|
662
|
+
projectID: String(normalizedRoute.projectID || normalizedRoute.project_id || "").trim(),
|
|
663
|
+
type: "file",
|
|
664
|
+
uri: artifactPath,
|
|
665
|
+
source: "runner_execution",
|
|
666
|
+
}));
|
|
667
|
+
const evidenceID = String(createdEvidence.id || createdEvidence.evidence_id || createdEvidence.evidenceID || "").trim();
|
|
668
|
+
if (!evidenceID) {
|
|
669
|
+
errors.push(`failed to create evidence for artifact "${artifactPath}"`);
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
createdEvidenceItems.push({
|
|
673
|
+
id: evidenceID,
|
|
674
|
+
path: artifactPath,
|
|
675
|
+
});
|
|
676
|
+
for (const workItem of createdWorkItems) {
|
|
677
|
+
const workItemID = String(safeObject(workItem).id || "").trim();
|
|
678
|
+
if (!workItemID) {
|
|
679
|
+
continue;
|
|
680
|
+
}
|
|
681
|
+
try {
|
|
682
|
+
await linkWorkItemEvidence({
|
|
683
|
+
siteBaseURL: runtime.baseURL,
|
|
684
|
+
token: runtime.token,
|
|
685
|
+
timeoutSeconds: runtime.timeoutSeconds,
|
|
686
|
+
actorUserID: safeObject(runtime.actor).user_id,
|
|
687
|
+
workItemID,
|
|
688
|
+
evidenceID,
|
|
689
|
+
relationNote: `Execution artifact: ${artifactPath}`,
|
|
690
|
+
});
|
|
691
|
+
} catch (err) {
|
|
692
|
+
errors.push(`failed to link evidence "${artifactPath}" to work item "${String(safeObject(workItem).title || workItemID).trim() || workItemID}": ${String(err?.message || err)}`);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
} catch (err) {
|
|
696
|
+
errors.push(`failed to create evidence for artifact "${artifactPath}": ${String(err?.message || err)}`);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
637
701
|
return {
|
|
638
702
|
workItems: createdWorkItems,
|
|
703
|
+
evidenceItems: createdEvidenceItems,
|
|
639
704
|
errors,
|
|
640
705
|
};
|
|
641
706
|
}
|
|
@@ -1148,6 +1213,7 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
1148
1213
|
const mergedArtifactPaths = new Set();
|
|
1149
1214
|
const mergedBoundaryViolations = [];
|
|
1150
1215
|
const mergedWorkItems = [];
|
|
1216
|
+
const mergedEvidenceItems = [];
|
|
1151
1217
|
const mergedCtxpackChangedPaths = new Set();
|
|
1152
1218
|
let finalCtxpackUpdate = null;
|
|
1153
1219
|
const totalSteps = plannedSteps.length;
|
|
@@ -1318,6 +1384,7 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
1318
1384
|
selectedRecord,
|
|
1319
1385
|
});
|
|
1320
1386
|
createdWorkItems = ensureArray(workItemMaterialization.workItems);
|
|
1387
|
+
const createdEvidenceItems = ensureArray(workItemMaterialization.evidenceItems);
|
|
1321
1388
|
stepErrors.push(
|
|
1322
1389
|
...ensureArray(workItemMaterialization.errors)
|
|
1323
1390
|
.map((item) => String(item || "").trim())
|
|
@@ -1326,6 +1393,17 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
1326
1393
|
if (requiresWorkItemsForExecutionStep(step) && createdWorkItems.length === 0) {
|
|
1327
1394
|
stepErrors.push(`${String(step.role || "").trim()} step completed without creating any governance work items`);
|
|
1328
1395
|
}
|
|
1396
|
+
createdEvidenceItems.forEach((item) => {
|
|
1397
|
+
const evidence = safeObject(item);
|
|
1398
|
+
const evidenceID = String(evidence.id || "").trim();
|
|
1399
|
+
if (!evidenceID) {
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
if (mergedEvidenceItems.some((existing) => String(safeObject(existing).id || "").trim() === evidenceID)) {
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
mergedEvidenceItems.push(evidence);
|
|
1406
|
+
});
|
|
1329
1407
|
}
|
|
1330
1408
|
if (stepErrors.length > 0) {
|
|
1331
1409
|
const reason = stepErrors.join("; ");
|
|
@@ -1387,6 +1465,7 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
1387
1465
|
artifactValidation: String(stepValidation.status || "").trim() || "none",
|
|
1388
1466
|
ctxpack: ctxpackUpdate,
|
|
1389
1467
|
workItems: createdWorkItems,
|
|
1468
|
+
evidenceItems: mergedEvidenceItems,
|
|
1390
1469
|
});
|
|
1391
1470
|
}
|
|
1392
1471
|
const finalStepResult = stepResults[stepResults.length - 1] || {};
|
|
@@ -1431,6 +1510,10 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
1431
1510
|
description: String(safeObject(item).description || "").trim(),
|
|
1432
1511
|
thread_id: String(safeObject(item).thread_id || "").trim(),
|
|
1433
1512
|
})),
|
|
1513
|
+
evidenceItems: mergedEvidenceItems.map((item) => ({
|
|
1514
|
+
id: String(safeObject(item).id || "").trim(),
|
|
1515
|
+
path: String(safeObject(item).path || "").trim(),
|
|
1516
|
+
})),
|
|
1434
1517
|
ctxpackUpdate: finalCtxpackUpdate && Object.keys(finalCtxpackUpdate).length > 0
|
|
1435
1518
|
? {
|
|
1436
1519
|
ctxpack_id: String(finalCtxpackUpdate.ctxpackID || "").trim(),
|
|
@@ -3050,6 +3133,8 @@ export async function processRunnerSelectedRecord({
|
|
|
3050
3133
|
last_boundary_violations: [],
|
|
3051
3134
|
last_work_item_ids: ensureArray(aiResult?.workItems).map((item) => String(safeObject(item).id || "").trim()).filter(Boolean),
|
|
3052
3135
|
last_work_item_titles: ensureArray(aiResult?.workItems).map((item) => String(safeObject(item).title || "").trim()).filter(Boolean),
|
|
3136
|
+
last_evidence_ids: ensureArray(aiResult?.evidenceItems).map((item) => String(safeObject(item).id || "").trim()).filter(Boolean),
|
|
3137
|
+
last_evidence_paths: ensureArray(aiResult?.evidenceItems).map((item) => String(safeObject(item).path || "").trim()).filter(Boolean),
|
|
3053
3138
|
last_ctxpack_version_id: String(safeObject(aiResult?.ctxpackUpdate).version_id || "").trim(),
|
|
3054
3139
|
last_ctxpack_changed_paths: ensureArray(safeObject(aiResult?.ctxpackUpdate).changed_paths).map((item) => String(item || "").trim()).filter(Boolean),
|
|
3055
3140
|
last_ctxpack_pushed_file_count: intFromRawAllowZero(safeObject(aiResult?.ctxpackUpdate).pushed_file_count, 0),
|
|
@@ -3099,6 +3184,8 @@ export async function processRunnerSelectedRecord({
|
|
|
3099
3184
|
ctxpack_pushed_file_count: intFromRawAllowZero(safeObject(aiResult?.ctxpackUpdate).pushed_file_count, 0),
|
|
3100
3185
|
work_item_ids: ensureArray(aiResult?.workItems).map((item) => String(safeObject(item).id || "").trim()).filter(Boolean),
|
|
3101
3186
|
work_item_titles: ensureArray(aiResult?.workItems).map((item) => String(safeObject(item).title || "").trim()).filter(Boolean),
|
|
3187
|
+
evidence_ids: ensureArray(aiResult?.evidenceItems).map((item) => String(safeObject(item).id || "").trim()).filter(Boolean),
|
|
3188
|
+
evidence_paths: ensureArray(aiResult?.evidenceItems).map((item) => String(safeObject(item).path || "").trim()).filter(Boolean),
|
|
3102
3189
|
reply_chars: String(sanitizedReplyText || "").length,
|
|
3103
3190
|
execution_mode: executionPlan.mode,
|
|
3104
3191
|
role_profile: executionPlan.roleProfileName,
|
|
@@ -3887,6 +3887,8 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
3887
3887
|
let deliveredText = "";
|
|
3888
3888
|
let createWorkItemCalls = 0;
|
|
3889
3889
|
let createThreadCalls = 0;
|
|
3890
|
+
let createEvidenceCalls = 0;
|
|
3891
|
+
let linkEvidenceCalls = 0;
|
|
3890
3892
|
let ctxpackPushCalls = 0;
|
|
3891
3893
|
const workspaceDir = fs.mkdtempSync(path.join(os.tmpdir(), "metheus-runner-selftest-workitems-"));
|
|
3892
3894
|
const processed = await processRunnerSelectedRecord({
|
|
@@ -4063,6 +4065,20 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
4063
4065
|
thread_id: `${workItemID}-thread`,
|
|
4064
4066
|
};
|
|
4065
4067
|
},
|
|
4068
|
+
createProjectEvidence: async ({ uri }) => {
|
|
4069
|
+
createEvidenceCalls += 1;
|
|
4070
|
+
return {
|
|
4071
|
+
id: `evidence-${createEvidenceCalls}`,
|
|
4072
|
+
evidence_id: `evidence-${createEvidenceCalls}`,
|
|
4073
|
+
uri,
|
|
4074
|
+
};
|
|
4075
|
+
},
|
|
4076
|
+
linkWorkItemEvidence: async () => {
|
|
4077
|
+
linkEvidenceCalls += 1;
|
|
4078
|
+
return {
|
|
4079
|
+
linked: true,
|
|
4080
|
+
};
|
|
4081
|
+
},
|
|
4066
4082
|
replaceProjectCtxpackFiles: async ({ artifacts }) => {
|
|
4067
4083
|
ctxpackPushCalls += 1;
|
|
4068
4084
|
return {
|
|
@@ -4106,12 +4122,15 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
4106
4122
|
&& deliveryCalls === 1
|
|
4107
4123
|
&& createWorkItemCalls === 2
|
|
4108
4124
|
&& createThreadCalls === 2
|
|
4125
|
+
&& createEvidenceCalls === 1
|
|
4126
|
+
&& linkEvidenceCalls === 2
|
|
4109
4127
|
&& ctxpackPushCalls === 1
|
|
4110
4128
|
&& ensureArray(processed.result?.work_item_ids).length === 2
|
|
4129
|
+
&& ensureArray(processed.result?.evidence_ids).length === 1
|
|
4111
4130
|
&& ensureArray(processed.result?.executed_role_plan?.created_work_items).length === 2
|
|
4112
4131
|
&& String(processed.result?.ctxpack_version_id || "") === "version-1"
|
|
4113
4132
|
&& /implementation plan/i.test(deliveredText),
|
|
4114
|
-
`kind=${String(processed.kind || "(none)")} delivery_calls=${deliveryCalls} delivered=${deliveredText} created_work_items=${ensureArray(processed.result?.work_item_ids).join(",")} threads=${createThreadCalls} ctxpack_pushes=${ctxpackPushCalls}`,
|
|
4133
|
+
`kind=${String(processed.kind || "(none)")} delivery_calls=${deliveryCalls} delivered=${deliveredText} created_work_items=${ensureArray(processed.result?.work_item_ids).join(",")} evidence_ids=${ensureArray(processed.result?.evidence_ids).join(",")} threads=${createThreadCalls} evidence_links=${linkEvidenceCalls} ctxpack_pushes=${ctxpackPushCalls}`,
|
|
4115
4134
|
);
|
|
4116
4135
|
} catch (err) {
|
|
4117
4136
|
push("single_bot_execution_request_materializes_governance_work_items", false, String(err?.message || err));
|