@h9-foundry/agentforge-cli 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/bin.js +49 -1
- package/dist/bin.js.map +1 -1
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1141 -4
- package/dist/index.js.map +1 -1
- package/dist/internal/builtin-agents.d.ts.map +1 -1
- package/dist/internal/builtin-agents.js +1372 -196
- package/dist/internal/builtin-agents.js.map +1 -1
- package/package.json +8 -8
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { agentManifestSchema, agentOutputSchema, designArtifactSchema, implementationArtifactSchema, implementationInventorySchema, qaArtifactSchema, qaEvidenceNormalizationSchema, qaRequestSchema, securityArtifactSchema, securityEvidenceNormalizationSchema, securityRequestSchema, planningArtifactSchema } from "@h9-foundry/agentforge-schemas";
|
|
3
|
+
import { agentManifestSchema, agentOutputSchema, designArtifactSchema, githubActionsEvidenceSchema, implementationArtifactSchema, implementationInventorySchema, incidentArtifactSchema, incidentEvidenceNormalizationSchema, incidentRequestSchema, maintenanceArtifactSchema, maintenanceEvidenceNormalizationSchema, maintenanceRequestSchema, qaArtifactSchema, qaEvidenceNormalizationSchema, qaRequestSchema, releaseApprovalRecommendationSchema, releaseArtifactSchema, releaseEvidenceNormalizationSchema, releaseRequestSchema, securityArtifactSchema, securityEvidenceNormalizationSchema, securityRequestSchema, planningArtifactSchema } from "@h9-foundry/agentforge-schemas";
|
|
4
4
|
const contextCollectorAgent = {
|
|
5
5
|
manifest: agentManifestSchema.parse({
|
|
6
6
|
version: 1,
|
|
@@ -73,6 +73,32 @@ function parsePackageScripts(packageJsonPath) {
|
|
|
73
73
|
}
|
|
74
74
|
return Object.fromEntries(Object.entries(parsed.scripts).filter((entry) => typeof entry[1] === "string"));
|
|
75
75
|
}
|
|
76
|
+
function resolveWorkspacePackage(root, packageName) {
|
|
77
|
+
if (!root) {
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
80
|
+
for (const topLevel of ["packages", "agents", "adapters"]) {
|
|
81
|
+
const scopeRoot = join(root, topLevel);
|
|
82
|
+
if (!existsSync(scopeRoot)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
for (const entry of readdirSync(scopeRoot)) {
|
|
86
|
+
const manifestPath = join(scopeRoot, entry, "package.json");
|
|
87
|
+
if (!existsSync(manifestPath)) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
91
|
+
if (!isRecord(parsed) || parsed.name !== packageName || typeof parsed.version !== "string") {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
currentVersion: parsed.version,
|
|
96
|
+
manifestPath
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
76
102
|
const allowedValidationScriptNames = new Set(["test", "lint", "typecheck", "build", "build:packages", "release:verify"]);
|
|
77
103
|
function normalizeRequestedCommand(command) {
|
|
78
104
|
return command.trim().replace(/\s+/g, " ");
|
|
@@ -148,6 +174,79 @@ function loadBundleArtifactPayloadPaths(bundlePath) {
|
|
|
148
174
|
return [];
|
|
149
175
|
});
|
|
150
176
|
}
|
|
177
|
+
function loadBundleFinishedAt(bundlePath) {
|
|
178
|
+
if (!existsSync(bundlePath)) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
const parsed = JSON.parse(readFileSync(bundlePath, "utf8"));
|
|
182
|
+
return isRecord(parsed) && typeof parsed.finishedAt === "string" ? parsed.finishedAt : undefined;
|
|
183
|
+
}
|
|
184
|
+
function describeEvidenceObservation(repoRoot, pathValue) {
|
|
185
|
+
if (!repoRoot) {
|
|
186
|
+
return `Observed source ${pathValue} during deterministic intake.`;
|
|
187
|
+
}
|
|
188
|
+
const absolutePath = join(repoRoot, pathValue);
|
|
189
|
+
if (!existsSync(absolutePath)) {
|
|
190
|
+
return `Observed source ${pathValue} during deterministic intake.`;
|
|
191
|
+
}
|
|
192
|
+
const observedAt = pathValue.endsWith(".json") && pathValue.includes(".agentops/runs/")
|
|
193
|
+
? loadBundleFinishedAt(absolutePath)
|
|
194
|
+
: undefined;
|
|
195
|
+
const fallbackObservedAt = observedAt ?? statSync(absolutePath).mtime.toISOString();
|
|
196
|
+
return `Observed source ${pathValue} at ${fallbackObservedAt}.`;
|
|
197
|
+
}
|
|
198
|
+
function loadGitHubActionsEvidence(bundlePath) {
|
|
199
|
+
if (!existsSync(bundlePath) || !bundlePath.endsWith(".json")) {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
const parsed = JSON.parse(readFileSync(bundlePath, "utf8"));
|
|
203
|
+
const candidate = isRecord(parsed) ? { ...parsed, sourcePath: parsed.sourcePath ?? bundlePath } : parsed;
|
|
204
|
+
const result = githubActionsEvidenceSchema.safeParse(candidate);
|
|
205
|
+
return result.success ? result.data : undefined;
|
|
206
|
+
}
|
|
207
|
+
function isFailingGitHubActionsConclusion(conclusion) {
|
|
208
|
+
return Boolean(conclusion && !["success", "neutral", "skipped"].includes(conclusion));
|
|
209
|
+
}
|
|
210
|
+
function summarizeGitHubActionsFailures(evidence) {
|
|
211
|
+
const failedJobs = evidence.jobs
|
|
212
|
+
.filter((job) => job.status === "completed" && isFailingGitHubActionsConclusion(job.conclusion))
|
|
213
|
+
.map((job) => `${evidence.workflowName} / ${job.name}`);
|
|
214
|
+
const failedCheckRuns = evidence.checkRuns
|
|
215
|
+
.filter((checkRun) => checkRun.status === "completed" && isFailingGitHubActionsConclusion(checkRun.conclusion))
|
|
216
|
+
.map((checkRun) => `${evidence.workflowName} / ${checkRun.name}`);
|
|
217
|
+
const runLevelFailure = failedJobs.length === 0 &&
|
|
218
|
+
failedCheckRuns.length === 0 &&
|
|
219
|
+
evidence.status === "completed" &&
|
|
220
|
+
isFailingGitHubActionsConclusion(evidence.conclusion)
|
|
221
|
+
? [`${evidence.workflowName} / workflow-run`]
|
|
222
|
+
: [];
|
|
223
|
+
return [...failedJobs, ...failedCheckRuns, ...runLevelFailure];
|
|
224
|
+
}
|
|
225
|
+
function normalizeGitHubActionsEvidence(repoRoot, evidenceSources) {
|
|
226
|
+
const evidence = evidenceSources.flatMap((pathValue) => {
|
|
227
|
+
if (!repoRoot) {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
const normalized = loadGitHubActionsEvidence(join(repoRoot, pathValue));
|
|
231
|
+
return normalized ? [normalized] : [];
|
|
232
|
+
});
|
|
233
|
+
const workflowNames = [...new Set(evidence.map((entry) => entry.workflowName))];
|
|
234
|
+
const failingChecks = [...new Set(evidence.flatMap((entry) => summarizeGitHubActionsFailures(entry)))];
|
|
235
|
+
const provenanceRefs = [
|
|
236
|
+
...new Set(evidence.flatMap((entry) => [
|
|
237
|
+
entry.sourcePath,
|
|
238
|
+
entry.htmlUrl,
|
|
239
|
+
...entry.jobs.map((job) => job.htmlUrl),
|
|
240
|
+
...entry.checkRuns.map((checkRun) => checkRun.detailsUrl)
|
|
241
|
+
].filter((value) => Boolean(value))))
|
|
242
|
+
];
|
|
243
|
+
return {
|
|
244
|
+
evidence,
|
|
245
|
+
workflowNames,
|
|
246
|
+
failingChecks,
|
|
247
|
+
provenanceRefs
|
|
248
|
+
};
|
|
249
|
+
}
|
|
151
250
|
function derivePackageScope(pathValue) {
|
|
152
251
|
const segments = pathValue.split("/").filter(Boolean);
|
|
153
252
|
if (segments.length < 2) {
|
|
@@ -159,13 +258,17 @@ function derivePackageScope(pathValue) {
|
|
|
159
258
|
}
|
|
160
259
|
return undefined;
|
|
161
260
|
}
|
|
261
|
+
function includesAnyKeyword(values, keywords) {
|
|
262
|
+
const haystack = values.join(" ").toLowerCase();
|
|
263
|
+
return keywords.some((keyword) => haystack.includes(keyword));
|
|
264
|
+
}
|
|
162
265
|
function getWorkflowInput(stateSlice, key) {
|
|
163
266
|
if (!isRecord(stateSlice.workflowInputs)) {
|
|
164
267
|
return undefined;
|
|
165
268
|
}
|
|
166
269
|
return stateSlice.workflowInputs[key];
|
|
167
270
|
}
|
|
168
|
-
function buildLifecycleArtifactEnvelopeBase(state, displayName, summary, inputRefs, issueRefs = []) {
|
|
271
|
+
function buildLifecycleArtifactEnvelopeBase(state, displayName, summary, inputRefs, issueRefs = [], githubRefs = []) {
|
|
169
272
|
return {
|
|
170
273
|
schemaVersion: state.version,
|
|
171
274
|
workflow: {
|
|
@@ -176,7 +279,8 @@ function buildLifecycleArtifactEnvelopeBase(state, displayName, summary, inputRe
|
|
|
176
279
|
sourceType: "workflow-run",
|
|
177
280
|
runId: state.runId,
|
|
178
281
|
inputRefs: [...inputRefs],
|
|
179
|
-
issueRefs: [...issueRefs]
|
|
282
|
+
issueRefs: [...issueRefs],
|
|
283
|
+
githubRefs: [...githubRefs]
|
|
180
284
|
},
|
|
181
285
|
status: "complete",
|
|
182
286
|
generatedAt: new Date().toISOString(),
|
|
@@ -204,7 +308,7 @@ function buildLifecycleArtifactEnvelopeBase(state, displayName, summary, inputRe
|
|
|
204
308
|
summary
|
|
205
309
|
};
|
|
206
310
|
}
|
|
207
|
-
function buildArtifactEnvelopeBase(state, summary, inputRefs, issueRefs) {
|
|
311
|
+
function buildArtifactEnvelopeBase(state, summary, inputRefs, issueRefs, githubRefs = []) {
|
|
208
312
|
return {
|
|
209
313
|
schemaVersion: state.version,
|
|
210
314
|
workflow: {
|
|
@@ -214,7 +318,8 @@ function buildArtifactEnvelopeBase(state, summary, inputRefs, issueRefs) {
|
|
|
214
318
|
sourceType: "workflow-run",
|
|
215
319
|
runId: state.runId,
|
|
216
320
|
inputRefs: [...inputRefs],
|
|
217
|
-
issueRefs: [...issueRefs]
|
|
321
|
+
issueRefs: [...issueRefs],
|
|
322
|
+
githubRefs: [...githubRefs]
|
|
218
323
|
},
|
|
219
324
|
status: "complete",
|
|
220
325
|
generatedAt: new Date().toISOString(),
|
|
@@ -340,6 +445,7 @@ const planningAnalystAgent = {
|
|
|
340
445
|
outputSchema: agentOutputSchema,
|
|
341
446
|
async execute({ state, stateSlice }) {
|
|
342
447
|
const planningRequest = getWorkflowInput(stateSlice, "planningRequest");
|
|
448
|
+
const planningGithubRefs = getWorkflowInput(stateSlice, "planningGithubRefs") ?? [];
|
|
343
449
|
const requestFile = getWorkflowInput(stateSlice, "requestFile");
|
|
344
450
|
if (!planningRequest) {
|
|
345
451
|
throw new Error("planning-discovery requires a validated planning request before planning analysis.");
|
|
@@ -363,7 +469,7 @@ const planningAnalystAgent = {
|
|
|
363
469
|
];
|
|
364
470
|
const summary = `Planning brief scoped ${objectives.length} objective(s) for ${state.repo.name}.`;
|
|
365
471
|
const planningBrief = planningArtifactSchema.parse({
|
|
366
|
-
...buildArtifactEnvelopeBase(state, summary, [requestFile ?? ".agentops/requests/planning.yaml"], planningRequest.issueRefs),
|
|
472
|
+
...buildArtifactEnvelopeBase(state, summary, [requestFile ?? ".agentops/requests/planning.yaml"], planningRequest.issueRefs, planningGithubRefs),
|
|
367
473
|
artifactKind: "planning-brief",
|
|
368
474
|
lifecycleDomain: "plan",
|
|
369
475
|
workflow: {
|
|
@@ -759,12 +865,12 @@ const securityIntakeAgent = {
|
|
|
759
865
|
});
|
|
760
866
|
}
|
|
761
867
|
};
|
|
762
|
-
const
|
|
868
|
+
const incidentIntakeAgent = {
|
|
763
869
|
manifest: agentManifestSchema.parse({
|
|
764
870
|
version: 1,
|
|
765
|
-
name: "
|
|
766
|
-
displayName: "
|
|
767
|
-
category: "
|
|
871
|
+
name: "incident-intake",
|
|
872
|
+
displayName: "Incident Intake",
|
|
873
|
+
category: "operate",
|
|
768
874
|
runtime: {
|
|
769
875
|
minVersion: "0.1.0",
|
|
770
876
|
kind: "deterministic"
|
|
@@ -773,7 +879,66 @@ const securityEvidenceNormalizationAgent = {
|
|
|
773
879
|
model: false,
|
|
774
880
|
network: false,
|
|
775
881
|
tools: [],
|
|
776
|
-
readPaths: [".agentops/requests/**", ".agentops/runs/**", "**/*.json", "**/*.
|
|
882
|
+
readPaths: [".agentops/requests/**", ".agentops/runs/**", "**/*.json", "**/*.log", "**/*.md"],
|
|
883
|
+
writePaths: []
|
|
884
|
+
},
|
|
885
|
+
inputs: ["workflowInputs", "repo"],
|
|
886
|
+
outputs: ["summary", "metadata"],
|
|
887
|
+
contextPolicy: {
|
|
888
|
+
sections: ["workflowInputs", "repo", "context"],
|
|
889
|
+
minimalContext: true
|
|
890
|
+
},
|
|
891
|
+
catalog: {
|
|
892
|
+
domain: "operate",
|
|
893
|
+
supportLevel: "internal",
|
|
894
|
+
maturity: "mvp",
|
|
895
|
+
trustScope: "official-core-only"
|
|
896
|
+
},
|
|
897
|
+
trust: {
|
|
898
|
+
tier: "core",
|
|
899
|
+
source: "official",
|
|
900
|
+
reviewed: true
|
|
901
|
+
}
|
|
902
|
+
}),
|
|
903
|
+
outputSchema: agentOutputSchema,
|
|
904
|
+
async execute({ stateSlice }) {
|
|
905
|
+
const incidentRequest = getWorkflowInput(stateSlice, "incidentRequest");
|
|
906
|
+
const requestFile = getWorkflowInput(stateSlice, "requestFile");
|
|
907
|
+
if (!incidentRequest) {
|
|
908
|
+
throw new Error("incident-handoff requires a validated incident request before runtime execution.");
|
|
909
|
+
}
|
|
910
|
+
return agentOutputSchema.parse({
|
|
911
|
+
summary: `Loaded incident request from ${requestFile ?? ".agentops/requests/incident.yaml"} for ${incidentRequest.incidentSummary}.`,
|
|
912
|
+
findings: [],
|
|
913
|
+
proposedActions: [],
|
|
914
|
+
lifecycleArtifacts: [],
|
|
915
|
+
requestedTools: [],
|
|
916
|
+
blockedActionFlags: [],
|
|
917
|
+
metadata: {
|
|
918
|
+
...incidentRequestSchema.parse({
|
|
919
|
+
...incidentRequest,
|
|
920
|
+
evidenceSources: [...new Set(incidentRequest.evidenceSources)]
|
|
921
|
+
}),
|
|
922
|
+
evidenceSourceCount: incidentRequest.evidenceSources.length + incidentRequest.releaseReportRefs.length
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
const incidentEvidenceNormalizationAgent = {
|
|
928
|
+
manifest: agentManifestSchema.parse({
|
|
929
|
+
version: 1,
|
|
930
|
+
name: "incident-evidence-normalizer",
|
|
931
|
+
displayName: "Incident Evidence Normalizer",
|
|
932
|
+
category: "operate",
|
|
933
|
+
runtime: {
|
|
934
|
+
minVersion: "0.1.0",
|
|
935
|
+
kind: "deterministic"
|
|
936
|
+
},
|
|
937
|
+
permissions: {
|
|
938
|
+
model: false,
|
|
939
|
+
network: false,
|
|
940
|
+
tools: [],
|
|
941
|
+
readPaths: [".agentops/requests/**", ".agentops/runs/**", "**/*.json", "**/*.log", "**/*.md", "**/*.txt"],
|
|
777
942
|
writePaths: []
|
|
778
943
|
},
|
|
779
944
|
inputs: ["workflowInputs", "repo", "agentResults"],
|
|
@@ -783,7 +948,7 @@ const securityEvidenceNormalizationAgent = {
|
|
|
783
948
|
minimalContext: true
|
|
784
949
|
},
|
|
785
950
|
catalog: {
|
|
786
|
-
domain: "
|
|
951
|
+
domain: "operate",
|
|
787
952
|
supportLevel: "internal",
|
|
788
953
|
maturity: "mvp",
|
|
789
954
|
trustScope: "official-core-only"
|
|
@@ -796,53 +961,60 @@ const securityEvidenceNormalizationAgent = {
|
|
|
796
961
|
}),
|
|
797
962
|
outputSchema: agentOutputSchema,
|
|
798
963
|
async execute({ stateSlice }) {
|
|
799
|
-
const
|
|
800
|
-
if (!
|
|
801
|
-
throw new Error("
|
|
964
|
+
const incidentRequest = getWorkflowInput(stateSlice, "incidentRequest");
|
|
965
|
+
if (!incidentRequest) {
|
|
966
|
+
throw new Error("incident-handoff requires validated incident request inputs before evidence normalization.");
|
|
802
967
|
}
|
|
803
968
|
const repoRoot = stateSlice.repo?.root;
|
|
804
969
|
const intakeMetadata = isRecord(stateSlice.agentResults?.intake?.metadata) ? stateSlice.agentResults.intake.metadata : {};
|
|
805
|
-
const
|
|
806
|
-
?
|
|
807
|
-
:
|
|
808
|
-
const
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
const
|
|
813
|
-
const normalizedEvidenceSources = [...new Set([securityRequest.targetRef, ...securityRequest.evidenceSources])];
|
|
970
|
+
const releaseReportRefs = asStringArray(intakeMetadata.releaseReportRefs).length > 0
|
|
971
|
+
? asStringArray(intakeMetadata.releaseReportRefs)
|
|
972
|
+
: incidentRequest.releaseReportRefs;
|
|
973
|
+
const evidenceSources = asStringArray(intakeMetadata.evidenceSources).length > 0
|
|
974
|
+
? asStringArray(intakeMetadata.evidenceSources)
|
|
975
|
+
: incidentRequest.evidenceSources;
|
|
976
|
+
const severityHint = typeof intakeMetadata.severityHint === "string" ? intakeMetadata.severityHint : incidentRequest.severityHint;
|
|
977
|
+
const normalizedEvidenceSources = [...new Set([...evidenceSources, ...releaseReportRefs])];
|
|
814
978
|
const missingEvidenceSources = normalizedEvidenceSources.filter((pathValue) => repoRoot && !existsSync(join(repoRoot, pathValue)));
|
|
815
979
|
if (missingEvidenceSources.length > 0) {
|
|
816
|
-
throw new Error(`
|
|
980
|
+
throw new Error(`Incident evidence source not found: ${missingEvidenceSources[0]}`);
|
|
817
981
|
}
|
|
818
|
-
const
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
...(referencedArtifactKinds.length > 0 ? [`Referenced artifact kinds: ${referencedArtifactKinds.join(", ")}`] : []),
|
|
824
|
-
...(affectedPackages.length > 0 ? [`Affected packages inferred from bounded artifact payloads: ${affectedPackages.join(", ")}`] : []),
|
|
825
|
-
...(normalizedFocusAreas.length > 0 ? [`Requested focus areas: ${normalizedFocusAreas.join(", ")}`] : []),
|
|
826
|
-
"Security evidence collection remains local, read-only, and bounded to validated references."
|
|
982
|
+
const referencedArtifactKinds = [...new Set(releaseReportRefs.flatMap((pathValue) => (repoRoot ? loadBundleArtifactKinds(join(repoRoot, pathValue)) : [])))];
|
|
983
|
+
const timelineSummary = [
|
|
984
|
+
`Severity hint: ${severityHint}.`,
|
|
985
|
+
"Normalized staged incident evidence and release-report references before reasoning.",
|
|
986
|
+
...normalizedEvidenceSources.map((pathValue) => describeEvidenceObservation(repoRoot, pathValue))
|
|
827
987
|
];
|
|
828
|
-
const
|
|
829
|
-
|
|
830
|
-
...
|
|
831
|
-
...
|
|
988
|
+
const likelyImpactedAreas = [
|
|
989
|
+
...(releaseReportRefs.length > 0 ? ["release-readiness"] : []),
|
|
990
|
+
...(evidenceSources.length > 0 ? ["staged-operational-evidence"] : []),
|
|
991
|
+
...(severityHint === "high" || severityHint === "critical" ? ["security-follow-up"] : [])
|
|
832
992
|
];
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
993
|
+
const followUpWorkflowRefs = [
|
|
994
|
+
"maintenance-triage",
|
|
995
|
+
...(releaseReportRefs.length > 0 ? ["release-readiness"] : []),
|
|
996
|
+
...(severityHint === "high" || severityHint === "critical" ? ["security-review"] : [])
|
|
997
|
+
];
|
|
998
|
+
const normalization = incidentEvidenceNormalizationSchema.parse({
|
|
999
|
+
incidentSummary: incidentRequest.incidentSummary,
|
|
1000
|
+
severityHint,
|
|
837
1001
|
normalizedEvidenceSources,
|
|
838
1002
|
missingEvidenceSources: [],
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
1003
|
+
releaseReportRefs,
|
|
1004
|
+
timelineSummary,
|
|
1005
|
+
likelyImpactedAreas: [...new Set(likelyImpactedAreas)],
|
|
1006
|
+
followUpWorkflowRefs: [...new Set(followUpWorkflowRefs)],
|
|
1007
|
+
provenanceRefs: [
|
|
1008
|
+
...new Set([
|
|
1009
|
+
...evidenceSources,
|
|
1010
|
+
...releaseReportRefs.map((pathValue) => `${pathValue}#release-report`)
|
|
1011
|
+
])
|
|
1012
|
+
],
|
|
1013
|
+
redactionCategories: ["github-token", "api-key", "aws-key", "bearer-token", "password", "private-key", "operational-sensitive"],
|
|
1014
|
+
referencedArtifactKinds
|
|
843
1015
|
});
|
|
844
1016
|
return agentOutputSchema.parse({
|
|
845
|
-
summary: `Normalized
|
|
1017
|
+
summary: `Normalized incident evidence across ${normalization.normalizedEvidenceSources.length} staged source(s).`,
|
|
846
1018
|
findings: [],
|
|
847
1019
|
proposedActions: [],
|
|
848
1020
|
lifecycleArtifacts: [],
|
|
@@ -852,31 +1024,31 @@ const securityEvidenceNormalizationAgent = {
|
|
|
852
1024
|
});
|
|
853
1025
|
}
|
|
854
1026
|
};
|
|
855
|
-
const
|
|
1027
|
+
const maintenanceIntakeAgent = {
|
|
856
1028
|
manifest: agentManifestSchema.parse({
|
|
857
1029
|
version: 1,
|
|
858
|
-
name: "
|
|
859
|
-
displayName: "
|
|
860
|
-
category: "
|
|
1030
|
+
name: "maintenance-intake",
|
|
1031
|
+
displayName: "Maintenance Intake",
|
|
1032
|
+
category: "maintain",
|
|
861
1033
|
runtime: {
|
|
862
1034
|
minVersion: "0.1.0",
|
|
863
|
-
kind: "
|
|
1035
|
+
kind: "deterministic"
|
|
864
1036
|
},
|
|
865
1037
|
permissions: {
|
|
866
|
-
model:
|
|
1038
|
+
model: false,
|
|
867
1039
|
network: false,
|
|
868
1040
|
tools: [],
|
|
869
|
-
readPaths: ["
|
|
1041
|
+
readPaths: [".agentops/requests/**", ".agentops/runs/**", "**/*.json", "**/*.md", "**/*.txt"],
|
|
870
1042
|
writePaths: []
|
|
871
1043
|
},
|
|
872
|
-
inputs: ["workflowInputs", "repo"
|
|
873
|
-
outputs: ["
|
|
1044
|
+
inputs: ["workflowInputs", "repo"],
|
|
1045
|
+
outputs: ["summary", "metadata"],
|
|
874
1046
|
contextPolicy: {
|
|
875
|
-
sections: ["workflowInputs", "repo", "
|
|
1047
|
+
sections: ["workflowInputs", "repo", "context"],
|
|
876
1048
|
minimalContext: true
|
|
877
1049
|
},
|
|
878
1050
|
catalog: {
|
|
879
|
-
domain: "
|
|
1051
|
+
domain: "maintain",
|
|
880
1052
|
supportLevel: "internal",
|
|
881
1053
|
maturity: "mvp",
|
|
882
1054
|
trustScope: "official-core-only"
|
|
@@ -888,120 +1060,44 @@ const securityAnalystAgent = {
|
|
|
888
1060
|
}
|
|
889
1061
|
}),
|
|
890
1062
|
outputSchema: agentOutputSchema,
|
|
891
|
-
async execute({
|
|
892
|
-
const
|
|
1063
|
+
async execute({ stateSlice }) {
|
|
1064
|
+
const maintenanceRequest = getWorkflowInput(stateSlice, "maintenanceRequest");
|
|
893
1065
|
const requestFile = getWorkflowInput(stateSlice, "requestFile");
|
|
894
|
-
|
|
895
|
-
|
|
1066
|
+
const maintenanceIssueRefs = getWorkflowInput(stateSlice, "maintenanceIssueRefs") ?? [];
|
|
1067
|
+
const maintenanceGithubRefs = getWorkflowInput(stateSlice, "maintenanceGithubRefs") ?? [];
|
|
1068
|
+
if (!maintenanceRequest) {
|
|
1069
|
+
throw new Error("maintenance-triage requires a validated maintenance request before runtime execution.");
|
|
896
1070
|
}
|
|
897
|
-
const intakeMetadata = isRecord(stateSlice.agentResults?.intake?.metadata) ? stateSlice.agentResults.intake.metadata : {};
|
|
898
|
-
const evidenceMetadata = securityEvidenceNormalizationSchema.safeParse(stateSlice.agentResults?.evidence?.metadata);
|
|
899
|
-
const normalizedEvidence = evidenceMetadata.success ? evidenceMetadata.data : undefined;
|
|
900
|
-
const referencedArtifactKinds = normalizedEvidence?.referencedArtifactKinds ?? asStringArray(intakeMetadata.referencedArtifactKinds);
|
|
901
|
-
const normalizedFocusAreas = normalizedEvidence?.normalizedFocusAreas ?? asStringArray(intakeMetadata.focusAreas);
|
|
902
|
-
const normalizedConstraints = asStringArray(intakeMetadata.constraints);
|
|
903
|
-
const evidenceSources = normalizedEvidence?.normalizedEvidenceSources && normalizedEvidence.normalizedEvidenceSources.length > 0
|
|
904
|
-
? normalizedEvidence.normalizedEvidenceSources
|
|
905
|
-
: asStringArray(intakeMetadata.evidenceSources).length > 0
|
|
906
|
-
? asStringArray(intakeMetadata.evidenceSources)
|
|
907
|
-
: [...new Set([securityRequest.targetRef, ...securityRequest.evidenceSources])];
|
|
908
|
-
const focusAreas = normalizedFocusAreas.length > 0 ? normalizedFocusAreas : securityRequest.focusAreas;
|
|
909
|
-
const inferredSeverity = securityRequest.releaseContext === "blocking" ? "high" : securityRequest.releaseContext === "candidate" ? "medium" : "low";
|
|
910
|
-
const findings = focusAreas.length > 0
|
|
911
|
-
? focusAreas.map((focusArea, index) => ({
|
|
912
|
-
id: `security-finding-${index + 1}`,
|
|
913
|
-
title: `Inspect ${focusArea} evidence before promotion`,
|
|
914
|
-
summary: `Security review flagged ${focusArea} for bounded follow-up on ${securityRequest.targetRef}.`,
|
|
915
|
-
severity: inferredSeverity,
|
|
916
|
-
rationale: "The MVP security workflow synthesizes a structured report from validated references before deterministic evidence normalization lands.",
|
|
917
|
-
confidence: 0.76,
|
|
918
|
-
location: securityRequest.targetRef,
|
|
919
|
-
tags: ["security", focusArea]
|
|
920
|
-
}))
|
|
921
|
-
: [
|
|
922
|
-
{
|
|
923
|
-
id: "security-finding-1",
|
|
924
|
-
title: "Inspect referenced security evidence before promotion",
|
|
925
|
-
summary: `Security review requires bounded interpretation of the referenced evidence for ${securityRequest.targetRef}.`,
|
|
926
|
-
severity: inferredSeverity,
|
|
927
|
-
rationale: "The current security workflow is read-only and request-driven, so findings remain tied to validated local references rather than automatic scanning.",
|
|
928
|
-
confidence: 0.72,
|
|
929
|
-
location: securityRequest.targetRef,
|
|
930
|
-
tags: ["security", "evidence"]
|
|
931
|
-
}
|
|
932
|
-
];
|
|
933
|
-
const mitigations = [
|
|
934
|
-
...focusAreas.map((focusArea) => `Review ${focusArea} evidence and document the release impact before promotion.`),
|
|
935
|
-
...(normalizedConstraints.length > 0 ? [`Keep security follow-up bounded by: ${normalizedConstraints.join("; ")}.`] : [])
|
|
936
|
-
];
|
|
937
|
-
const followUpWork = [
|
|
938
|
-
...(normalizedEvidence?.securitySignals ?? []),
|
|
939
|
-
...(referencedArtifactKinds.length > 0
|
|
940
|
-
? [`Confirm the security posture for referenced artifacts: ${referencedArtifactKinds.join(", ")}.`]
|
|
941
|
-
: []),
|
|
942
|
-
"Use deterministic security evidence normalization outputs before broadening the workflow surface."
|
|
943
|
-
];
|
|
944
|
-
const summary = `Security report prepared for ${securityRequest.targetRef}.`;
|
|
945
|
-
const securityReport = securityArtifactSchema.parse({
|
|
946
|
-
...buildLifecycleArtifactEnvelopeBase(state, "Security Review", summary, [
|
|
947
|
-
requestFile ?? ".agentops/requests/security.yaml",
|
|
948
|
-
...(normalizedEvidence?.provenanceRefs ?? [securityRequest.targetRef, ...securityRequest.evidenceSources])
|
|
949
|
-
]),
|
|
950
|
-
artifactKind: "security-report",
|
|
951
|
-
lifecycleDomain: "security",
|
|
952
|
-
redaction: {
|
|
953
|
-
applied: true,
|
|
954
|
-
strategyVersion: "1.0.0",
|
|
955
|
-
categories: ["github-token", "api-key", "aws-key", "bearer-token", "password", "private-key", "security-sensitive"]
|
|
956
|
-
},
|
|
957
|
-
payload: {
|
|
958
|
-
targetRef: securityRequest.targetRef,
|
|
959
|
-
evidenceSources,
|
|
960
|
-
findings,
|
|
961
|
-
severitySummary: `highest severity: ${inferredSeverity}; ${findings.length} synthesized security finding(s).`,
|
|
962
|
-
mitigations: mitigations.length > 0
|
|
963
|
-
? mitigations
|
|
964
|
-
: ["Review the referenced security evidence before promoting this workflow output."],
|
|
965
|
-
releaseImpact: securityRequest.releaseContext === "blocking"
|
|
966
|
-
? "release-blocking security findings require resolution before promotion."
|
|
967
|
-
: securityRequest.releaseContext === "candidate"
|
|
968
|
-
? "candidate release requires explicit security review before promotion."
|
|
969
|
-
: "no release context was supplied; security output remains advisory.",
|
|
970
|
-
followUpWork
|
|
971
|
-
}
|
|
972
|
-
});
|
|
973
1071
|
return agentOutputSchema.parse({
|
|
974
|
-
summary
|
|
1072
|
+
summary: `Loaded maintenance request from ${requestFile ?? ".agentops/requests/maintenance.yaml"} for ${maintenanceRequest.maintenanceGoal}.`,
|
|
975
1073
|
findings: [],
|
|
976
1074
|
proposedActions: [],
|
|
977
|
-
lifecycleArtifacts: [
|
|
1075
|
+
lifecycleArtifacts: [],
|
|
978
1076
|
requestedTools: [],
|
|
979
1077
|
blockedActionFlags: [],
|
|
980
|
-
confidence: 0.76,
|
|
981
1078
|
metadata: {
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
}
|
|
1079
|
+
...maintenanceRequestSchema.parse({
|
|
1080
|
+
...maintenanceRequest,
|
|
1081
|
+
dependencyAlertRefs: [...new Set(maintenanceRequest.dependencyAlertRefs)],
|
|
1082
|
+
docsTaskRefs: [...new Set(maintenanceRequest.docsTaskRefs)],
|
|
1083
|
+
releaseReportRefs: [...new Set(maintenanceRequest.releaseReportRefs)],
|
|
1084
|
+
issueRefs: [...new Set(maintenanceRequest.issueRefs)]
|
|
1085
|
+
}),
|
|
1086
|
+
maintenanceIssueRefs,
|
|
1087
|
+
maintenanceGithubRefs,
|
|
1088
|
+
evidenceSourceCount: maintenanceRequest.dependencyAlertRefs.length +
|
|
1089
|
+
maintenanceRequest.docsTaskRefs.length +
|
|
1090
|
+
maintenanceRequest.releaseReportRefs.length
|
|
995
1091
|
}
|
|
996
1092
|
});
|
|
997
1093
|
}
|
|
998
1094
|
};
|
|
999
|
-
const
|
|
1095
|
+
const maintenanceEvidenceNormalizerAgent = {
|
|
1000
1096
|
manifest: agentManifestSchema.parse({
|
|
1001
1097
|
version: 1,
|
|
1002
|
-
name: "
|
|
1003
|
-
displayName: "
|
|
1004
|
-
category: "
|
|
1098
|
+
name: "maintenance-evidence-normalizer",
|
|
1099
|
+
displayName: "Maintenance Evidence Normalizer",
|
|
1100
|
+
category: "maintain",
|
|
1005
1101
|
runtime: {
|
|
1006
1102
|
minVersion: "0.1.0",
|
|
1007
1103
|
kind: "deterministic"
|
|
@@ -1010,7 +1106,7 @@ const qaEvidenceNormalizationAgent = {
|
|
|
1010
1106
|
model: false,
|
|
1011
1107
|
network: false,
|
|
1012
1108
|
tools: [],
|
|
1013
|
-
readPaths: [".agentops/requests/**", ".agentops/runs/**", "
|
|
1109
|
+
readPaths: [".agentops/requests/**", ".agentops/runs/**", "**/*.json", "**/*.md", "**/*.txt", "**/package.json"],
|
|
1014
1110
|
writePaths: []
|
|
1015
1111
|
},
|
|
1016
1112
|
inputs: ["workflowInputs", "repo", "agentResults"],
|
|
@@ -1020,7 +1116,7 @@ const qaEvidenceNormalizationAgent = {
|
|
|
1020
1116
|
minimalContext: true
|
|
1021
1117
|
},
|
|
1022
1118
|
catalog: {
|
|
1023
|
-
domain: "
|
|
1119
|
+
domain: "maintain",
|
|
1024
1120
|
supportLevel: "internal",
|
|
1025
1121
|
maturity: "mvp",
|
|
1026
1122
|
trustScope: "official-core-only"
|
|
@@ -1033,28 +1129,1080 @@ const qaEvidenceNormalizationAgent = {
|
|
|
1033
1129
|
}),
|
|
1034
1130
|
outputSchema: agentOutputSchema,
|
|
1035
1131
|
async execute({ stateSlice }) {
|
|
1036
|
-
const
|
|
1037
|
-
if (!
|
|
1038
|
-
throw new Error("
|
|
1132
|
+
const maintenanceRequest = getWorkflowInput(stateSlice, "maintenanceRequest");
|
|
1133
|
+
if (!maintenanceRequest) {
|
|
1134
|
+
throw new Error("maintenance-triage requires validated maintenance inputs before evidence normalization.");
|
|
1039
1135
|
}
|
|
1040
1136
|
const repoRoot = stateSlice.repo?.root;
|
|
1041
|
-
const packageManager = stateSlice.repo?.packageManager || "pnpm";
|
|
1042
1137
|
const intakeMetadata = isRecord(stateSlice.agentResults?.intake?.metadata) ? stateSlice.agentResults.intake.metadata : {};
|
|
1043
|
-
const
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
const
|
|
1138
|
+
const dependencyAlertRefs = asStringArray(intakeMetadata.dependencyAlertRefs).length > 0
|
|
1139
|
+
? asStringArray(intakeMetadata.dependencyAlertRefs)
|
|
1140
|
+
: maintenanceRequest.dependencyAlertRefs;
|
|
1141
|
+
const docsTaskRefs = asStringArray(intakeMetadata.docsTaskRefs).length > 0
|
|
1142
|
+
? asStringArray(intakeMetadata.docsTaskRefs)
|
|
1143
|
+
: maintenanceRequest.docsTaskRefs;
|
|
1144
|
+
const releaseReportRefs = asStringArray(intakeMetadata.releaseReportRefs).length > 0
|
|
1145
|
+
? asStringArray(intakeMetadata.releaseReportRefs)
|
|
1146
|
+
: maintenanceRequest.releaseReportRefs;
|
|
1147
|
+
const normalizedEvidenceSources = [...new Set([...dependencyAlertRefs, ...docsTaskRefs, ...releaseReportRefs])];
|
|
1050
1148
|
const missingEvidenceSources = normalizedEvidenceSources.filter((pathValue) => repoRoot && !existsSync(join(repoRoot, pathValue)));
|
|
1051
1149
|
if (missingEvidenceSources.length > 0) {
|
|
1052
|
-
throw new Error(`
|
|
1150
|
+
throw new Error(`Maintenance evidence source not found: ${missingEvidenceSources[0]}`);
|
|
1053
1151
|
}
|
|
1054
|
-
const
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1152
|
+
const referencedArtifactKinds = [
|
|
1153
|
+
...new Set(releaseReportRefs.flatMap((pathValue) => (repoRoot ? loadBundleArtifactKinds(join(repoRoot, pathValue)) : [])))
|
|
1154
|
+
];
|
|
1155
|
+
const releasePayloadPaths = releaseReportRefs.flatMap((pathValue) => (repoRoot ? loadBundleArtifactPayloadPaths(join(repoRoot, pathValue)) : []));
|
|
1156
|
+
const affectedPackagesOrDocs = [
|
|
1157
|
+
...new Set([...docsTaskRefs, ...releasePayloadPaths]
|
|
1158
|
+
.map((pathValue) => derivePackageScope(pathValue) ?? pathValue)
|
|
1159
|
+
.filter((value) => Boolean(value)))
|
|
1160
|
+
];
|
|
1161
|
+
const maintenanceSignals = [
|
|
1162
|
+
...normalizedEvidenceSources.map((pathValue) => describeEvidenceObservation(repoRoot, pathValue)),
|
|
1163
|
+
...(dependencyAlertRefs.length > 0 ? ["Dependency alert references contribute bounded maintenance follow-up context."] : []),
|
|
1164
|
+
...(docsTaskRefs.length > 0 ? ["Documentation task references contribute bounded maintenance follow-up context."] : []),
|
|
1165
|
+
...(releaseReportRefs.length > 0 ? ["Release report references contribute bounded maintenance follow-up context."] : []),
|
|
1166
|
+
...(referencedArtifactKinds.length > 0 ? [`Referenced artifact kinds: ${referencedArtifactKinds.join(", ")}`] : [])
|
|
1167
|
+
];
|
|
1168
|
+
const routingInputs = [
|
|
1169
|
+
maintenanceRequest.maintenanceGoal,
|
|
1170
|
+
...dependencyAlertRefs,
|
|
1171
|
+
...docsTaskRefs,
|
|
1172
|
+
...releaseReportRefs,
|
|
1173
|
+
...maintenanceSignals
|
|
1174
|
+
];
|
|
1175
|
+
const securitySignal = referencedArtifactKinds.includes("security-report") ||
|
|
1176
|
+
includesAnyKeyword(routingInputs, ["security", "vulnerability", "vuln", "cve", "advisory"]);
|
|
1177
|
+
const qaSignal = referencedArtifactKinds.includes("qa-report") ||
|
|
1178
|
+
includesAnyKeyword(routingInputs, ["qa", "test", "coverage", "flaky"]);
|
|
1179
|
+
const followUpWorkflowRefs = [
|
|
1180
|
+
...new Set([
|
|
1181
|
+
...(securitySignal ? ["security-review"] : []),
|
|
1182
|
+
...(dependencyAlertRefs.length > 0 || docsTaskRefs.length > 0 ? ["implementation-proposal"] : []),
|
|
1183
|
+
...(releaseReportRefs.length > 0 ? ["release-readiness"] : []),
|
|
1184
|
+
...(qaSignal ? ["qa-review"] : [])
|
|
1185
|
+
])
|
|
1186
|
+
];
|
|
1187
|
+
const routingRecommendation = followUpWorkflowRefs[0] ?? "implementation-proposal";
|
|
1188
|
+
const provenanceRefs = [
|
|
1189
|
+
...new Set([
|
|
1190
|
+
...dependencyAlertRefs,
|
|
1191
|
+
...docsTaskRefs,
|
|
1192
|
+
...releaseReportRefs.map((pathValue) => `${pathValue}#release-report`)
|
|
1193
|
+
])
|
|
1194
|
+
];
|
|
1195
|
+
const normalization = maintenanceEvidenceNormalizationSchema.parse({
|
|
1196
|
+
maintenanceGoal: maintenanceRequest.maintenanceGoal,
|
|
1197
|
+
dependencyAlertRefs,
|
|
1198
|
+
docsTaskRefs,
|
|
1199
|
+
releaseReportRefs,
|
|
1200
|
+
normalizedEvidenceSources,
|
|
1201
|
+
missingEvidenceSources: [],
|
|
1202
|
+
referencedArtifactKinds,
|
|
1203
|
+
affectedPackagesOrDocs,
|
|
1204
|
+
maintenanceSignals,
|
|
1205
|
+
followUpWorkflowRefs,
|
|
1206
|
+
routingRecommendation,
|
|
1207
|
+
provenanceRefs
|
|
1208
|
+
});
|
|
1209
|
+
return agentOutputSchema.parse({
|
|
1210
|
+
summary: `Normalized maintenance evidence across ${normalization.normalizedEvidenceSources.length} source(s) for ${maintenanceRequest.maintenanceGoal}.`,
|
|
1211
|
+
findings: [],
|
|
1212
|
+
proposedActions: [],
|
|
1213
|
+
lifecycleArtifacts: [],
|
|
1214
|
+
requestedTools: [],
|
|
1215
|
+
blockedActionFlags: [],
|
|
1216
|
+
metadata: normalization
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
const maintenanceAnalystAgent = {
|
|
1221
|
+
manifest: agentManifestSchema.parse({
|
|
1222
|
+
version: 1,
|
|
1223
|
+
name: "maintenance-analyst",
|
|
1224
|
+
displayName: "Maintenance Analyst",
|
|
1225
|
+
category: "maintain",
|
|
1226
|
+
runtime: {
|
|
1227
|
+
minVersion: "0.1.0",
|
|
1228
|
+
kind: "reasoning"
|
|
1229
|
+
},
|
|
1230
|
+
permissions: {
|
|
1231
|
+
model: true,
|
|
1232
|
+
network: false,
|
|
1233
|
+
tools: [],
|
|
1234
|
+
readPaths: ["**/*"],
|
|
1235
|
+
writePaths: []
|
|
1236
|
+
},
|
|
1237
|
+
inputs: ["workflowInputs", "repo", "changes", "agentResults"],
|
|
1238
|
+
outputs: ["lifecycleArtifacts"],
|
|
1239
|
+
contextPolicy: {
|
|
1240
|
+
sections: ["workflowInputs", "repo", "changes", "agentResults"],
|
|
1241
|
+
minimalContext: true
|
|
1242
|
+
},
|
|
1243
|
+
catalog: {
|
|
1244
|
+
domain: "maintain",
|
|
1245
|
+
supportLevel: "internal",
|
|
1246
|
+
maturity: "mvp",
|
|
1247
|
+
trustScope: "official-core-only"
|
|
1248
|
+
},
|
|
1249
|
+
trust: {
|
|
1250
|
+
tier: "core",
|
|
1251
|
+
source: "official",
|
|
1252
|
+
reviewed: true
|
|
1253
|
+
}
|
|
1254
|
+
}),
|
|
1255
|
+
outputSchema: agentOutputSchema,
|
|
1256
|
+
async execute({ state, stateSlice }) {
|
|
1257
|
+
const maintenanceRequest = getWorkflowInput(stateSlice, "maintenanceRequest");
|
|
1258
|
+
const maintenanceIssueRefs = getWorkflowInput(stateSlice, "maintenanceIssueRefs") ?? [];
|
|
1259
|
+
const maintenanceGithubRefs = getWorkflowInput(stateSlice, "maintenanceGithubRefs") ?? [];
|
|
1260
|
+
const requestFile = getWorkflowInput(stateSlice, "requestFile");
|
|
1261
|
+
if (!maintenanceRequest) {
|
|
1262
|
+
throw new Error("maintenance-triage requires validated maintenance inputs before maintenance analysis.");
|
|
1263
|
+
}
|
|
1264
|
+
const intakeMetadata = isRecord(stateSlice.agentResults?.intake?.metadata) ? stateSlice.agentResults.intake.metadata : {};
|
|
1265
|
+
const evidenceMetadata = maintenanceEvidenceNormalizationSchema.safeParse(stateSlice.agentResults?.evidence?.metadata);
|
|
1266
|
+
const normalizedEvidence = evidenceMetadata.success ? evidenceMetadata.data : undefined;
|
|
1267
|
+
const dependencyAlertRefs = normalizedEvidence?.dependencyAlertRefs ??
|
|
1268
|
+
(asStringArray(intakeMetadata.dependencyAlertRefs).length > 0
|
|
1269
|
+
? asStringArray(intakeMetadata.dependencyAlertRefs)
|
|
1270
|
+
: maintenanceRequest.dependencyAlertRefs);
|
|
1271
|
+
const docsTaskRefs = normalizedEvidence?.docsTaskRefs ??
|
|
1272
|
+
(asStringArray(intakeMetadata.docsTaskRefs).length > 0
|
|
1273
|
+
? asStringArray(intakeMetadata.docsTaskRefs)
|
|
1274
|
+
: maintenanceRequest.docsTaskRefs);
|
|
1275
|
+
const releaseReportRefs = normalizedEvidence?.releaseReportRefs ??
|
|
1276
|
+
(asStringArray(intakeMetadata.releaseReportRefs).length > 0
|
|
1277
|
+
? asStringArray(intakeMetadata.releaseReportRefs)
|
|
1278
|
+
: maintenanceRequest.releaseReportRefs);
|
|
1279
|
+
const normalizedConstraints = asStringArray(intakeMetadata.constraints);
|
|
1280
|
+
const evidenceSources = normalizedEvidence?.normalizedEvidenceSources ?? [...new Set([...dependencyAlertRefs, ...docsTaskRefs, ...releaseReportRefs])];
|
|
1281
|
+
const affectedPackagesOrDocs = normalizedEvidence?.affectedPackagesOrDocs ?? [];
|
|
1282
|
+
const followUpWorkflowRefs = normalizedEvidence?.followUpWorkflowRefs ?? [];
|
|
1283
|
+
const routingRecommendation = normalizedEvidence?.routingRecommendation ?? "implementation-proposal";
|
|
1284
|
+
const maintenanceSignals = normalizedEvidence?.maintenanceSignals ?? [];
|
|
1285
|
+
const referencedArtifactKinds = normalizedEvidence?.referencedArtifactKinds ?? [];
|
|
1286
|
+
const currentFindings = [
|
|
1287
|
+
...(maintenanceSignals.length > 0
|
|
1288
|
+
? maintenanceSignals
|
|
1289
|
+
: [
|
|
1290
|
+
...(dependencyAlertRefs.length > 0 ? [`${dependencyAlertRefs.length} dependency alert reference(s) require maintenance triage.`] : []),
|
|
1291
|
+
...(docsTaskRefs.length > 0 ? [`${docsTaskRefs.length} docs task reference(s) require maintenance triage.`] : []),
|
|
1292
|
+
...(releaseReportRefs.length > 0 ? [`${releaseReportRefs.length} release-report reference(s) contribute maintenance follow-up context.`] : [])
|
|
1293
|
+
])
|
|
1294
|
+
];
|
|
1295
|
+
const recommendedActions = [
|
|
1296
|
+
...dependencyAlertRefs.map((pathValue) => `Review dependency alert reference \`${pathValue}\` before choosing a follow-up workflow.`),
|
|
1297
|
+
...docsTaskRefs.map((pathValue) => `Review docs task reference \`${pathValue}\` before choosing a follow-up workflow.`),
|
|
1298
|
+
...releaseReportRefs.map((pathValue) => `Review release report reference \`${pathValue}\` for maintenance-linked follow-up work.`),
|
|
1299
|
+
...(affectedPackagesOrDocs.length > 0 ? [`Review the affected maintenance surfaces: ${affectedPackagesOrDocs.join(", ")}.`] : []),
|
|
1300
|
+
...(followUpWorkflowRefs.length > 0
|
|
1301
|
+
? [`Route the next bounded follow-up through ${routingRecommendation} (${followUpWorkflowRefs.join(", ")} considered).`]
|
|
1302
|
+
: []),
|
|
1303
|
+
...(normalizedConstraints.length > 0 ? [`Keep maintenance follow-up bounded by: ${normalizedConstraints.join("; ")}.`] : [])
|
|
1304
|
+
];
|
|
1305
|
+
const priorityAssessment = releaseReportRefs.length > 0 || dependencyAlertRefs.length > 1
|
|
1306
|
+
? "Elevated maintenance triage: release-linked or multi-alert follow-up should be prioritized before broader maintenance work."
|
|
1307
|
+
: "Routine maintenance triage: review bounded references and route follow-up deliberately.";
|
|
1308
|
+
const risks = [
|
|
1309
|
+
...(releaseReportRefs.length > 0 ? ["Release-linked maintenance follow-up can drift if release-readiness is deferred."] : []),
|
|
1310
|
+
...(dependencyAlertRefs.length > 0 ? ["Dependency alert follow-up can widen change scope once implementation work begins."] : []),
|
|
1311
|
+
...(docsTaskRefs.length > 0 ? ["Documentation debt can diverge from implemented behavior if maintenance triage is deferred."] : []),
|
|
1312
|
+
...(referencedArtifactKinds.includes("security-report")
|
|
1313
|
+
? ["Security-linked maintenance follow-up should remain prioritized until the linked evidence is resolved."]
|
|
1314
|
+
: [])
|
|
1315
|
+
];
|
|
1316
|
+
const stalenessSignals = [
|
|
1317
|
+
...(dependencyAlertRefs.length > 0 ? ["Dependency alert follow-up remains pending review."] : []),
|
|
1318
|
+
...(docsTaskRefs.length > 0 ? ["Documentation maintenance follow-up remains pending review."] : []),
|
|
1319
|
+
...(releaseReportRefs.length > 0 ? ["Release-linked maintenance follow-up remains pending review."] : [])
|
|
1320
|
+
];
|
|
1321
|
+
const summary = `Maintenance report prepared for ${maintenanceRequest.maintenanceGoal}.`;
|
|
1322
|
+
const maintenanceReport = maintenanceArtifactSchema.parse({
|
|
1323
|
+
...buildLifecycleArtifactEnvelopeBase(state, "Maintenance Triage", summary, [requestFile ?? ".agentops/requests/maintenance.yaml", ...evidenceSources], maintenanceIssueRefs, maintenanceGithubRefs),
|
|
1324
|
+
artifactKind: "maintenance-report",
|
|
1325
|
+
lifecycleDomain: "maintain",
|
|
1326
|
+
payload: {
|
|
1327
|
+
maintenanceScope: maintenanceRequest.maintenanceGoal,
|
|
1328
|
+
evidenceSources,
|
|
1329
|
+
affectedPackagesOrDocs,
|
|
1330
|
+
currentFindings: currentFindings.length > 0
|
|
1331
|
+
? currentFindings
|
|
1332
|
+
: ["Maintenance triage remained bounded to validated references; no additional findings were synthesized."],
|
|
1333
|
+
recommendedActions: recommendedActions.length > 0
|
|
1334
|
+
? recommendedActions
|
|
1335
|
+
: ["Add at least one bounded maintenance reference before broadening the workflow surface."],
|
|
1336
|
+
routingRecommendation,
|
|
1337
|
+
followUpWorkflowRefs,
|
|
1338
|
+
risks,
|
|
1339
|
+
priorityAssessment,
|
|
1340
|
+
dependencyUpdates: dependencyAlertRefs,
|
|
1341
|
+
docsUpdates: docsTaskRefs,
|
|
1342
|
+
stalenessSignals,
|
|
1343
|
+
followUpIssues: maintenanceIssueRefs
|
|
1344
|
+
}
|
|
1345
|
+
});
|
|
1346
|
+
return agentOutputSchema.parse({
|
|
1347
|
+
summary,
|
|
1348
|
+
findings: [],
|
|
1349
|
+
proposedActions: [],
|
|
1350
|
+
lifecycleArtifacts: [maintenanceReport],
|
|
1351
|
+
requestedTools: [],
|
|
1352
|
+
blockedActionFlags: [],
|
|
1353
|
+
confidence: 0.73,
|
|
1354
|
+
metadata: {
|
|
1355
|
+
deterministicInputs: {
|
|
1356
|
+
evidenceSources,
|
|
1357
|
+
dependencyAlertRefs,
|
|
1358
|
+
docsTaskRefs,
|
|
1359
|
+
releaseReportRefs,
|
|
1360
|
+
affectedPackagesOrDocs,
|
|
1361
|
+
maintenanceSignals,
|
|
1362
|
+
referencedArtifactKinds,
|
|
1363
|
+
issueRefs: maintenanceIssueRefs,
|
|
1364
|
+
constraints: normalizedConstraints
|
|
1365
|
+
},
|
|
1366
|
+
synthesizedAssessment: {
|
|
1367
|
+
priorityAssessment: maintenanceReport.payload.priorityAssessment,
|
|
1368
|
+
recommendedActions: maintenanceReport.payload.recommendedActions,
|
|
1369
|
+
routingRecommendation: maintenanceReport.payload.routingRecommendation,
|
|
1370
|
+
followUpWorkflowRefs: maintenanceReport.payload.followUpWorkflowRefs,
|
|
1371
|
+
risks: maintenanceReport.payload.risks,
|
|
1372
|
+
followUpIssues: maintenanceReport.payload.followUpIssues
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
};
|
|
1378
|
+
const incidentAnalystAgent = {
|
|
1379
|
+
manifest: agentManifestSchema.parse({
|
|
1380
|
+
version: 1,
|
|
1381
|
+
name: "incident-analyst",
|
|
1382
|
+
displayName: "Incident Analyst",
|
|
1383
|
+
category: "operate",
|
|
1384
|
+
runtime: {
|
|
1385
|
+
minVersion: "0.1.0",
|
|
1386
|
+
kind: "reasoning"
|
|
1387
|
+
},
|
|
1388
|
+
permissions: {
|
|
1389
|
+
model: true,
|
|
1390
|
+
network: false,
|
|
1391
|
+
tools: [],
|
|
1392
|
+
readPaths: ["**/*"],
|
|
1393
|
+
writePaths: []
|
|
1394
|
+
},
|
|
1395
|
+
inputs: ["workflowInputs", "repo", "changes", "agentResults"],
|
|
1396
|
+
outputs: ["lifecycleArtifacts"],
|
|
1397
|
+
contextPolicy: {
|
|
1398
|
+
sections: ["workflowInputs", "repo", "changes", "agentResults"],
|
|
1399
|
+
minimalContext: true
|
|
1400
|
+
},
|
|
1401
|
+
catalog: {
|
|
1402
|
+
domain: "operate",
|
|
1403
|
+
supportLevel: "internal",
|
|
1404
|
+
maturity: "mvp",
|
|
1405
|
+
trustScope: "official-core-only"
|
|
1406
|
+
},
|
|
1407
|
+
trust: {
|
|
1408
|
+
tier: "core",
|
|
1409
|
+
source: "official",
|
|
1410
|
+
reviewed: true
|
|
1411
|
+
}
|
|
1412
|
+
}),
|
|
1413
|
+
outputSchema: agentOutputSchema,
|
|
1414
|
+
async execute({ state, stateSlice }) {
|
|
1415
|
+
const incidentRequest = getWorkflowInput(stateSlice, "incidentRequest");
|
|
1416
|
+
const requestFile = getWorkflowInput(stateSlice, "requestFile");
|
|
1417
|
+
const incidentIssueRefs = getWorkflowInput(stateSlice, "incidentIssueRefs") ?? [];
|
|
1418
|
+
const incidentGithubRefs = getWorkflowInput(stateSlice, "incidentGithubRefs") ?? [];
|
|
1419
|
+
if (!incidentRequest) {
|
|
1420
|
+
throw new Error("incident-handoff requires validated incident inputs before incident analysis.");
|
|
1421
|
+
}
|
|
1422
|
+
const intakeMetadata = isRecord(stateSlice.agentResults?.intake?.metadata) ? stateSlice.agentResults.intake.metadata : {};
|
|
1423
|
+
const evidenceMetadata = incidentEvidenceNormalizationSchema.safeParse(stateSlice.agentResults?.evidence?.metadata);
|
|
1424
|
+
const normalizedEvidence = evidenceMetadata.success ? evidenceMetadata.data : undefined;
|
|
1425
|
+
const evidenceSources = normalizedEvidence?.normalizedEvidenceSources && normalizedEvidence.normalizedEvidenceSources.length > 0
|
|
1426
|
+
? normalizedEvidence.normalizedEvidenceSources
|
|
1427
|
+
: asStringArray(intakeMetadata.evidenceSources).length > 0
|
|
1428
|
+
? [
|
|
1429
|
+
...new Set([
|
|
1430
|
+
...asStringArray(intakeMetadata.evidenceSources),
|
|
1431
|
+
...asStringArray(intakeMetadata.releaseReportRefs)
|
|
1432
|
+
])
|
|
1433
|
+
]
|
|
1434
|
+
: [...new Set([...incidentRequest.evidenceSources, ...incidentRequest.releaseReportRefs])];
|
|
1435
|
+
const severityHint = normalizedEvidence?.severityHint ??
|
|
1436
|
+
(typeof intakeMetadata.severityHint === "string" ? intakeMetadata.severityHint : incidentRequest.severityHint);
|
|
1437
|
+
const constraints = asStringArray(intakeMetadata.constraints);
|
|
1438
|
+
const followUpWorkflowRefs = normalizedEvidence?.followUpWorkflowRefs && normalizedEvidence.followUpWorkflowRefs.length > 0
|
|
1439
|
+
? normalizedEvidence.followUpWorkflowRefs
|
|
1440
|
+
: [
|
|
1441
|
+
"maintenance-triage",
|
|
1442
|
+
...(incidentRequest.releaseReportRefs.length > 0 ? ["release-readiness"] : []),
|
|
1443
|
+
...(severityHint === "high" || severityHint === "critical" ? ["security-review"] : [])
|
|
1444
|
+
];
|
|
1445
|
+
const likelyImpactedAreas = normalizedEvidence?.likelyImpactedAreas && normalizedEvidence.likelyImpactedAreas.length > 0
|
|
1446
|
+
? normalizedEvidence.likelyImpactedAreas
|
|
1447
|
+
: [
|
|
1448
|
+
...(incidentRequest.releaseReportRefs.length > 0 ? ["release-readiness"] : []),
|
|
1449
|
+
...(incidentRequest.evidenceSources.length > 0 ? ["staged-operational-evidence"] : []),
|
|
1450
|
+
...(severityHint === "high" || severityHint === "critical" ? ["security-follow-up"] : [])
|
|
1451
|
+
];
|
|
1452
|
+
const openQuestions = [
|
|
1453
|
+
...(incidentRequest.issueRefs.length === 0 ? ["Should this incident be linked to a tracked issue before escalation?"] : []),
|
|
1454
|
+
...(incidentRequest.releaseReportRefs.length === 0
|
|
1455
|
+
? ["Is there a release-report bundle that should be attached for additional provenance?"]
|
|
1456
|
+
: [])
|
|
1457
|
+
];
|
|
1458
|
+
const summary = `Incident brief prepared for ${incidentRequest.incidentSummary}.`;
|
|
1459
|
+
const incidentBrief = incidentArtifactSchema.parse({
|
|
1460
|
+
...buildLifecycleArtifactEnvelopeBase(state, "Incident Handoff", summary, [requestFile ?? ".agentops/requests/incident.yaml", ...evidenceSources], incidentIssueRefs, incidentGithubRefs),
|
|
1461
|
+
artifactKind: "incident-brief",
|
|
1462
|
+
lifecycleDomain: "operate",
|
|
1463
|
+
redaction: {
|
|
1464
|
+
applied: true,
|
|
1465
|
+
strategyVersion: "1.0.0",
|
|
1466
|
+
categories: normalizedEvidence?.redactionCategories ?? [
|
|
1467
|
+
"github-token",
|
|
1468
|
+
"api-key",
|
|
1469
|
+
"aws-key",
|
|
1470
|
+
"bearer-token",
|
|
1471
|
+
"password",
|
|
1472
|
+
"private-key",
|
|
1473
|
+
"operational-sensitive"
|
|
1474
|
+
]
|
|
1475
|
+
},
|
|
1476
|
+
payload: {
|
|
1477
|
+
incidentSummary: incidentRequest.incidentSummary,
|
|
1478
|
+
evidenceSources,
|
|
1479
|
+
timelineSummary: normalizedEvidence?.timelineSummary ?? [
|
|
1480
|
+
`Severity hint: ${severityHint}.`,
|
|
1481
|
+
`Validated ${incidentRequest.evidenceSources.length} staged evidence source(s) and ${incidentRequest.releaseReportRefs.length} release-report reference(s) before reasoning.`
|
|
1482
|
+
],
|
|
1483
|
+
likelyImpactedAreas: likelyImpactedAreas.length > 0
|
|
1484
|
+
? likelyImpactedAreas
|
|
1485
|
+
: ["manual incident triage is still required to identify impacted repository areas."],
|
|
1486
|
+
followUpWorkflowRefs: [...new Set(followUpWorkflowRefs)],
|
|
1487
|
+
openQuestions
|
|
1488
|
+
}
|
|
1489
|
+
});
|
|
1490
|
+
return agentOutputSchema.parse({
|
|
1491
|
+
summary,
|
|
1492
|
+
findings: [],
|
|
1493
|
+
proposedActions: [],
|
|
1494
|
+
lifecycleArtifacts: [incidentBrief],
|
|
1495
|
+
requestedTools: [],
|
|
1496
|
+
blockedActionFlags: [],
|
|
1497
|
+
confidence: severityHint === "critical" ? 0.7 : 0.74,
|
|
1498
|
+
metadata: {
|
|
1499
|
+
deterministicInputs: {
|
|
1500
|
+
severityHint,
|
|
1501
|
+
evidenceSources,
|
|
1502
|
+
issueRefs: incidentIssueRefs,
|
|
1503
|
+
constraints,
|
|
1504
|
+
normalizedEvidence: normalizedEvidence ?? null
|
|
1505
|
+
},
|
|
1506
|
+
synthesizedAssessment: {
|
|
1507
|
+
likelyImpactedAreas: incidentBrief.payload.likelyImpactedAreas,
|
|
1508
|
+
followUpWorkflowRefs: incidentBrief.payload.followUpWorkflowRefs,
|
|
1509
|
+
openQuestions: incidentBrief.payload.openQuestions
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1514
|
+
};
|
|
1515
|
+
const releaseIntakeAgent = {
|
|
1516
|
+
manifest: agentManifestSchema.parse({
|
|
1517
|
+
version: 1,
|
|
1518
|
+
name: "release-intake",
|
|
1519
|
+
displayName: "Release Intake",
|
|
1520
|
+
category: "release",
|
|
1521
|
+
runtime: {
|
|
1522
|
+
minVersion: "0.1.0",
|
|
1523
|
+
kind: "deterministic"
|
|
1524
|
+
},
|
|
1525
|
+
permissions: {
|
|
1526
|
+
model: false,
|
|
1527
|
+
network: false,
|
|
1528
|
+
tools: [],
|
|
1529
|
+
readPaths: [".agentops/requests/**", ".agentops/runs/**"],
|
|
1530
|
+
writePaths: []
|
|
1531
|
+
},
|
|
1532
|
+
inputs: ["workflowInputs", "repo"],
|
|
1533
|
+
outputs: ["summary", "metadata"],
|
|
1534
|
+
contextPolicy: {
|
|
1535
|
+
sections: ["workflowInputs", "repo", "context"],
|
|
1536
|
+
minimalContext: true
|
|
1537
|
+
},
|
|
1538
|
+
catalog: {
|
|
1539
|
+
domain: "release",
|
|
1540
|
+
supportLevel: "internal",
|
|
1541
|
+
maturity: "mvp",
|
|
1542
|
+
trustScope: "official-core-only"
|
|
1543
|
+
},
|
|
1544
|
+
trust: {
|
|
1545
|
+
tier: "core",
|
|
1546
|
+
source: "official",
|
|
1547
|
+
reviewed: true
|
|
1548
|
+
}
|
|
1549
|
+
}),
|
|
1550
|
+
outputSchema: agentOutputSchema,
|
|
1551
|
+
async execute({ stateSlice }) {
|
|
1552
|
+
const releaseRequest = getWorkflowInput(stateSlice, "releaseRequest");
|
|
1553
|
+
const releaseIssueRefs = getWorkflowInput(stateSlice, "releaseIssueRefs") ?? [];
|
|
1554
|
+
const releaseGithubRefs = getWorkflowInput(stateSlice, "releaseGithubRefs") ?? [];
|
|
1555
|
+
const requestFile = getWorkflowInput(stateSlice, "requestFile");
|
|
1556
|
+
if (!releaseRequest) {
|
|
1557
|
+
throw new Error("release-readiness requires a validated release request before runtime execution.");
|
|
1558
|
+
}
|
|
1559
|
+
return agentOutputSchema.parse({
|
|
1560
|
+
summary: `Loaded release request from ${requestFile ?? ".agentops/requests/release.yaml"} for ${releaseRequest.releaseScope}.`,
|
|
1561
|
+
findings: [],
|
|
1562
|
+
proposedActions: [],
|
|
1563
|
+
lifecycleArtifacts: [],
|
|
1564
|
+
requestedTools: [],
|
|
1565
|
+
blockedActionFlags: [],
|
|
1566
|
+
metadata: {
|
|
1567
|
+
...releaseRequestSchema.parse(releaseRequest),
|
|
1568
|
+
releaseIssueRefs,
|
|
1569
|
+
releaseGithubRefs,
|
|
1570
|
+
evidenceSourceCount: releaseRequest.qaReportRefs.length + releaseRequest.securityReportRefs.length + releaseRequest.evidenceSources.length
|
|
1571
|
+
}
|
|
1572
|
+
});
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1575
|
+
const releaseEvidenceNormalizationAgent = {
|
|
1576
|
+
manifest: agentManifestSchema.parse({
|
|
1577
|
+
version: 1,
|
|
1578
|
+
name: "release-evidence-normalizer",
|
|
1579
|
+
displayName: "Release Evidence Normalizer",
|
|
1580
|
+
category: "release",
|
|
1581
|
+
runtime: {
|
|
1582
|
+
minVersion: "0.1.0",
|
|
1583
|
+
kind: "deterministic"
|
|
1584
|
+
},
|
|
1585
|
+
permissions: {
|
|
1586
|
+
model: false,
|
|
1587
|
+
network: false,
|
|
1588
|
+
tools: [],
|
|
1589
|
+
readPaths: [".agentops/requests/**", ".agentops/runs/**", "**/*.json", "**/*.md", "**/package.json"],
|
|
1590
|
+
writePaths: []
|
|
1591
|
+
},
|
|
1592
|
+
inputs: ["workflowInputs", "repo", "agentResults"],
|
|
1593
|
+
outputs: ["summary", "metadata"],
|
|
1594
|
+
contextPolicy: {
|
|
1595
|
+
sections: ["workflowInputs", "repo", "agentResults"],
|
|
1596
|
+
minimalContext: true
|
|
1597
|
+
},
|
|
1598
|
+
catalog: {
|
|
1599
|
+
domain: "release",
|
|
1600
|
+
supportLevel: "internal",
|
|
1601
|
+
maturity: "mvp",
|
|
1602
|
+
trustScope: "official-core-only"
|
|
1603
|
+
},
|
|
1604
|
+
trust: {
|
|
1605
|
+
tier: "core",
|
|
1606
|
+
source: "official",
|
|
1607
|
+
reviewed: true
|
|
1608
|
+
}
|
|
1609
|
+
}),
|
|
1610
|
+
outputSchema: agentOutputSchema,
|
|
1611
|
+
async execute({ stateSlice }) {
|
|
1612
|
+
const releaseRequest = getWorkflowInput(stateSlice, "releaseRequest");
|
|
1613
|
+
if (!releaseRequest) {
|
|
1614
|
+
throw new Error("release-readiness requires validated release request inputs before evidence normalization.");
|
|
1615
|
+
}
|
|
1616
|
+
const repoRoot = stateSlice.repo?.root;
|
|
1617
|
+
const intakeMetadata = isRecord(stateSlice.agentResults?.intake?.metadata) ? stateSlice.agentResults.intake.metadata : {};
|
|
1618
|
+
const qaReportRefs = asStringArray(intakeMetadata.qaReportRefs).length > 0
|
|
1619
|
+
? asStringArray(intakeMetadata.qaReportRefs)
|
|
1620
|
+
: releaseRequest.qaReportRefs;
|
|
1621
|
+
const securityReportRefs = asStringArray(intakeMetadata.securityReportRefs).length > 0
|
|
1622
|
+
? asStringArray(intakeMetadata.securityReportRefs)
|
|
1623
|
+
: releaseRequest.securityReportRefs;
|
|
1624
|
+
const evidenceSources = asStringArray(intakeMetadata.evidenceSources).length > 0
|
|
1625
|
+
? asStringArray(intakeMetadata.evidenceSources)
|
|
1626
|
+
: releaseRequest.evidenceSources;
|
|
1627
|
+
const normalizedEvidenceSources = [...new Set([...qaReportRefs, ...securityReportRefs, ...evidenceSources])];
|
|
1628
|
+
const missingEvidenceSources = normalizedEvidenceSources.filter((pathValue) => repoRoot && !existsSync(join(repoRoot, pathValue)));
|
|
1629
|
+
if (missingEvidenceSources.length > 0) {
|
|
1630
|
+
throw new Error(`Release evidence source not found: ${missingEvidenceSources[0]}`);
|
|
1631
|
+
}
|
|
1632
|
+
const versionResolutions = releaseRequest.versionTargets.map((target) => {
|
|
1633
|
+
const resolved = resolveWorkspacePackage(repoRoot, target.name);
|
|
1634
|
+
return {
|
|
1635
|
+
name: target.name,
|
|
1636
|
+
targetVersion: target.version,
|
|
1637
|
+
currentVersion: resolved.currentVersion,
|
|
1638
|
+
status: !resolved.currentVersion
|
|
1639
|
+
? "package-missing"
|
|
1640
|
+
: resolved.currentVersion === target.version
|
|
1641
|
+
? "matches-target"
|
|
1642
|
+
: "pending-version-bump",
|
|
1643
|
+
manifestPath: resolved.manifestPath
|
|
1644
|
+
};
|
|
1645
|
+
});
|
|
1646
|
+
const missingPackages = versionResolutions.filter((entry) => entry.status === "package-missing").map((entry) => entry.name);
|
|
1647
|
+
const versionCheckStatus = missingPackages.length === 0 ? "passed" : "failed";
|
|
1648
|
+
const baseReadinessStatus = qaReportRefs.length > 0 && securityReportRefs.length > 0
|
|
1649
|
+
? "ready"
|
|
1650
|
+
: qaReportRefs.length > 0 || securityReportRefs.length > 0
|
|
1651
|
+
? "partial"
|
|
1652
|
+
: "blocked";
|
|
1653
|
+
const readinessStatus = missingPackages.length > 0 ? "blocked" : baseReadinessStatus;
|
|
1654
|
+
const localReadinessChecks = [
|
|
1655
|
+
{
|
|
1656
|
+
name: "qa-report-refs",
|
|
1657
|
+
status: qaReportRefs.length > 0 ? "passed" : "skipped",
|
|
1658
|
+
detail: qaReportRefs.length > 0
|
|
1659
|
+
? `Using ${qaReportRefs.length} validated QA report reference(s).`
|
|
1660
|
+
: "No QA report references were supplied."
|
|
1661
|
+
},
|
|
1662
|
+
{
|
|
1663
|
+
name: "security-report-refs",
|
|
1664
|
+
status: securityReportRefs.length > 0 ? "passed" : "skipped",
|
|
1665
|
+
detail: securityReportRefs.length > 0
|
|
1666
|
+
? `Using ${securityReportRefs.length} validated security report reference(s).`
|
|
1667
|
+
: "No security report references were supplied."
|
|
1668
|
+
},
|
|
1669
|
+
{
|
|
1670
|
+
name: "local-release-evidence",
|
|
1671
|
+
status: evidenceSources.length > 0 ? "passed" : "skipped",
|
|
1672
|
+
detail: evidenceSources.length > 0
|
|
1673
|
+
? `Using ${evidenceSources.length} bounded local release evidence source(s).`
|
|
1674
|
+
: "No additional local release evidence sources were supplied."
|
|
1675
|
+
},
|
|
1676
|
+
{
|
|
1677
|
+
name: "workspace-version-targets",
|
|
1678
|
+
status: versionCheckStatus,
|
|
1679
|
+
detail: missingPackages.length === 0
|
|
1680
|
+
? `Resolved ${versionResolutions.length} workspace version target(s).`
|
|
1681
|
+
: `Missing workspace package metadata for: ${missingPackages.join(", ")}.`
|
|
1682
|
+
}
|
|
1683
|
+
];
|
|
1684
|
+
const approvalRecommendations = [
|
|
1685
|
+
{
|
|
1686
|
+
action: "publish-packages",
|
|
1687
|
+
classification: readinessStatus === "ready" ? "approval_required" : "deny",
|
|
1688
|
+
reason: readinessStatus === "ready"
|
|
1689
|
+
? "Package publication remains outside the default read-only workflow path and needs explicit release approval."
|
|
1690
|
+
: "Keep package publication blocked until bounded release evidence is complete and normalized."
|
|
1691
|
+
},
|
|
1692
|
+
{
|
|
1693
|
+
action: "create-release-tag",
|
|
1694
|
+
classification: readinessStatus === "ready" ? "approval_required" : "deny",
|
|
1695
|
+
reason: readinessStatus === "ready"
|
|
1696
|
+
? "Tag creation is a release-significant side effect and remains approval-gated."
|
|
1697
|
+
: "Do not create release tags while readiness remains partial or blocked."
|
|
1698
|
+
},
|
|
1699
|
+
{
|
|
1700
|
+
action: "promote-release",
|
|
1701
|
+
classification: readinessStatus === "ready" ? "approval_required" : "deny",
|
|
1702
|
+
reason: readinessStatus === "ready"
|
|
1703
|
+
? "Promotion remains a release-significant side effect and requires explicit maintainer approval."
|
|
1704
|
+
: "Keep release promotion blocked until bounded QA and security evidence is complete."
|
|
1705
|
+
}
|
|
1706
|
+
];
|
|
1707
|
+
const provenanceRefs = [
|
|
1708
|
+
...normalizedEvidenceSources,
|
|
1709
|
+
...versionResolutions
|
|
1710
|
+
.map((entry) => entry.manifestPath)
|
|
1711
|
+
.filter((value) => Boolean(value))
|
|
1712
|
+
];
|
|
1713
|
+
const normalization = releaseEvidenceNormalizationSchema.parse({
|
|
1714
|
+
qaReportRefs,
|
|
1715
|
+
securityReportRefs,
|
|
1716
|
+
normalizedEvidenceSources,
|
|
1717
|
+
missingEvidenceSources: [],
|
|
1718
|
+
versionResolutions: versionResolutions.map((entry) => ({
|
|
1719
|
+
name: entry.name,
|
|
1720
|
+
targetVersion: entry.targetVersion,
|
|
1721
|
+
currentVersion: entry.currentVersion,
|
|
1722
|
+
status: entry.status
|
|
1723
|
+
})),
|
|
1724
|
+
localReadinessChecks,
|
|
1725
|
+
readinessStatus,
|
|
1726
|
+
approvalRecommendations,
|
|
1727
|
+
provenanceRefs: [...new Set(provenanceRefs)]
|
|
1728
|
+
});
|
|
1729
|
+
return agentOutputSchema.parse({
|
|
1730
|
+
summary: `Normalized release evidence across ${normalization.normalizedEvidenceSources.length} source(s) and ${normalization.versionResolutions.length} version target(s).`,
|
|
1731
|
+
findings: [],
|
|
1732
|
+
proposedActions: [],
|
|
1733
|
+
lifecycleArtifacts: [],
|
|
1734
|
+
requestedTools: [],
|
|
1735
|
+
blockedActionFlags: [],
|
|
1736
|
+
metadata: normalization
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
};
|
|
1740
|
+
const releaseAnalystAgent = {
|
|
1741
|
+
manifest: agentManifestSchema.parse({
|
|
1742
|
+
version: 1,
|
|
1743
|
+
name: "release-analyst",
|
|
1744
|
+
displayName: "Release Analyst",
|
|
1745
|
+
category: "release",
|
|
1746
|
+
runtime: {
|
|
1747
|
+
minVersion: "0.1.0",
|
|
1748
|
+
kind: "reasoning"
|
|
1749
|
+
},
|
|
1750
|
+
permissions: {
|
|
1751
|
+
model: true,
|
|
1752
|
+
network: false,
|
|
1753
|
+
tools: [],
|
|
1754
|
+
readPaths: ["**/*"],
|
|
1755
|
+
writePaths: []
|
|
1756
|
+
},
|
|
1757
|
+
inputs: ["workflowInputs", "repo", "agentResults"],
|
|
1758
|
+
outputs: ["lifecycleArtifacts"],
|
|
1759
|
+
contextPolicy: {
|
|
1760
|
+
sections: ["workflowInputs", "repo", "agentResults"],
|
|
1761
|
+
minimalContext: true
|
|
1762
|
+
},
|
|
1763
|
+
catalog: {
|
|
1764
|
+
domain: "release",
|
|
1765
|
+
supportLevel: "internal",
|
|
1766
|
+
maturity: "mvp",
|
|
1767
|
+
trustScope: "official-core-only"
|
|
1768
|
+
},
|
|
1769
|
+
trust: {
|
|
1770
|
+
tier: "core",
|
|
1771
|
+
source: "official",
|
|
1772
|
+
reviewed: true
|
|
1773
|
+
}
|
|
1774
|
+
}),
|
|
1775
|
+
outputSchema: agentOutputSchema,
|
|
1776
|
+
async execute({ state, stateSlice }) {
|
|
1777
|
+
const releaseRequest = getWorkflowInput(stateSlice, "releaseRequest");
|
|
1778
|
+
const releaseIssueRefs = getWorkflowInput(stateSlice, "releaseIssueRefs") ?? [];
|
|
1779
|
+
const releaseGithubRefs = getWorkflowInput(stateSlice, "releaseGithubRefs") ?? [];
|
|
1780
|
+
const requestFile = getWorkflowInput(stateSlice, "requestFile");
|
|
1781
|
+
if (!releaseRequest) {
|
|
1782
|
+
throw new Error("release-readiness requires validated release inputs before release analysis.");
|
|
1783
|
+
}
|
|
1784
|
+
const intakeMetadata = isRecord(stateSlice.agentResults?.intake?.metadata) ? stateSlice.agentResults.intake.metadata : {};
|
|
1785
|
+
const evidenceMetadata = releaseEvidenceNormalizationSchema.safeParse(stateSlice.agentResults?.evidence?.metadata);
|
|
1786
|
+
const normalizedEvidence = evidenceMetadata.success ? evidenceMetadata.data : undefined;
|
|
1787
|
+
const qaReportRefs = normalizedEvidence?.qaReportRefs && normalizedEvidence.qaReportRefs.length > 0
|
|
1788
|
+
? normalizedEvidence.qaReportRefs
|
|
1789
|
+
: asStringArray(intakeMetadata.qaReportRefs).length > 0
|
|
1790
|
+
? asStringArray(intakeMetadata.qaReportRefs)
|
|
1791
|
+
: releaseRequest.qaReportRefs;
|
|
1792
|
+
const securityReportRefs = normalizedEvidence?.securityReportRefs && normalizedEvidence.securityReportRefs.length > 0
|
|
1793
|
+
? normalizedEvidence.securityReportRefs
|
|
1794
|
+
: asStringArray(intakeMetadata.securityReportRefs).length > 0
|
|
1795
|
+
? asStringArray(intakeMetadata.securityReportRefs)
|
|
1796
|
+
: releaseRequest.securityReportRefs;
|
|
1797
|
+
const evidenceSources = normalizedEvidence?.normalizedEvidenceSources && normalizedEvidence.normalizedEvidenceSources.length > 0
|
|
1798
|
+
? normalizedEvidence.normalizedEvidenceSources
|
|
1799
|
+
: asStringArray(intakeMetadata.evidenceSources).length > 0
|
|
1800
|
+
? asStringArray(intakeMetadata.evidenceSources)
|
|
1801
|
+
: releaseRequest.evidenceSources;
|
|
1802
|
+
const constraints = asStringArray(intakeMetadata.constraints);
|
|
1803
|
+
const allEvidenceRefs = [...new Set([...qaReportRefs, ...securityReportRefs, ...evidenceSources])];
|
|
1804
|
+
const versionResolutions = normalizedEvidence?.versionResolutions ?? [];
|
|
1805
|
+
const verificationChecks = normalizedEvidence?.localReadinessChecks ?? [
|
|
1806
|
+
{
|
|
1807
|
+
name: "qa-report-refs",
|
|
1808
|
+
status: qaReportRefs.length > 0 ? "passed" : "skipped",
|
|
1809
|
+
detail: qaReportRefs.length > 0
|
|
1810
|
+
? `Using ${qaReportRefs.length} validated QA report reference(s).`
|
|
1811
|
+
: "No QA report references were supplied."
|
|
1812
|
+
},
|
|
1813
|
+
{
|
|
1814
|
+
name: "security-report-refs",
|
|
1815
|
+
status: securityReportRefs.length > 0 ? "passed" : "skipped",
|
|
1816
|
+
detail: securityReportRefs.length > 0
|
|
1817
|
+
? `Using ${securityReportRefs.length} validated security report reference(s).`
|
|
1818
|
+
: "No security report references were supplied."
|
|
1819
|
+
},
|
|
1820
|
+
{
|
|
1821
|
+
name: "local-release-evidence",
|
|
1822
|
+
status: evidenceSources.length > 0 ? "passed" : "skipped",
|
|
1823
|
+
detail: evidenceSources.length > 0
|
|
1824
|
+
? `Using ${evidenceSources.length} bounded local release evidence source(s).`
|
|
1825
|
+
: "No additional local release evidence sources were supplied."
|
|
1826
|
+
}
|
|
1827
|
+
];
|
|
1828
|
+
const readinessStatus = normalizedEvidence?.readinessStatus ??
|
|
1829
|
+
(qaReportRefs.length > 0 && securityReportRefs.length > 0
|
|
1830
|
+
? "ready"
|
|
1831
|
+
: qaReportRefs.length > 0 || securityReportRefs.length > 0
|
|
1832
|
+
? "partial"
|
|
1833
|
+
: "blocked");
|
|
1834
|
+
const approvalRecommendations = normalizedEvidence?.approvalRecommendations ?? [
|
|
1835
|
+
{
|
|
1836
|
+
action: "publish-packages",
|
|
1837
|
+
classification: readinessStatus === "ready" ? "approval_required" : "deny",
|
|
1838
|
+
reason: readinessStatus === "ready"
|
|
1839
|
+
? "Package publication remains outside the default read-only workflow path and needs explicit release approval."
|
|
1840
|
+
: "Keep package publication blocked until bounded release evidence is complete and normalized."
|
|
1841
|
+
}
|
|
1842
|
+
];
|
|
1843
|
+
const summary = `Release report prepared for ${releaseRequest.releaseScope}.`;
|
|
1844
|
+
const publishingPlan = [
|
|
1845
|
+
...(versionResolutions.length > 0
|
|
1846
|
+
? [`Resolved ${versionResolutions.length} workspace version target(s) before any publish or promotion step.`]
|
|
1847
|
+
: []),
|
|
1848
|
+
"Review the bounded QA and security evidence before invoking any publish or promotion step.",
|
|
1849
|
+
"Run `agentforge release check --json` and `agentforge release verify --json` before any release cut.",
|
|
1850
|
+
...approvalRecommendations.map((recommendation) => `${recommendation.action}: ${recommendation.classification.replaceAll("_", " ")} (${recommendation.reason})`),
|
|
1851
|
+
"Keep trusted publishing and tag or publish actions outside this default read-only workflow path."
|
|
1852
|
+
];
|
|
1853
|
+
const rollbackNotes = [
|
|
1854
|
+
"Use the release report to decide whether to pause or defer promotion before any publish step.",
|
|
1855
|
+
"If readiness remains partial or blocked, keep the current version set unchanged and resolve evidence gaps first."
|
|
1856
|
+
];
|
|
1857
|
+
const externalDependencies = [
|
|
1858
|
+
...(qaReportRefs.length > 0 ? ["Validated QA report inputs remain available for reviewer inspection."] : []),
|
|
1859
|
+
...(securityReportRefs.length > 0 ? ["Validated security report inputs remain available for reviewer inspection."] : [])
|
|
1860
|
+
];
|
|
1861
|
+
const releaseReport = releaseArtifactSchema.parse({
|
|
1862
|
+
...buildLifecycleArtifactEnvelopeBase(state, "Release Readiness", summary, [requestFile ?? ".agentops/requests/release.yaml", ...allEvidenceRefs], releaseIssueRefs, releaseGithubRefs),
|
|
1863
|
+
artifactKind: "release-report",
|
|
1864
|
+
lifecycleDomain: "release",
|
|
1865
|
+
payload: {
|
|
1866
|
+
releaseScope: releaseRequest.releaseScope,
|
|
1867
|
+
versionTargets: releaseRequest.versionTargets,
|
|
1868
|
+
readinessStatus,
|
|
1869
|
+
verificationChecks: verificationChecks.map((check) => ({ ...check })),
|
|
1870
|
+
versionResolutions,
|
|
1871
|
+
approvalRecommendations: approvalRecommendations.map((recommendation) => releaseApprovalRecommendationSchema.parse(recommendation)),
|
|
1872
|
+
publishingPlan,
|
|
1873
|
+
trustStatus: "trusted-publishing-reviewed-separately",
|
|
1874
|
+
publishedPackages: [],
|
|
1875
|
+
tagRefs: [],
|
|
1876
|
+
provenanceRefs: allEvidenceRefs,
|
|
1877
|
+
rollbackNotes,
|
|
1878
|
+
externalDependencies
|
|
1879
|
+
}
|
|
1880
|
+
});
|
|
1881
|
+
return agentOutputSchema.parse({
|
|
1882
|
+
summary,
|
|
1883
|
+
findings: [],
|
|
1884
|
+
proposedActions: [],
|
|
1885
|
+
lifecycleArtifacts: [releaseReport],
|
|
1886
|
+
requestedTools: [],
|
|
1887
|
+
blockedActionFlags: [],
|
|
1888
|
+
confidence: 0.77,
|
|
1889
|
+
metadata: {
|
|
1890
|
+
deterministicInputs: {
|
|
1891
|
+
versionTargets: releaseRequest.versionTargets,
|
|
1892
|
+
qaReportRefs,
|
|
1893
|
+
securityReportRefs,
|
|
1894
|
+
evidenceSources,
|
|
1895
|
+
constraints,
|
|
1896
|
+
normalizedEvidence: normalizedEvidence ?? null
|
|
1897
|
+
},
|
|
1898
|
+
synthesizedAssessment: {
|
|
1899
|
+
readinessStatus,
|
|
1900
|
+
approvalRecommendations,
|
|
1901
|
+
publishingPlan,
|
|
1902
|
+
rollbackNotes
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
});
|
|
1906
|
+
}
|
|
1907
|
+
};
|
|
1908
|
+
const securityEvidenceNormalizationAgent = {
|
|
1909
|
+
manifest: agentManifestSchema.parse({
|
|
1910
|
+
version: 1,
|
|
1911
|
+
name: "security-evidence-normalizer",
|
|
1912
|
+
displayName: "Security Evidence Normalizer",
|
|
1913
|
+
category: "security",
|
|
1914
|
+
runtime: {
|
|
1915
|
+
minVersion: "0.1.0",
|
|
1916
|
+
kind: "deterministic"
|
|
1917
|
+
},
|
|
1918
|
+
permissions: {
|
|
1919
|
+
model: false,
|
|
1920
|
+
network: false,
|
|
1921
|
+
tools: [],
|
|
1922
|
+
readPaths: [".agentops/requests/**", ".agentops/runs/**", "**/*.json", "**/*.md", "**/package.json"],
|
|
1923
|
+
writePaths: []
|
|
1924
|
+
},
|
|
1925
|
+
inputs: ["workflowInputs", "repo", "agentResults"],
|
|
1926
|
+
outputs: ["summary", "metadata"],
|
|
1927
|
+
contextPolicy: {
|
|
1928
|
+
sections: ["workflowInputs", "repo", "agentResults"],
|
|
1929
|
+
minimalContext: true
|
|
1930
|
+
},
|
|
1931
|
+
catalog: {
|
|
1932
|
+
domain: "security",
|
|
1933
|
+
supportLevel: "internal",
|
|
1934
|
+
maturity: "mvp",
|
|
1935
|
+
trustScope: "official-core-only"
|
|
1936
|
+
},
|
|
1937
|
+
trust: {
|
|
1938
|
+
tier: "core",
|
|
1939
|
+
source: "official",
|
|
1940
|
+
reviewed: true
|
|
1941
|
+
}
|
|
1942
|
+
}),
|
|
1943
|
+
outputSchema: agentOutputSchema,
|
|
1944
|
+
async execute({ stateSlice }) {
|
|
1945
|
+
const securityRequest = getWorkflowInput(stateSlice, "securityRequest");
|
|
1946
|
+
if (!securityRequest) {
|
|
1947
|
+
throw new Error("security-review requires validated security request inputs before evidence normalization.");
|
|
1948
|
+
}
|
|
1949
|
+
const repoRoot = stateSlice.repo?.root;
|
|
1950
|
+
const intakeMetadata = isRecord(stateSlice.agentResults?.intake?.metadata) ? stateSlice.agentResults.intake.metadata : {};
|
|
1951
|
+
const targetType = typeof intakeMetadata.targetType === "string" && intakeMetadata.targetType === "artifact-bundle"
|
|
1952
|
+
? "artifact-bundle"
|
|
1953
|
+
: "local-reference";
|
|
1954
|
+
const targetPath = repoRoot ? join(repoRoot, securityRequest.targetRef) : securityRequest.targetRef;
|
|
1955
|
+
if (repoRoot && !existsSync(targetPath)) {
|
|
1956
|
+
throw new Error(`Security target reference not found: ${securityRequest.targetRef}`);
|
|
1957
|
+
}
|
|
1958
|
+
const referencedArtifactKinds = targetType === "artifact-bundle" ? loadBundleArtifactKinds(targetPath) : [];
|
|
1959
|
+
const normalizedEvidenceSources = [...new Set([securityRequest.targetRef, ...securityRequest.evidenceSources])];
|
|
1960
|
+
const missingEvidenceSources = normalizedEvidenceSources.filter((pathValue) => repoRoot && !existsSync(join(repoRoot, pathValue)));
|
|
1961
|
+
if (missingEvidenceSources.length > 0) {
|
|
1962
|
+
throw new Error(`Security evidence source not found: ${missingEvidenceSources[0]}`);
|
|
1963
|
+
}
|
|
1964
|
+
const normalizedFocusAreas = securityRequest.focusAreas.length > 0 ? [...new Set(securityRequest.focusAreas)] : ["general-review"];
|
|
1965
|
+
const affectedPackages = targetType === "artifact-bundle"
|
|
1966
|
+
? [...new Set(loadBundleArtifactPayloadPaths(targetPath).map(derivePackageScope).filter((value) => Boolean(value)))]
|
|
1967
|
+
: [];
|
|
1968
|
+
const securitySignals = [
|
|
1969
|
+
...(referencedArtifactKinds.length > 0 ? [`Referenced artifact kinds: ${referencedArtifactKinds.join(", ")}`] : []),
|
|
1970
|
+
...(affectedPackages.length > 0 ? [`Affected packages inferred from bounded artifact payloads: ${affectedPackages.join(", ")}`] : []),
|
|
1971
|
+
...(normalizedFocusAreas.length > 0 ? [`Requested focus areas: ${normalizedFocusAreas.join(", ")}`] : []),
|
|
1972
|
+
"Security evidence collection remains local, read-only, and bounded to validated references."
|
|
1973
|
+
];
|
|
1974
|
+
const provenanceRefs = [
|
|
1975
|
+
securityRequest.targetRef,
|
|
1976
|
+
...securityRequest.evidenceSources,
|
|
1977
|
+
...referencedArtifactKinds.map((artifactKind) => `${securityRequest.targetRef}#${artifactKind}`)
|
|
1978
|
+
];
|
|
1979
|
+
const normalization = securityEvidenceNormalizationSchema.parse({
|
|
1980
|
+
targetRef: securityRequest.targetRef,
|
|
1981
|
+
targetType,
|
|
1982
|
+
referencedArtifactKinds,
|
|
1983
|
+
normalizedEvidenceSources,
|
|
1984
|
+
missingEvidenceSources: [],
|
|
1985
|
+
normalizedFocusAreas,
|
|
1986
|
+
securitySignals,
|
|
1987
|
+
provenanceRefs: [...new Set(provenanceRefs)],
|
|
1988
|
+
affectedPackages
|
|
1989
|
+
});
|
|
1990
|
+
return agentOutputSchema.parse({
|
|
1991
|
+
summary: `Normalized security evidence for ${securityRequest.targetRef}.`,
|
|
1992
|
+
findings: [],
|
|
1993
|
+
proposedActions: [],
|
|
1994
|
+
lifecycleArtifacts: [],
|
|
1995
|
+
requestedTools: [],
|
|
1996
|
+
blockedActionFlags: [],
|
|
1997
|
+
metadata: normalization
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
};
|
|
2001
|
+
const securityAnalystAgent = {
|
|
2002
|
+
manifest: agentManifestSchema.parse({
|
|
2003
|
+
version: 1,
|
|
2004
|
+
name: "security-analyst",
|
|
2005
|
+
displayName: "Security Analyst",
|
|
2006
|
+
category: "security",
|
|
2007
|
+
runtime: {
|
|
2008
|
+
minVersion: "0.1.0",
|
|
2009
|
+
kind: "reasoning"
|
|
2010
|
+
},
|
|
2011
|
+
permissions: {
|
|
2012
|
+
model: true,
|
|
2013
|
+
network: false,
|
|
2014
|
+
tools: [],
|
|
2015
|
+
readPaths: ["**/*"],
|
|
2016
|
+
writePaths: []
|
|
2017
|
+
},
|
|
2018
|
+
inputs: ["workflowInputs", "repo", "changes", "agentResults"],
|
|
2019
|
+
outputs: ["lifecycleArtifacts"],
|
|
2020
|
+
contextPolicy: {
|
|
2021
|
+
sections: ["workflowInputs", "repo", "changes", "agentResults"],
|
|
2022
|
+
minimalContext: true
|
|
2023
|
+
},
|
|
2024
|
+
catalog: {
|
|
2025
|
+
domain: "security",
|
|
2026
|
+
supportLevel: "internal",
|
|
2027
|
+
maturity: "mvp",
|
|
2028
|
+
trustScope: "official-core-only"
|
|
2029
|
+
},
|
|
2030
|
+
trust: {
|
|
2031
|
+
tier: "core",
|
|
2032
|
+
source: "official",
|
|
2033
|
+
reviewed: true
|
|
2034
|
+
}
|
|
2035
|
+
}),
|
|
2036
|
+
outputSchema: agentOutputSchema,
|
|
2037
|
+
async execute({ state, stateSlice }) {
|
|
2038
|
+
const securityRequest = getWorkflowInput(stateSlice, "securityRequest");
|
|
2039
|
+
const securityIssueRefs = getWorkflowInput(stateSlice, "securityIssueRefs") ?? [];
|
|
2040
|
+
const securityGithubRefs = getWorkflowInput(stateSlice, "securityGithubRefs") ?? [];
|
|
2041
|
+
const requestFile = getWorkflowInput(stateSlice, "requestFile");
|
|
2042
|
+
if (!securityRequest) {
|
|
2043
|
+
throw new Error("security-review requires validated security inputs before security analysis.");
|
|
2044
|
+
}
|
|
2045
|
+
const intakeMetadata = isRecord(stateSlice.agentResults?.intake?.metadata) ? stateSlice.agentResults.intake.metadata : {};
|
|
2046
|
+
const evidenceMetadata = securityEvidenceNormalizationSchema.safeParse(stateSlice.agentResults?.evidence?.metadata);
|
|
2047
|
+
const normalizedEvidence = evidenceMetadata.success ? evidenceMetadata.data : undefined;
|
|
2048
|
+
const referencedArtifactKinds = normalizedEvidence?.referencedArtifactKinds ?? asStringArray(intakeMetadata.referencedArtifactKinds);
|
|
2049
|
+
const normalizedFocusAreas = normalizedEvidence?.normalizedFocusAreas ?? asStringArray(intakeMetadata.focusAreas);
|
|
2050
|
+
const normalizedConstraints = asStringArray(intakeMetadata.constraints);
|
|
2051
|
+
const evidenceSources = normalizedEvidence?.normalizedEvidenceSources && normalizedEvidence.normalizedEvidenceSources.length > 0
|
|
2052
|
+
? normalizedEvidence.normalizedEvidenceSources
|
|
2053
|
+
: asStringArray(intakeMetadata.evidenceSources).length > 0
|
|
2054
|
+
? asStringArray(intakeMetadata.evidenceSources)
|
|
2055
|
+
: [...new Set([securityRequest.targetRef, ...securityRequest.evidenceSources])];
|
|
2056
|
+
const focusAreas = normalizedFocusAreas.length > 0 ? normalizedFocusAreas : securityRequest.focusAreas;
|
|
2057
|
+
const inferredSeverity = securityRequest.releaseContext === "blocking" ? "high" : securityRequest.releaseContext === "candidate" ? "medium" : "low";
|
|
2058
|
+
const findings = focusAreas.length > 0
|
|
2059
|
+
? focusAreas.map((focusArea, index) => ({
|
|
2060
|
+
id: `security-finding-${index + 1}`,
|
|
2061
|
+
title: `Inspect ${focusArea} evidence before promotion`,
|
|
2062
|
+
summary: `Security review flagged ${focusArea} for bounded follow-up on ${securityRequest.targetRef}.`,
|
|
2063
|
+
severity: inferredSeverity,
|
|
2064
|
+
rationale: "The MVP security workflow synthesizes a structured report from validated references before deterministic evidence normalization lands.",
|
|
2065
|
+
confidence: 0.76,
|
|
2066
|
+
location: securityRequest.targetRef,
|
|
2067
|
+
tags: ["security", focusArea]
|
|
2068
|
+
}))
|
|
2069
|
+
: [
|
|
2070
|
+
{
|
|
2071
|
+
id: "security-finding-1",
|
|
2072
|
+
title: "Inspect referenced security evidence before promotion",
|
|
2073
|
+
summary: `Security review requires bounded interpretation of the referenced evidence for ${securityRequest.targetRef}.`,
|
|
2074
|
+
severity: inferredSeverity,
|
|
2075
|
+
rationale: "The current security workflow is read-only and request-driven, so findings remain tied to validated local references rather than automatic scanning.",
|
|
2076
|
+
confidence: 0.72,
|
|
2077
|
+
location: securityRequest.targetRef,
|
|
2078
|
+
tags: ["security", "evidence"]
|
|
2079
|
+
}
|
|
2080
|
+
];
|
|
2081
|
+
const mitigations = [
|
|
2082
|
+
...focusAreas.map((focusArea) => `Review ${focusArea} evidence and document the release impact before promotion.`),
|
|
2083
|
+
...(normalizedConstraints.length > 0 ? [`Keep security follow-up bounded by: ${normalizedConstraints.join("; ")}.`] : [])
|
|
2084
|
+
];
|
|
2085
|
+
const followUpWork = [
|
|
2086
|
+
...(normalizedEvidence?.securitySignals ?? []),
|
|
2087
|
+
...(referencedArtifactKinds.length > 0
|
|
2088
|
+
? [`Confirm the security posture for referenced artifacts: ${referencedArtifactKinds.join(", ")}.`]
|
|
2089
|
+
: []),
|
|
2090
|
+
"Use deterministic security evidence normalization outputs before broadening the workflow surface."
|
|
2091
|
+
];
|
|
2092
|
+
const summary = `Security report prepared for ${securityRequest.targetRef}.`;
|
|
2093
|
+
const securityReport = securityArtifactSchema.parse({
|
|
2094
|
+
...buildLifecycleArtifactEnvelopeBase(state, "Security Review", summary, [
|
|
2095
|
+
requestFile ?? ".agentops/requests/security.yaml",
|
|
2096
|
+
...(normalizedEvidence?.provenanceRefs ?? [securityRequest.targetRef, ...securityRequest.evidenceSources])
|
|
2097
|
+
], securityIssueRefs, securityGithubRefs),
|
|
2098
|
+
artifactKind: "security-report",
|
|
2099
|
+
lifecycleDomain: "security",
|
|
2100
|
+
redaction: {
|
|
2101
|
+
applied: true,
|
|
2102
|
+
strategyVersion: "1.0.0",
|
|
2103
|
+
categories: ["github-token", "api-key", "aws-key", "bearer-token", "password", "private-key", "security-sensitive"]
|
|
2104
|
+
},
|
|
2105
|
+
payload: {
|
|
2106
|
+
targetRef: securityRequest.targetRef,
|
|
2107
|
+
evidenceSources,
|
|
2108
|
+
findings,
|
|
2109
|
+
severitySummary: `highest severity: ${inferredSeverity}; ${findings.length} synthesized security finding(s).`,
|
|
2110
|
+
mitigations: mitigations.length > 0
|
|
2111
|
+
? mitigations
|
|
2112
|
+
: ["Review the referenced security evidence before promoting this workflow output."],
|
|
2113
|
+
releaseImpact: securityRequest.releaseContext === "blocking"
|
|
2114
|
+
? "release-blocking security findings require resolution before promotion."
|
|
2115
|
+
: securityRequest.releaseContext === "candidate"
|
|
2116
|
+
? "candidate release requires explicit security review before promotion."
|
|
2117
|
+
: "no release context was supplied; security output remains advisory.",
|
|
2118
|
+
followUpWork
|
|
2119
|
+
}
|
|
2120
|
+
});
|
|
2121
|
+
return agentOutputSchema.parse({
|
|
2122
|
+
summary,
|
|
2123
|
+
findings: [],
|
|
2124
|
+
proposedActions: [],
|
|
2125
|
+
lifecycleArtifacts: [securityReport],
|
|
2126
|
+
requestedTools: [],
|
|
2127
|
+
blockedActionFlags: [],
|
|
2128
|
+
confidence: 0.76,
|
|
2129
|
+
metadata: {
|
|
2130
|
+
deterministicInputs: {
|
|
2131
|
+
targetRef: securityRequest.targetRef,
|
|
2132
|
+
evidenceSources,
|
|
2133
|
+
focusAreas,
|
|
2134
|
+
constraints: normalizedConstraints,
|
|
2135
|
+
referencedArtifactKinds,
|
|
2136
|
+
normalizedEvidence: normalizedEvidence ?? null
|
|
2137
|
+
},
|
|
2138
|
+
synthesizedAssessment: {
|
|
2139
|
+
severitySummary: securityReport.payload.severitySummary,
|
|
2140
|
+
mitigations: securityReport.payload.mitigations,
|
|
2141
|
+
followUpWork: securityReport.payload.followUpWork
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
2146
|
+
};
|
|
2147
|
+
const qaEvidenceNormalizationAgent = {
|
|
2148
|
+
manifest: agentManifestSchema.parse({
|
|
2149
|
+
version: 1,
|
|
2150
|
+
name: "qa-evidence-normalizer",
|
|
2151
|
+
displayName: "QA Evidence Normalizer",
|
|
2152
|
+
category: "qa",
|
|
2153
|
+
runtime: {
|
|
2154
|
+
minVersion: "0.1.0",
|
|
2155
|
+
kind: "deterministic"
|
|
2156
|
+
},
|
|
2157
|
+
permissions: {
|
|
2158
|
+
model: false,
|
|
2159
|
+
network: false,
|
|
2160
|
+
tools: [],
|
|
2161
|
+
readPaths: [".agentops/requests/**", ".agentops/runs/**", "**/package.json", "**/*.json", "**/*.xml", "**/*.log", "**/*.md"],
|
|
2162
|
+
writePaths: []
|
|
2163
|
+
},
|
|
2164
|
+
inputs: ["workflowInputs", "repo", "agentResults"],
|
|
2165
|
+
outputs: ["summary", "metadata"],
|
|
2166
|
+
contextPolicy: {
|
|
2167
|
+
sections: ["workflowInputs", "repo", "agentResults"],
|
|
2168
|
+
minimalContext: true
|
|
2169
|
+
},
|
|
2170
|
+
catalog: {
|
|
2171
|
+
domain: "test",
|
|
2172
|
+
supportLevel: "internal",
|
|
2173
|
+
maturity: "mvp",
|
|
2174
|
+
trustScope: "official-core-only"
|
|
2175
|
+
},
|
|
2176
|
+
trust: {
|
|
2177
|
+
tier: "core",
|
|
2178
|
+
source: "official",
|
|
2179
|
+
reviewed: true
|
|
2180
|
+
}
|
|
2181
|
+
}),
|
|
2182
|
+
outputSchema: agentOutputSchema,
|
|
2183
|
+
async execute({ stateSlice }) {
|
|
2184
|
+
const qaRequest = getWorkflowInput(stateSlice, "qaRequest");
|
|
2185
|
+
if (!qaRequest) {
|
|
2186
|
+
throw new Error("qa-review requires validated QA request inputs before evidence normalization.");
|
|
2187
|
+
}
|
|
2188
|
+
const repoRoot = stateSlice.repo?.root;
|
|
2189
|
+
const packageManager = stateSlice.repo?.packageManager || "pnpm";
|
|
2190
|
+
const intakeMetadata = isRecord(stateSlice.agentResults?.intake?.metadata) ? stateSlice.agentResults.intake.metadata : {};
|
|
2191
|
+
const targetType = typeof intakeMetadata.targetType === "string" ? intakeMetadata.targetType : "local-reference";
|
|
2192
|
+
const targetPath = repoRoot ? join(repoRoot, qaRequest.targetRef) : qaRequest.targetRef;
|
|
2193
|
+
if (repoRoot && !existsSync(targetPath)) {
|
|
2194
|
+
throw new Error(`QA target reference not found: ${qaRequest.targetRef}`);
|
|
2195
|
+
}
|
|
2196
|
+
const referencedArtifactKinds = targetType === "artifact-bundle" ? loadBundleArtifactKinds(targetPath) : [];
|
|
2197
|
+
const normalizedEvidenceSources = [...new Set([qaRequest.targetRef, ...qaRequest.evidenceSources])];
|
|
2198
|
+
const missingEvidenceSources = normalizedEvidenceSources.filter((pathValue) => repoRoot && !existsSync(join(repoRoot, pathValue)));
|
|
2199
|
+
if (missingEvidenceSources.length > 0) {
|
|
2200
|
+
throw new Error(`QA evidence source not found: ${missingEvidenceSources[0]}`);
|
|
2201
|
+
}
|
|
2202
|
+
const bundleAffectedPaths = targetType === "artifact-bundle" && referencedArtifactKinds.includes("implementation-proposal") && existsSync(targetPath)
|
|
2203
|
+
? asStringArray((() => {
|
|
2204
|
+
const parsed = JSON.parse(readFileSync(targetPath, "utf8"));
|
|
2205
|
+
if (!isRecord(parsed) || !Array.isArray(parsed.lifecycleArtifacts)) {
|
|
1058
2206
|
return [];
|
|
1059
2207
|
}
|
|
1060
2208
|
const implementationArtifact = parsed.lifecycleArtifacts.find((artifact) => isRecord(artifact) &&
|
|
@@ -1069,6 +2217,7 @@ const qaEvidenceNormalizationAgent = {
|
|
|
1069
2217
|
const allowlistedCommands = new Set(allowedValidationCommands.map((entry) => entry.command));
|
|
1070
2218
|
const normalizedExecutedChecks = qaRequest.executedChecks.map(normalizeRequestedCommand);
|
|
1071
2219
|
const unrecognizedExecutedChecks = normalizedExecutedChecks.filter((command) => !allowlistedCommands.has(command));
|
|
2220
|
+
const githubActions = normalizeGitHubActionsEvidence(repoRoot, normalizedEvidenceSources);
|
|
1072
2221
|
const normalization = qaEvidenceNormalizationSchema.parse({
|
|
1073
2222
|
targetRef: qaRequest.targetRef,
|
|
1074
2223
|
targetType,
|
|
@@ -1078,10 +2227,11 @@ const qaEvidenceNormalizationAgent = {
|
|
|
1078
2227
|
normalizedExecutedChecks,
|
|
1079
2228
|
unrecognizedExecutedChecks,
|
|
1080
2229
|
affectedPackages,
|
|
1081
|
-
allowedValidationCommands
|
|
2230
|
+
allowedValidationCommands,
|
|
2231
|
+
githubActions
|
|
1082
2232
|
});
|
|
1083
2233
|
return agentOutputSchema.parse({
|
|
1084
|
-
summary: `Normalized QA evidence across ${normalization.normalizedEvidenceSources.length} source(s)
|
|
2234
|
+
summary: `Normalized QA evidence across ${normalization.normalizedEvidenceSources.length} source(s), ${normalization.allowedValidationCommands.length} allowlisted validation command(s), and ${normalization.githubActions.evidence.length} GitHub Actions evidence export(s).`,
|
|
1085
2235
|
findings: [],
|
|
1086
2236
|
proposedActions: [],
|
|
1087
2237
|
lifecycleArtifacts: [],
|
|
@@ -1129,20 +2279,31 @@ const qaAnalystAgent = {
|
|
|
1129
2279
|
outputSchema: agentOutputSchema,
|
|
1130
2280
|
async execute({ state, stateSlice }) {
|
|
1131
2281
|
const qaRequest = getWorkflowInput(stateSlice, "qaRequest");
|
|
2282
|
+
const qaIssueRefs = getWorkflowInput(stateSlice, "qaIssueRefs") ?? [];
|
|
2283
|
+
const qaGithubRefs = getWorkflowInput(stateSlice, "qaGithubRefs") ?? [];
|
|
1132
2284
|
const requestFile = getWorkflowInput(stateSlice, "requestFile");
|
|
1133
2285
|
if (!qaRequest) {
|
|
1134
2286
|
throw new Error("qa-review requires validated QA inputs before QA analysis.");
|
|
1135
2287
|
}
|
|
1136
2288
|
const intakeMetadata = isRecord(stateSlice.agentResults?.intake?.metadata) ? stateSlice.agentResults.intake.metadata : {};
|
|
1137
|
-
const evidenceMetadata =
|
|
1138
|
-
const
|
|
1139
|
-
const
|
|
2289
|
+
const evidenceMetadata = qaEvidenceNormalizationSchema.safeParse(stateSlice.agentResults?.evidence?.metadata);
|
|
2290
|
+
const normalizedEvidence = evidenceMetadata.success ? evidenceMetadata.data : undefined;
|
|
2291
|
+
const normalizedEvidenceSources = normalizedEvidence?.normalizedEvidenceSources ?? [];
|
|
2292
|
+
const normalizedExecutedChecks = normalizedEvidence?.normalizedExecutedChecks ?? [];
|
|
1140
2293
|
const normalizedFocusAreas = asStringArray(intakeMetadata.focusAreas);
|
|
1141
2294
|
const normalizedConstraints = asStringArray(intakeMetadata.constraints);
|
|
1142
|
-
const missingEvidenceSources =
|
|
1143
|
-
const unrecognizedExecutedChecks =
|
|
1144
|
-
const
|
|
1145
|
-
?
|
|
2295
|
+
const missingEvidenceSources = normalizedEvidence?.missingEvidenceSources ?? [];
|
|
2296
|
+
const unrecognizedExecutedChecks = normalizedEvidence?.unrecognizedExecutedChecks ?? [];
|
|
2297
|
+
const normalizedGithubActions = normalizedEvidence
|
|
2298
|
+
? normalizedEvidence.githubActions
|
|
2299
|
+
: {
|
|
2300
|
+
evidence: [],
|
|
2301
|
+
workflowNames: [],
|
|
2302
|
+
failingChecks: [],
|
|
2303
|
+
provenanceRefs: []
|
|
2304
|
+
};
|
|
2305
|
+
const targetType = normalizedEvidence?.targetType
|
|
2306
|
+
? normalizedEvidence.targetType
|
|
1146
2307
|
: typeof intakeMetadata.targetType === "string"
|
|
1147
2308
|
? intakeMetadata.targetType
|
|
1148
2309
|
: "local-reference";
|
|
@@ -1179,16 +2340,23 @@ const qaAnalystAgent = {
|
|
|
1179
2340
|
...missingEvidenceSources.map((pathValue) => `Referenced QA evidence is missing: ${pathValue}`),
|
|
1180
2341
|
...(focusAreas.includes("coverage") ? ["Coverage evidence still needs deterministic normalization before it can be promoted to an official QA signal."] : []),
|
|
1181
2342
|
...(executedChecks.length === 0 ? ["No executed validation checks were recorded in the request."] : []),
|
|
1182
|
-
...unrecognizedExecutedChecks.map((command) => `Executed check is outside the bounded allowlist and still needs manual interpretation: ${command}`)
|
|
2343
|
+
...unrecognizedExecutedChecks.map((command) => `Executed check is outside the bounded allowlist and still needs manual interpretation: ${command}`),
|
|
2344
|
+
...normalizedGithubActions.failingChecks.map((checkName) => `GitHub Actions evidence still reports a failing check that needs manual review: ${checkName}`)
|
|
1183
2345
|
];
|
|
1184
2346
|
const recommendedNextChecks = [
|
|
1185
2347
|
...executedChecks.map((command) => `Review the recorded output for \`${command}\` before promotion.`),
|
|
1186
2348
|
...focusAreas.map((focusArea) => `Confirm whether ${focusArea} needs additional deterministic QA evidence.`),
|
|
2349
|
+
...normalizedGithubActions.workflowNames.map((workflowName) => `Review the exported GitHub Actions evidence for workflow \`${workflowName}\` before promotion.`),
|
|
1187
2350
|
...(normalizedConstraints.length > 0 ? [`Keep QA follow-up bounded by: ${normalizedConstraints.join("; ")}.`] : [])
|
|
1188
2351
|
];
|
|
1189
2352
|
const summary = `QA report prepared for ${qaRequest.targetRef}.`;
|
|
2353
|
+
const releaseImpactBase = qaRequest.releaseContext === "blocking"
|
|
2354
|
+
? "release-blocking QA findings require resolution before promotion."
|
|
2355
|
+
: qaRequest.releaseContext === "candidate"
|
|
2356
|
+
? "candidate release still requires explicit QA review before promotion."
|
|
2357
|
+
: "no release context was supplied; QA output remains advisory.";
|
|
1190
2358
|
const qaReport = qaArtifactSchema.parse({
|
|
1191
|
-
...buildArtifactEnvelopeBase(state, summary, [requestFile ?? ".agentops/requests/qa.yaml", qaRequest.targetRef, ...qaRequest.evidenceSources],
|
|
2359
|
+
...buildArtifactEnvelopeBase(state, summary, [requestFile ?? ".agentops/requests/qa.yaml", qaRequest.targetRef, ...qaRequest.evidenceSources], qaIssueRefs, qaGithubRefs),
|
|
1192
2360
|
artifactKind: "qa-report",
|
|
1193
2361
|
lifecycleDomain: "test",
|
|
1194
2362
|
workflow: {
|
|
@@ -1204,11 +2372,9 @@ const qaAnalystAgent = {
|
|
|
1204
2372
|
recommendedNextChecks: recommendedNextChecks.length > 0
|
|
1205
2373
|
? recommendedNextChecks
|
|
1206
2374
|
: ["Capture additional bounded QA evidence before promotion."],
|
|
1207
|
-
releaseImpact:
|
|
1208
|
-
?
|
|
1209
|
-
:
|
|
1210
|
-
? "candidate release still requires explicit QA review before promotion."
|
|
1211
|
-
: "no release context was supplied; QA output remains advisory."
|
|
2375
|
+
releaseImpact: normalizedGithubActions.failingChecks.length > 0
|
|
2376
|
+
? `${releaseImpactBase} GitHub Actions evidence still shows failing checks: ${normalizedGithubActions.failingChecks.join(", ")}.`
|
|
2377
|
+
: releaseImpactBase
|
|
1212
2378
|
}
|
|
1213
2379
|
});
|
|
1214
2380
|
return agentOutputSchema.parse({
|
|
@@ -1226,7 +2392,8 @@ const qaAnalystAgent = {
|
|
|
1226
2392
|
evidenceSources,
|
|
1227
2393
|
executedChecks,
|
|
1228
2394
|
focusAreas,
|
|
1229
|
-
constraints: normalizedConstraints
|
|
2395
|
+
constraints: normalizedConstraints,
|
|
2396
|
+
githubActions: normalizedGithubActions
|
|
1230
2397
|
},
|
|
1231
2398
|
synthesizedAssessment: {
|
|
1232
2399
|
releaseContext: qaRequest.releaseContext,
|
|
@@ -1435,7 +2602,7 @@ const implementationPlannerAgent = {
|
|
|
1435
2602
|
];
|
|
1436
2603
|
const summary = `Implementation proposal prepared for ${implementationRequest.implementationGoal}.`;
|
|
1437
2604
|
const implementationProposal = implementationArtifactSchema.parse({
|
|
1438
|
-
...buildArtifactEnvelopeBase(state, summary, [requestFile ?? ".agentops/requests/implementation.yaml", implementationRequest.designRecordRef], designRecord.source.issueRefs),
|
|
2605
|
+
...buildArtifactEnvelopeBase(state, summary, [requestFile ?? ".agentops/requests/implementation.yaml", implementationRequest.designRecordRef], designRecord.source.issueRefs, designRecord.source.githubRefs),
|
|
1439
2606
|
artifactKind: "implementation-proposal",
|
|
1440
2607
|
lifecycleDomain: "build",
|
|
1441
2608
|
workflow: {
|
|
@@ -1548,7 +2715,7 @@ const designAnalystAgent = {
|
|
|
1548
2715
|
];
|
|
1549
2716
|
const summary = `Design record prepared for ${designRequest.decisionTarget}.`;
|
|
1550
2717
|
const designRecord = designArtifactSchema.parse({
|
|
1551
|
-
...buildArtifactEnvelopeBase(state, summary, [requestFile ?? ".agentops/requests/design.yaml", designRequest.planningBriefRef], planningBrief.source.issueRefs),
|
|
2718
|
+
...buildArtifactEnvelopeBase(state, summary, [requestFile ?? ".agentops/requests/design.yaml", designRequest.planningBriefRef], planningBrief.source.issueRefs, planningBrief.source.githubRefs),
|
|
1552
2719
|
artifactKind: "design-record",
|
|
1553
2720
|
lifecycleDomain: "design",
|
|
1554
2721
|
workflow: {
|
|
@@ -1837,6 +3004,15 @@ export function createBuiltinAgentRegistry() {
|
|
|
1837
3004
|
["implementation-intake", implementationIntakeAgent],
|
|
1838
3005
|
["qa-intake", qaIntakeAgent],
|
|
1839
3006
|
["security-intake", securityIntakeAgent],
|
|
3007
|
+
["incident-intake", incidentIntakeAgent],
|
|
3008
|
+
["incident-evidence-normalizer", incidentEvidenceNormalizationAgent],
|
|
3009
|
+
["maintenance-intake", maintenanceIntakeAgent],
|
|
3010
|
+
["maintenance-evidence-normalizer", maintenanceEvidenceNormalizerAgent],
|
|
3011
|
+
["maintenance-analyst", maintenanceAnalystAgent],
|
|
3012
|
+
["incident-analyst", incidentAnalystAgent],
|
|
3013
|
+
["release-intake", releaseIntakeAgent],
|
|
3014
|
+
["release-evidence-normalizer", releaseEvidenceNormalizationAgent],
|
|
3015
|
+
["release-analyst", releaseAnalystAgent],
|
|
1840
3016
|
["security-evidence-normalizer", securityEvidenceNormalizationAgent],
|
|
1841
3017
|
["security-analyst", securityAnalystAgent],
|
|
1842
3018
|
["qa-evidence-normalizer", qaEvidenceNormalizationAgent],
|