@ai-sdlc/orchestrator 0.4.0 → 0.5.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/adapters.d.ts +18 -3
- package/dist/adapters.js +92 -2
- package/dist/cli/commands/init.js +4 -8
- package/dist/cli/commands/run.js +2 -2
- package/dist/config.d.ts +3 -0
- package/dist/config.js +14 -5
- package/dist/execute.d.ts +5 -2
- package/dist/execute.js +101 -46
- package/dist/fix-ci.js +13 -11
- package/dist/index.d.ts +6 -4
- package/dist/index.js +6 -3
- package/dist/orchestrator.d.ts +1 -1
- package/dist/orchestrator.js +31 -9
- package/dist/plugin.d.ts +9 -3
- package/dist/priority.d.ts +102 -0
- package/dist/priority.js +230 -0
- package/dist/runners/claude-code.js +56 -6
- package/dist/runners/codex.js +15 -4
- package/dist/runners/copilot.js +15 -4
- package/dist/runners/cursor.js +15 -4
- package/dist/runners/generic-llm.js +1 -1
- package/dist/runners/index.d.ts +1 -0
- package/dist/runners/index.js +1 -0
- package/dist/runners/security-triage.d.ts +43 -0
- package/dist/runners/security-triage.js +154 -0
- package/dist/runners/types.d.ts +5 -1
- package/dist/security.d.ts +8 -3
- package/dist/security.js +13 -2
- package/dist/shared.d.ts +17 -0
- package/dist/shared.js +27 -0
- package/dist/state/index.d.ts +1 -1
- package/dist/state/schema.d.ts +3 -1
- package/dist/state/schema.js +36 -1
- package/dist/state/store.d.ts +15 -1
- package/dist/state/store.js +86 -13
- package/dist/state/types.d.ts +17 -0
- package/dist/triage.d.ts +36 -0
- package/dist/triage.js +133 -0
- package/dist/types.d.ts +1 -1
- package/dist/watch.d.ts +6 -2
- package/dist/watch.js +34 -6
- package/package.json +4 -2
package/dist/execute.js
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* load config -> fetch issue -> validate -> check autonomy ->
|
|
6
6
|
* create branch -> invoke agent -> authorize -> validate -> push -> create PR -> comment
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
8
|
+
import { createGitHubSourceControl, routeByComplexity, evaluatePromotion, evaluateComplexity, selectModel, withSpan, getMeter, SPAN_NAMES, METRIC_NAMES, ATTRIBUTE_KEYS, } from '@ai-sdlc/reference';
|
|
9
9
|
import { loadConfigAsync } from './config.js';
|
|
10
10
|
import { validateIssue, validateIssueWithExtensions, parseComplexity } from './validate-issue.js';
|
|
11
11
|
import { createLogger } from './logger.js';
|
|
12
12
|
import { createStructuredConsoleLogger, createStructuredBufferLogger, } from './structured-logger.js';
|
|
13
13
|
import { ClaudeCodeRunner } from './runners/claude-code.js';
|
|
14
|
-
import { execFileAsync, getGitHubConfig, resolveRepoRoot, createDefaultAuditLog, resolveAutonomyLevel, resolveConstraints, isAutonomousStrategy, recordMetric, validateAndAuditOutput, evaluatePipelineCompliance, authorizeFilesChanged, interpolateBranchPattern, interpolatePRTitle, } from './shared.js';
|
|
14
|
+
import { execFileAsync, getGitHubConfig, resolveRepoRoot, createDefaultAuditLog, resolveAutonomyLevel, resolveConstraints, isAutonomousStrategy, recordMetric, validateAndAuditOutput, evaluatePipelineCompliance, authorizeFilesChanged, interpolateBranchPattern, interpolatePRTitle, issueIdToNumber, formatIssueRef, } from './shared.js';
|
|
15
15
|
import { checkKillSwitch, issueAgentCredentials, revokeAgentCredentials, classifyAndSubmitApproval, createPipelineSecurity, } from './security.js';
|
|
16
16
|
import { createPipelineOrchestration, executePipelineOrchestration, validatePipelineHandoffs, } from './orchestration.js';
|
|
17
17
|
import { createPipelineProvenance, attachProvenanceToPR, validatePipelineProvenance, } from './provenance.js';
|
|
@@ -21,7 +21,9 @@ import { createPipelineExpressionEvaluator, createPipelineLLMEvaluator, createPi
|
|
|
21
21
|
import { verifyAuditIntegrity, createFileAuditLog, loadAuditEntries, computeAuditHash, } from './audit-extended.js';
|
|
22
22
|
import { renderTemplate } from './notifications.js';
|
|
23
23
|
import { admitIssueResource, createPipelineAdmission, } from './admission.js';
|
|
24
|
-
import { createPipelineAdapterRegistry, createPipelineWebhookBridge, resolveAdapterFromGit, scanPipelineAdapters, } from './adapters.js';
|
|
24
|
+
import { createPipelineAdapterRegistry, createPipelineWebhookBridge, resolveAdapterFromGit, scanPipelineAdapters, resolveIssueTrackerFromConfig, } from './adapters.js';
|
|
25
|
+
import { existsSync, readFileSync, appendFileSync } from 'node:fs';
|
|
26
|
+
import { join } from 'node:path';
|
|
25
27
|
import { defaultSandboxConstraints, DEFAULT_CONFIG_DIR_NAME, DEFAULT_PR_FOOTER, NOTIFICATION_TITLES, } from './defaults.js';
|
|
26
28
|
import { checkFrameworkCompliance, getControlCatalog, getFrameworkMappings, listSupportedFrameworks, } from './compliance-extended.js';
|
|
27
29
|
import { createSilentLogger, withPipelineSpanSync, getPipelineTracer, validateResourceSchema, } from './telemetry-extended.js';
|
|
@@ -31,9 +33,9 @@ import { CostTracker } from './cost-tracker.js';
|
|
|
31
33
|
import { enrichAgentContext } from './context-enrichment.js';
|
|
32
34
|
import { reportGateCheckRuns } from './check-runs.js';
|
|
33
35
|
/**
|
|
34
|
-
* Execute the full AI-SDLC pipeline for a given issue
|
|
36
|
+
* Execute the full AI-SDLC pipeline for a given issue ID.
|
|
35
37
|
*/
|
|
36
|
-
export async function executePipeline(
|
|
38
|
+
export async function executePipeline(issueId, options = {}) {
|
|
37
39
|
const workDir = options.workDir ?? (await resolveRepoRoot());
|
|
38
40
|
const configDir = options.configDir ?? `${workDir}/${DEFAULT_CONFIG_DIR_NAME}`;
|
|
39
41
|
const log = options.logger ??
|
|
@@ -86,22 +88,22 @@ export async function executePipeline(issueNumber, options = {}) {
|
|
|
86
88
|
// 2. Create adapters (or use injected ones)
|
|
87
89
|
const { org, repo } = getGitHubConfig(options.secretStore);
|
|
88
90
|
const ghConfig = { org, repo, token: { secretRef: 'github-token' } };
|
|
89
|
-
const tracker = options.tracker ??
|
|
91
|
+
const tracker = options.tracker ?? resolveIssueTrackerFromConfig(config, ghConfig);
|
|
90
92
|
const sc = options.sourceControl ?? createGitHubSourceControl(ghConfig);
|
|
91
93
|
// 3. Fetch issue
|
|
92
94
|
log.stage('validate-issue');
|
|
93
|
-
const issue = await tracker.getIssue(
|
|
95
|
+
const issue = await tracker.getIssue(issueId);
|
|
94
96
|
// Store issue context in working memory if provided
|
|
95
97
|
if (options.memory) {
|
|
96
98
|
options.memory.working.set('currentIssue', {
|
|
97
|
-
|
|
99
|
+
issueId,
|
|
98
100
|
title: issue.title,
|
|
99
101
|
description: issue.description,
|
|
100
102
|
});
|
|
101
103
|
}
|
|
102
104
|
// Wrap pipeline body in try/catch to record failure episodes
|
|
103
105
|
try {
|
|
104
|
-
return await executePipelineBody(
|
|
106
|
+
return await executePipelineBody(issueId, issue, config, qualityGate, agentRole, autonomyPolicy, tracker, sc, auditLog, metricStore, options, log, workDir);
|
|
105
107
|
}
|
|
106
108
|
catch (err) {
|
|
107
109
|
// Record failure episode before rethrowing
|
|
@@ -109,18 +111,19 @@ export async function executePipeline(issueNumber, options = {}) {
|
|
|
109
111
|
options.memory.episodic.append({
|
|
110
112
|
key: 'pipeline-execution',
|
|
111
113
|
value: {
|
|
112
|
-
|
|
114
|
+
issueId,
|
|
113
115
|
outcome: 'failure',
|
|
114
116
|
error: err instanceof Error ? err.message : String(err),
|
|
115
117
|
},
|
|
116
|
-
metadata: { summary: `Failed issue
|
|
118
|
+
metadata: { summary: `Failed issue ${formatIssueRef(issueId)}: ${issue.title}` },
|
|
117
119
|
});
|
|
118
120
|
options.memory.working.clear();
|
|
119
121
|
}
|
|
120
122
|
throw err;
|
|
121
123
|
}
|
|
122
124
|
}
|
|
123
|
-
async function executePipelineBody(
|
|
125
|
+
async function executePipelineBody(issueId, issue, config, qualityGate, agentRole, autonomyPolicy, tracker, sc, auditLog, metricStore, options, log, workDir) {
|
|
126
|
+
const issueNumber = issueIdToNumber(issueId);
|
|
124
127
|
const meter = getMeter();
|
|
125
128
|
// Discovery: register agent and resolve by issue labels
|
|
126
129
|
const discovery = createPipelineDiscovery();
|
|
@@ -167,7 +170,7 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
167
170
|
auditLog.record({
|
|
168
171
|
actor: 'system',
|
|
169
172
|
action: 'evaluate',
|
|
170
|
-
resource: `issue#${
|
|
173
|
+
resource: `issue#${issueId}`,
|
|
171
174
|
policy: qualityGate.metadata.name,
|
|
172
175
|
decision: 'denied',
|
|
173
176
|
details: {
|
|
@@ -183,13 +186,13 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
183
186
|
const gateFailTitle = gateFailTpl
|
|
184
187
|
? renderTemplate(gateFailTpl, { details: failures }).title
|
|
185
188
|
: NOTIFICATION_TITLES.issueValidationFailed;
|
|
186
|
-
await tracker.addComment(
|
|
187
|
-
throw new Error(`Issue
|
|
189
|
+
await tracker.addComment(issueId, `## ${gateFailTitle}\n\n${gateFailBody}`);
|
|
190
|
+
throw new Error(`Issue ${formatIssueRef(issueId)} failed quality gate validation:\n${failures}`);
|
|
188
191
|
}
|
|
189
192
|
auditLog.record({
|
|
190
193
|
actor: 'system',
|
|
191
194
|
action: 'evaluate',
|
|
192
|
-
resource: `issue#${
|
|
195
|
+
resource: `issue#${issueId}`,
|
|
193
196
|
policy: qualityGate.metadata.name,
|
|
194
197
|
decision: 'allowed',
|
|
195
198
|
});
|
|
@@ -202,7 +205,7 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
202
205
|
auditLog.record({
|
|
203
206
|
actor: 'system',
|
|
204
207
|
action: 'route',
|
|
205
|
-
resource: `issue#${
|
|
208
|
+
resource: `issue#${issueId}`,
|
|
206
209
|
decision: isAutonomousStrategy(strategy) ? 'allowed' : 'denied',
|
|
207
210
|
details: { score: complexity, strategy },
|
|
208
211
|
});
|
|
@@ -214,21 +217,21 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
214
217
|
title: NOTIFICATION_TITLES.complexityTooHigh,
|
|
215
218
|
body: `Issue complexity (${complexity}) routed as "${strategy}" — requires human involvement.`,
|
|
216
219
|
};
|
|
217
|
-
await tracker.addComment(
|
|
218
|
-
throw new Error(`Issue
|
|
220
|
+
await tracker.addComment(issueId, `## ${complexityComment.title}\n\n${complexityComment.body}`);
|
|
221
|
+
throw new Error(`Issue ${formatIssueRef(issueId)} complexity ${complexity} routed as "${strategy}"`);
|
|
219
222
|
}
|
|
220
223
|
// Approval workflow check (after routing, before agent)
|
|
221
224
|
if (options.security) {
|
|
222
|
-
const approval = await classifyAndSubmitApproval(options.security, complexity, agentRole.metadata.name, `Execute pipeline for issue
|
|
225
|
+
const approval = await classifyAndSubmitApproval(options.security, complexity, agentRole.metadata.name, `Execute pipeline for issue ${formatIssueRef(issueId)}`);
|
|
223
226
|
if (approval.status === 'pending') {
|
|
224
|
-
throw new Error(`Issue
|
|
227
|
+
throw new Error(`Issue ${formatIssueRef(issueId)} requires approval (tier: ${approval.tier}) — status is pending`);
|
|
225
228
|
}
|
|
226
229
|
}
|
|
227
230
|
// 6. Check autonomy level allows coding
|
|
228
231
|
const currentLevel = resolveAutonomyLevel(autonomyPolicy);
|
|
229
232
|
log.stageEnd('validate-issue');
|
|
230
233
|
// 7. Create branch and checkout locally (read pattern from pipeline config)
|
|
231
|
-
const branchVars = { issueNumber:
|
|
234
|
+
const branchVars = { issueNumber: issueId, issueTitle: issue.title };
|
|
232
235
|
const branchName = interpolateBranchPattern(config.pipeline?.spec.branching?.pattern, branchVars);
|
|
233
236
|
await sc.createBranch({ name: branchName });
|
|
234
237
|
await execFileAsync('git', ['fetch', 'origin', branchName], { cwd: workDir });
|
|
@@ -248,6 +251,9 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
248
251
|
log.info(`Model selected: ${modelResult.model} (${modelResult.reason})`);
|
|
249
252
|
}
|
|
250
253
|
}
|
|
254
|
+
// 8b. Ensure .gitignore covers runtime artifacts so the agent doesn't
|
|
255
|
+
// re-add entries on every run.
|
|
256
|
+
ensureRuntimeGitignore(workDir);
|
|
251
257
|
// 9. Invoke agent (with sandbox + JIT credential lifecycle when security is provided)
|
|
252
258
|
log.stage('agent');
|
|
253
259
|
const runner = options.runner ?? new ClaudeCodeRunner();
|
|
@@ -258,7 +264,7 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
258
264
|
try {
|
|
259
265
|
if (options.security) {
|
|
260
266
|
const timeoutMs = codeStage?.timeout ? parseDuration(codeStage.timeout) : undefined;
|
|
261
|
-
sandboxId = await options.security.sandbox.isolate(`issue-${
|
|
267
|
+
sandboxId = await options.security.sandbox.isolate(`issue-${issueId}`, defaultSandboxConstraints(workDir, timeoutMs));
|
|
262
268
|
}
|
|
263
269
|
// Issue JIT credentials before agent execution
|
|
264
270
|
const jitCred = options.security
|
|
@@ -272,7 +278,7 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
272
278
|
// Enrich agent context with episodic memory
|
|
273
279
|
const episodicContext = options.stateStore
|
|
274
280
|
? enrichAgentContext(options.stateStore, {
|
|
275
|
-
issueNumber,
|
|
281
|
+
issueNumber: issueNumber ?? undefined,
|
|
276
282
|
agentName: effectiveAgent.metadata.name,
|
|
277
283
|
files: result ? result.filesChanged : undefined,
|
|
278
284
|
})
|
|
@@ -280,9 +286,10 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
280
286
|
const orchestrationResult = await executePipelineOrchestration(plan, [effectiveAgent], async (agent) => {
|
|
281
287
|
return withSpan(SPAN_NAMES.AGENT_TASK, {
|
|
282
288
|
[ATTRIBUTE_KEYS.AGENT]: agent.metadata.name,
|
|
283
|
-
[ATTRIBUTE_KEYS.RESOURCE_NAME]: `issue#${
|
|
289
|
+
[ATTRIBUTE_KEYS.RESOURCE_NAME]: `issue#${issueId}`,
|
|
284
290
|
}, () => runner.run({
|
|
285
|
-
|
|
291
|
+
issueId,
|
|
292
|
+
issueNumber: issueNumber ?? undefined,
|
|
286
293
|
issueTitle: issue.title,
|
|
287
294
|
issueBody: issue.description ?? '',
|
|
288
295
|
workDir,
|
|
@@ -296,6 +303,7 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
296
303
|
memory: options.memory,
|
|
297
304
|
codebaseContext: options.codebaseContext,
|
|
298
305
|
episodicContext,
|
|
306
|
+
sandboxId,
|
|
299
307
|
}));
|
|
300
308
|
});
|
|
301
309
|
// Extract the AgentResult from orchestration output
|
|
@@ -319,8 +327,8 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
319
327
|
const agentFailComment = agentFailTpl
|
|
320
328
|
? renderTemplate(agentFailTpl, { stageName: 'code', details: errorDetail })
|
|
321
329
|
: { title: NOTIFICATION_TITLES.agentFailed, body: errorDetail };
|
|
322
|
-
await tracker.addComment(
|
|
323
|
-
throw new Error(`Agent failed on issue
|
|
330
|
+
await tracker.addComment(issueId, `## ${agentFailComment.title}\n\n${agentFailComment.body}`);
|
|
331
|
+
throw new Error(`Agent failed on issue ${formatIssueRef(issueId)}: ${err}`);
|
|
324
332
|
}
|
|
325
333
|
result = stepOutput;
|
|
326
334
|
log.stageEnd('agent');
|
|
@@ -367,7 +375,7 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
367
375
|
auditLog,
|
|
368
376
|
log,
|
|
369
377
|
onViolation: async (violationList) => {
|
|
370
|
-
await tracker.addComment(
|
|
378
|
+
await tracker.addComment(issueId, `## ${NOTIFICATION_TITLES.guardrailViolations}\n\n${violationList}`);
|
|
371
379
|
},
|
|
372
380
|
});
|
|
373
381
|
});
|
|
@@ -396,7 +404,7 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
396
404
|
auditLog.record({
|
|
397
405
|
actor: 'system',
|
|
398
406
|
action: 'evaluate',
|
|
399
|
-
resource: `issue#${
|
|
407
|
+
resource: `issue#${issueId}`,
|
|
400
408
|
policy: 'post-agent-gates',
|
|
401
409
|
decision: gateResults.every((g) => g.verdict === 'pass') ? 'allowed' : 'denied',
|
|
402
410
|
details: {
|
|
@@ -423,7 +431,7 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
423
431
|
auditLog.record({
|
|
424
432
|
actor: 'system',
|
|
425
433
|
action: 'evaluate',
|
|
426
|
-
resource: `issue#${
|
|
434
|
+
resource: `issue#${issueId}`,
|
|
427
435
|
policy: 'post-agent-complexity',
|
|
428
436
|
decision: 'allowed',
|
|
429
437
|
details: {
|
|
@@ -468,9 +476,14 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
468
476
|
promptText: issue.description,
|
|
469
477
|
cost: costReceipt,
|
|
470
478
|
});
|
|
471
|
-
|
|
479
|
+
let provenanceText = attachProvenanceToPR(provenance);
|
|
480
|
+
// Include priority score in provenance section when available
|
|
481
|
+
if (options.priorityScore) {
|
|
482
|
+
provenanceText += `\n- **Priority Score**: ${options.priorityScore.composite.toFixed(4)} (confidence: ${options.priorityScore.confidence.toFixed(2)})`;
|
|
483
|
+
}
|
|
484
|
+
provenanceBlock = '\n\n' + provenanceText;
|
|
472
485
|
}
|
|
473
|
-
const prVars = { issueNumber:
|
|
486
|
+
const prVars = { issueNumber: issueId, issueTitle: issue.title };
|
|
474
487
|
const prTitle = interpolatePRTitle(prConfig?.titleTemplate, prVars);
|
|
475
488
|
const closeKeyword = prConfig?.closeKeyword ?? 'Closes';
|
|
476
489
|
const targetBranch = config.pipeline?.spec.branching?.targetBranch ?? 'main';
|
|
@@ -486,7 +499,7 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
486
499
|
if (section === 'changes')
|
|
487
500
|
parts.push('## Changes', '', result.filesChanged.map((f) => `- \`${f}\``).join('\n'));
|
|
488
501
|
if (section === 'closes')
|
|
489
|
-
parts.push('', `${closeKeyword}
|
|
502
|
+
parts.push('', `${closeKeyword} ${formatIssueRef(issueId)}`);
|
|
490
503
|
}
|
|
491
504
|
const footer = options.prFooter ?? DEFAULT_PR_FOOTER;
|
|
492
505
|
parts.push('', '---', footer);
|
|
@@ -504,7 +517,7 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
504
517
|
action: 'create',
|
|
505
518
|
resource: 'pull-request',
|
|
506
519
|
decision: 'allowed',
|
|
507
|
-
details: { prUrl: prResult.url,
|
|
520
|
+
details: { prUrl: prResult.url, issueId },
|
|
508
521
|
});
|
|
509
522
|
return prResult;
|
|
510
523
|
});
|
|
@@ -514,15 +527,15 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
514
527
|
const prCreatedComment = prCreatedTemplate
|
|
515
528
|
? renderTemplate(prCreatedTemplate, {
|
|
516
529
|
prUrl: pr.url,
|
|
517
|
-
issueNumber:
|
|
530
|
+
issueNumber: issueId,
|
|
518
531
|
})
|
|
519
532
|
: { title: NOTIFICATION_TITLES.prCreated, body: `Pull request created: ${pr.url}` };
|
|
520
|
-
await tracker.addComment(
|
|
533
|
+
await tracker.addComment(issueId, `## ${prCreatedComment.title}\n\n${prCreatedComment.body}`);
|
|
521
534
|
// 14b. Record cost from agent result
|
|
522
535
|
if (options.costTracker && result.tokenUsage) {
|
|
523
536
|
const tu = result.tokenUsage;
|
|
524
537
|
options.costTracker.recordCost({
|
|
525
|
-
runId: `run-${Date.now()}-${
|
|
538
|
+
runId: `run-${Date.now()}-${issueId}`,
|
|
526
539
|
agentName: agentRole.metadata.name,
|
|
527
540
|
pipelineType: 'execute',
|
|
528
541
|
model: tu.model,
|
|
@@ -530,7 +543,7 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
530
543
|
outputTokens: tu.outputTokens,
|
|
531
544
|
cacheReadTokens: tu.cacheReadTokens,
|
|
532
545
|
stageName: 'code',
|
|
533
|
-
issueNumber,
|
|
546
|
+
issueNumber: issueNumber ?? undefined,
|
|
534
547
|
});
|
|
535
548
|
}
|
|
536
549
|
// 14c. Record task outcome in autonomy tracker
|
|
@@ -617,18 +630,35 @@ async function executePipelineBody(issueNumber, issue, config, qualityGate, agen
|
|
|
617
630
|
}
|
|
618
631
|
// 17. Record episodic memory (success)
|
|
619
632
|
if (options.memory) {
|
|
633
|
+
const episodicValue = {
|
|
634
|
+
issueId,
|
|
635
|
+
prUrl: pr.url,
|
|
636
|
+
filesChanged: result.filesChanged.length,
|
|
637
|
+
outcome: 'success',
|
|
638
|
+
};
|
|
639
|
+
if (options.priorityScore) {
|
|
640
|
+
episodicValue.priorityComposite = options.priorityScore.composite;
|
|
641
|
+
episodicValue.priorityConfidence = options.priorityScore.confidence;
|
|
642
|
+
}
|
|
620
643
|
options.memory.episodic.append({
|
|
621
644
|
key: 'pipeline-execution',
|
|
622
|
-
value:
|
|
623
|
-
|
|
624
|
-
prUrl: pr.url,
|
|
625
|
-
filesChanged: result.filesChanged.length,
|
|
626
|
-
outcome: 'success',
|
|
627
|
-
},
|
|
628
|
-
metadata: { summary: `Completed issue #${issueNumber}: ${issue.title}` },
|
|
645
|
+
value: episodicValue,
|
|
646
|
+
metadata: { summary: `Completed issue ${formatIssueRef(issueId)}: ${issue.title}` },
|
|
629
647
|
});
|
|
630
648
|
options.memory.working.clear();
|
|
631
649
|
}
|
|
650
|
+
// 17b. Record priority calibration sample for feedback loop
|
|
651
|
+
if (options.stateStore && options.priorityScore) {
|
|
652
|
+
options.stateStore.savePrioritySample({
|
|
653
|
+
issueId,
|
|
654
|
+
priorityComposite: options.priorityScore.composite,
|
|
655
|
+
priorityConfidence: options.priorityScore.confidence,
|
|
656
|
+
priorityDimensions: JSON.stringify(options.priorityScore.dimensions),
|
|
657
|
+
actualComplexity: complexity,
|
|
658
|
+
filesChanged: result.filesChanged.length,
|
|
659
|
+
outcome: 'success',
|
|
660
|
+
});
|
|
661
|
+
}
|
|
632
662
|
// 18. Audit integrity verification (non-blocking)
|
|
633
663
|
if (options.auditFilePath) {
|
|
634
664
|
try {
|
|
@@ -738,4 +768,29 @@ function runPipelineDiagnostics(input) {
|
|
|
738
768
|
// which would empty it before artifact upload can capture the contents.
|
|
739
769
|
}
|
|
740
770
|
}
|
|
771
|
+
// ── Gitignore helper ─────────────────────────────────────────────────
|
|
772
|
+
const RUNTIME_GITIGNORE_ENTRIES = [
|
|
773
|
+
'# AI-SDLC runtime artifacts',
|
|
774
|
+
'.ai-sdlc/state.db',
|
|
775
|
+
'.ai-sdlc/state/',
|
|
776
|
+
'.ai-sdlc/audit.jsonl',
|
|
777
|
+
];
|
|
778
|
+
/**
|
|
779
|
+
* Ensure .gitignore in the working directory covers AI-SDLC runtime artifacts.
|
|
780
|
+
* Without this the agent sees untracked runtime files and appends duplicate
|
|
781
|
+
* gitignore entries on every run.
|
|
782
|
+
*/
|
|
783
|
+
function ensureRuntimeGitignore(workDir) {
|
|
784
|
+
try {
|
|
785
|
+
const gitignorePath = join(workDir, '.gitignore');
|
|
786
|
+
const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, 'utf-8') : '';
|
|
787
|
+
const missing = RUNTIME_GITIGNORE_ENTRIES.filter((entry) => !existing.includes(entry));
|
|
788
|
+
if (missing.length === 0)
|
|
789
|
+
return;
|
|
790
|
+
appendFileSync(gitignorePath, '\n' + missing.join('\n') + '\n', 'utf-8');
|
|
791
|
+
}
|
|
792
|
+
catch {
|
|
793
|
+
// Best-effort — workDir may not exist yet in tests or dry-run scenarios
|
|
794
|
+
}
|
|
795
|
+
}
|
|
741
796
|
//# sourceMappingURL=execute.js.map
|
package/dist/fix-ci.js
CHANGED
|
@@ -8,7 +8,7 @@ import { loadConfig } from './config.js';
|
|
|
8
8
|
import { createLogger } from './logger.js';
|
|
9
9
|
import { createStructuredConsoleLogger } from './structured-logger.js';
|
|
10
10
|
import { ClaudeCodeRunner } from './runners/claude-code.js';
|
|
11
|
-
import { execFileAsync, getGitHubConfig,
|
|
11
|
+
import { execFileAsync, getGitHubConfig, extractIssueId, resolveRepoRoot, createDefaultAuditLog, resolveAutonomyLevel, resolveConstraints, recordMetric, validateAndAuditOutput, authorizeFilesChanged, issueIdToNumber, } from './shared.js';
|
|
12
12
|
import { renderTemplate } from './notifications.js';
|
|
13
13
|
import { parseDuration } from './policy-evaluators.js';
|
|
14
14
|
import { checkKillSwitch, issueAgentCredentials, revokeAgentCredentials, } from './security.js';
|
|
@@ -157,24 +157,25 @@ export async function executeFixCI(prNumber, runId, options = {}) {
|
|
|
157
157
|
cwd: workDir,
|
|
158
158
|
});
|
|
159
159
|
const currentBranch = branchStdout.trim();
|
|
160
|
-
const
|
|
161
|
-
if (
|
|
162
|
-
throw new Error(`Branch "${currentBranch}" does not match ai-sdlc/issue
|
|
160
|
+
const issueId = extractIssueId(currentBranch);
|
|
161
|
+
if (issueId === null) {
|
|
162
|
+
throw new Error(`Branch "${currentBranch}" does not match ai-sdlc/issue-<id> pattern`);
|
|
163
163
|
}
|
|
164
|
+
const issueNumber = issueIdToNumber(issueId);
|
|
164
165
|
// 5. Resolve autonomy level and constraints
|
|
165
166
|
const currentLevel = resolveAutonomyLevel(autonomyPolicy);
|
|
166
167
|
const resolved = resolveConstraints(agentRole.spec.constraints, currentLevel);
|
|
167
168
|
// 6. Fetch issue data (via tracker when available)
|
|
168
|
-
let issueTitle = `Issue
|
|
169
|
+
let issueTitle = `Issue ${issueId}`;
|
|
169
170
|
let issueBody = '';
|
|
170
171
|
if (trackerAvailable) {
|
|
171
|
-
const issueData = await getTracker().getIssue(
|
|
172
|
+
const issueData = await getTracker().getIssue(issueId);
|
|
172
173
|
issueTitle = issueData.title;
|
|
173
174
|
issueBody = issueData.description ?? '';
|
|
174
175
|
}
|
|
175
176
|
// Store issue context in working memory
|
|
176
177
|
if (options.memory) {
|
|
177
|
-
options.memory.working.set('currentIssue', { prNumber,
|
|
178
|
+
options.memory.working.set('currentIssue', { prNumber, issueId, currentBranch });
|
|
178
179
|
}
|
|
179
180
|
// Query episodic memory for previous fix-CI attempts
|
|
180
181
|
if (options.memory) {
|
|
@@ -195,7 +196,7 @@ export async function executeFixCI(prNumber, runId, options = {}) {
|
|
|
195
196
|
try {
|
|
196
197
|
if (options.security) {
|
|
197
198
|
const timeoutMs = codeStage?.timeout ? parseDuration(codeStage.timeout) : undefined;
|
|
198
|
-
sandboxId = await options.security.sandbox.isolate(`issue-${
|
|
199
|
+
sandboxId = await options.security.sandbox.isolate(`issue-${issueId}`, defaultSandboxConstraints(workDir, timeoutMs));
|
|
199
200
|
}
|
|
200
201
|
// Issue JIT credentials before agent execution
|
|
201
202
|
const jitCred = options.security
|
|
@@ -207,7 +208,8 @@ export async function executeFixCI(prNumber, runId, options = {}) {
|
|
|
207
208
|
[ATTRIBUTE_KEYS.RESOURCE_NAME]: `pr#${prNumber}`,
|
|
208
209
|
}, async () => {
|
|
209
210
|
const r = await runner.run({
|
|
210
|
-
|
|
211
|
+
issueId,
|
|
212
|
+
issueNumber: issueNumber ?? undefined,
|
|
211
213
|
issueTitle,
|
|
212
214
|
issueBody,
|
|
213
215
|
workDir,
|
|
@@ -349,7 +351,7 @@ export async function executeFixCI(prNumber, runId, options = {}) {
|
|
|
349
351
|
key: 'fix-ci-execution',
|
|
350
352
|
value: {
|
|
351
353
|
prNumber,
|
|
352
|
-
|
|
354
|
+
issueId,
|
|
353
355
|
filesChanged: result.filesChanged.length,
|
|
354
356
|
outcome: 'success',
|
|
355
357
|
},
|
|
@@ -365,7 +367,7 @@ export async function executeFixCI(prNumber, runId, options = {}) {
|
|
|
365
367
|
key: 'fix-ci-execution',
|
|
366
368
|
value: {
|
|
367
369
|
prNumber,
|
|
368
|
-
|
|
370
|
+
issueId,
|
|
369
371
|
outcome: 'failure',
|
|
370
372
|
error: err instanceof Error ? err.message : String(err),
|
|
371
373
|
},
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ export { validateAgentOutput, type ValidationContext, type ValidationResult, typ
|
|
|
5
5
|
export { createLogger, type Logger } from './logger.js';
|
|
6
6
|
export { validateConfigFiles, type FileValidationResult } from './validate-config.js';
|
|
7
7
|
export { executeFixCI, countRetryAttempts, fetchCILogs, type FixCIOptions } from './fix-ci.js';
|
|
8
|
-
export {
|
|
8
|
+
export { executeTriage, type TriageOptions, type TriageResult } from './triage.js';
|
|
9
|
+
export { getGitHubConfig, resolveRepoRoot, createDefaultAuditLog, resolveAutonomyLevel, resolveConstraints, mergeBlockedPaths, isAutonomousStrategy, recordMetric, validateAndAuditOutput, createPipelineMemory, evaluatePipelineCompliance, authorizeFilesChanged, extractIssueNumber, extractIssueId, issueIdToNumber, formatIssueRef, BRANCH_PATTERN, createAbacPermissionHook, createBlockedPathsHook, createAuditLoggingHook, createPipelineAuthorizationChain, type GitHubEnvConfig, type ValidateAndAuditParams, } from './shared.js';
|
|
9
10
|
export { DEFAULT_MODEL, DEFAULT_GITHUB_ORG, DEFAULT_GITHUB_REPO, DEFAULT_GITHUB_REPOSITORY, DEFAULT_CONFIG_DIR_NAME, DEFAULT_SANDBOX_MEMORY_MB, DEFAULT_SANDBOX_CPU_PERCENT, DEFAULT_SANDBOX_NETWORK_POLICY, DEFAULT_SANDBOX_TIMEOUT_MS, defaultSandboxConstraints, DEFAULT_RUNNER_TIMEOUT_MS, DEFAULT_ALLOWED_TOOLS, DEFAULT_MAX_FILES_PER_CHANGE, DEFAULT_REQUIRE_TESTS, DEFAULT_BLOCKED_PATHS, DEFAULT_MAX_FIX_ATTEMPTS, DEFAULT_MAX_LOG_LINES, DEFAULT_GH_CLI_TIMEOUT_MS, DEFAULT_JIT_TTL_MS, DEFAULT_JIT_SCOPE, DEFAULT_BRANCH_TEMPLATE, DEFAULT_BRANCH_PATTERN, DEFAULT_PR_TITLE_TEMPLATE, DEFAULT_PR_FOOTER, DEFAULT_COMPLEXITY_THRESHOLDS, DEFAULT_MAX_LINES_PER_PR, DEFAULT_ANALYSIS_INCLUDE, DEFAULT_ANALYSIS_EXCLUDE, DEFAULT_GIT_HISTORY_DAYS, DEFAULT_HOTSPOT_THRESHOLD, NOTIFICATION_TITLES, DEFAULT_MODEL_COSTS, DEFAULT_COST_BUDGET_USD, DEFAULT_DASHBOARD_REFRESH_MS, PROGRESSIVE_GATE_PROFILES, DEFAULT_LINT_COMMAND, DEFAULT_FORMAT_COMMAND, DEFAULT_COMMIT_MESSAGE_TEMPLATE, DEFAULT_COMMIT_CO_AUTHOR, DEFAULT_OPENAI_API_URL, DEFAULT_OPENAI_MODEL, DEFAULT_ANTHROPIC_API_URL, DEFAULT_ANTHROPIC_MODEL, DEFAULT_GENERIC_LLM_MODEL, DEFAULT_LLM_TIMEOUT_MS, DEFAULT_LLM_MAX_TOKENS, DEFAULT_LLM_SYSTEM_PROMPT, DEFAULT_DOCKER_IMAGE, DEFAULT_WORKFLOW_FILE, DEFAULT_LABEL_TO_SKILL_MAP, DEFAULT_ANALYSIS_CACHE_TTL_MS, } from './defaults.js';
|
|
10
11
|
export type { ComplexityBand, GateProfile } from './defaults.js';
|
|
11
12
|
export { renderTemplate } from './notifications.js';
|
|
@@ -16,19 +17,20 @@ export { createPipelineMetricStore, createInstrumentedEnforcement, createInstrum
|
|
|
16
17
|
export { createPipelineDiscovery, findMatchingAgent, resolveAgentForIssue, matchAgentBySkill, createStubAgentCardFetcher, createPipelineAgentCardFetcher, } from './discovery.js';
|
|
17
18
|
export { createStructuredConsoleLogger, createStructuredBufferLogger, } from './structured-logger.js';
|
|
18
19
|
export { startWatch, type WatchOptions, type WatchHandle } from './watch.js';
|
|
20
|
+
export { computePriority, rankWorkItems, type PriorityScore, type PriorityInput, type PriorityConfig, } from './priority.js';
|
|
19
21
|
export { createPipelineOrchestration, executePipelineOrchestration, validatePipelineHandoffs, sequential, parallel, hybrid, hierarchical, swarm, validateHandoff, simpleSchemaValidate, } from './orchestration.js';
|
|
20
22
|
export { createPipelineRegoEvaluator, createPipelineCELEvaluator, createPipelineABACHook, createPipelineExpressionEvaluator, createPipelineLLMEvaluator, evaluatePipelineGate, scorePipelineComplexity, evaluatePipelineComplexityRouting, } from './policy-evaluators.js';
|
|
21
|
-
export { createPipelineAdapterRegistry, createPipelineWebhookBridge, resolveAdapterFromGit, resolveInfrastructure, scanPipelineAdapters, } from './adapters.js';
|
|
23
|
+
export { createPipelineAdapterRegistry, createPipelineWebhookBridge, resolveAdapterFromGit, resolveInfrastructure, resolveIssueTrackerFromConfig, scanPipelineAdapters, } from './adapters.js';
|
|
22
24
|
export { createPipelineReconciler, createGateReconciler, createAutonomyReconciler, hasResourceChanged, fingerprintResource, } from './reconcilers.js';
|
|
23
25
|
export { createFileAuditLog, verifyAuditIntegrity, loadAuditEntries, rotateAuditLog, computeAuditHash, } from './audit-extended.js';
|
|
24
26
|
export { checkFrameworkCompliance, getControlCatalog, getFrameworkMappings, listSupportedFrameworks, } from './compliance-extended.js';
|
|
25
27
|
export { createSilentLogger, withPipelineSpanSync, getPipelineTracer, validateResourceSchema, } from './telemetry-extended.js';
|
|
26
|
-
export { ClaudeCodeRunner, ClaudeCodeRunner as GitHubActionsRunner, GenericLLMRunner, CopilotRunner, CursorRunner, CodexRunner, RunnerRegistry, createRunnerRegistry, type AgentRunner, type AgentContext, type AgentResult, type GenericLLMConfig, type RegisteredRunner, } from './runners/index.js';
|
|
28
|
+
export { ClaudeCodeRunner, ClaudeCodeRunner as GitHubActionsRunner, GenericLLMRunner, CopilotRunner, CursorRunner, CodexRunner, RunnerRegistry, createRunnerRegistry, SecurityTriageRunner, type AgentRunner, type AgentContext, type AgentResult, type GenericLLMConfig, type RegisteredRunner, type SecurityTriageConfig, type TriageVerdict, } from './runners/index.js';
|
|
27
29
|
export type { TokenUsage } from './runners/index.js';
|
|
28
30
|
export { SlackMessenger, TeamsMessenger, NotificationRouter } from './notifications/index.js';
|
|
29
31
|
export type { SlackConfig, TeamsConfig, PipelineEvent, PipelineEventType, NotificationRoute, NotificationTemplate, } from './notifications/index.js';
|
|
30
32
|
export { StateStore } from './state/index.js';
|
|
31
|
-
export type { HotspotRecord, RoutingDecision, CostLedgerEntry, GateThresholdOverride, AutonomyEvent, AutonomyEventType, HandoffEvent, DeploymentRecord, DeploymentRecordState, RolloutStepRecord, AuditEntryRecord, } from './state/index.js';
|
|
33
|
+
export type { HotspotRecord, RoutingDecision, CostLedgerEntry, GateThresholdOverride, AutonomyEvent, AutonomyEventType, HandoffEvent, DeploymentRecord, DeploymentRecordState, RolloutStepRecord, AuditEntryRecord, PriorityCalibrationSample, } from './state/index.js';
|
|
32
34
|
export { createKubernetesTarget, createVercelTarget, createFlyioTarget, createHttpMetricsCollector, createStubMetricsCollector, RolloutController, } from './deploy/index.js';
|
|
33
35
|
export type { DeploymentTargetConfig, HealthCheckConfig, DeploymentState, DeploymentResult, DeploymentTarget, ExecFn, FetchFn, KubernetesConfig, VercelConfig, FlyioConfig, CanaryStep, CanaryConfig, BlueGreenConfig, RollingConfig, RolloutStrategy, RolloutPhase, RolloutStatus, RolloutMetrics, MetricsSource, RolloutControllerConfig, HttpMetricsConfig, } from './deploy/index.js';
|
|
34
36
|
export { getComplexityBand, getGateProfile, adjustEnforcement, adjustGateForComplexity, adjustGatesForComplexity, computeGateAdjustments, } from './progressive-gates.js';
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,9 @@ export { validateAgentOutput, } from './validate-agent-output.js';
|
|
|
6
6
|
export { createLogger } from './logger.js';
|
|
7
7
|
export { validateConfigFiles } from './validate-config.js';
|
|
8
8
|
export { executeFixCI, countRetryAttempts, fetchCILogs } from './fix-ci.js';
|
|
9
|
+
export { executeTriage } from './triage.js';
|
|
9
10
|
// Shared utilities
|
|
10
|
-
export { getGitHubConfig, resolveRepoRoot, createDefaultAuditLog, resolveAutonomyLevel, resolveConstraints, mergeBlockedPaths, isAutonomousStrategy, recordMetric, validateAndAuditOutput, createPipelineMemory, evaluatePipelineCompliance, authorizeFilesChanged, extractIssueNumber, BRANCH_PATTERN, createAbacPermissionHook, createBlockedPathsHook, createAuditLoggingHook, createPipelineAuthorizationChain, } from './shared.js';
|
|
11
|
+
export { getGitHubConfig, resolveRepoRoot, createDefaultAuditLog, resolveAutonomyLevel, resolveConstraints, mergeBlockedPaths, isAutonomousStrategy, recordMetric, validateAndAuditOutput, createPipelineMemory, evaluatePipelineCompliance, authorizeFilesChanged, extractIssueNumber, extractIssueId, issueIdToNumber, formatIssueRef, BRANCH_PATTERN, createAbacPermissionHook, createBlockedPathsHook, createAuditLoggingHook, createPipelineAuthorizationChain, } from './shared.js';
|
|
11
12
|
// Defaults
|
|
12
13
|
export { DEFAULT_MODEL, DEFAULT_GITHUB_ORG, DEFAULT_GITHUB_REPO, DEFAULT_GITHUB_REPOSITORY, DEFAULT_CONFIG_DIR_NAME, DEFAULT_SANDBOX_MEMORY_MB, DEFAULT_SANDBOX_CPU_PERCENT, DEFAULT_SANDBOX_NETWORK_POLICY, DEFAULT_SANDBOX_TIMEOUT_MS, defaultSandboxConstraints, DEFAULT_RUNNER_TIMEOUT_MS, DEFAULT_ALLOWED_TOOLS, DEFAULT_MAX_FILES_PER_CHANGE, DEFAULT_REQUIRE_TESTS, DEFAULT_BLOCKED_PATHS, DEFAULT_MAX_FIX_ATTEMPTS, DEFAULT_MAX_LOG_LINES, DEFAULT_GH_CLI_TIMEOUT_MS, DEFAULT_JIT_TTL_MS, DEFAULT_JIT_SCOPE, DEFAULT_BRANCH_TEMPLATE, DEFAULT_BRANCH_PATTERN, DEFAULT_PR_TITLE_TEMPLATE, DEFAULT_PR_FOOTER, DEFAULT_COMPLEXITY_THRESHOLDS, DEFAULT_MAX_LINES_PER_PR, DEFAULT_ANALYSIS_INCLUDE, DEFAULT_ANALYSIS_EXCLUDE, DEFAULT_GIT_HISTORY_DAYS, DEFAULT_HOTSPOT_THRESHOLD, NOTIFICATION_TITLES, DEFAULT_MODEL_COSTS, DEFAULT_COST_BUDGET_USD, DEFAULT_DASHBOARD_REFRESH_MS, PROGRESSIVE_GATE_PROFILES, DEFAULT_LINT_COMMAND, DEFAULT_FORMAT_COMMAND, DEFAULT_COMMIT_MESSAGE_TEMPLATE, DEFAULT_COMMIT_CO_AUTHOR, DEFAULT_OPENAI_API_URL, DEFAULT_OPENAI_MODEL, DEFAULT_ANTHROPIC_API_URL, DEFAULT_ANTHROPIC_MODEL, DEFAULT_GENERIC_LLM_MODEL, DEFAULT_LLM_TIMEOUT_MS, DEFAULT_LLM_MAX_TOKENS, DEFAULT_LLM_SYSTEM_PROMPT, DEFAULT_DOCKER_IMAGE, DEFAULT_WORKFLOW_FILE, DEFAULT_LABEL_TO_SKILL_MAP, DEFAULT_ANALYSIS_CACHE_TTL_MS, } from './defaults.js';
|
|
13
14
|
// Notifications
|
|
@@ -26,12 +27,14 @@ export { createPipelineDiscovery, findMatchingAgent, resolveAgentForIssue, match
|
|
|
26
27
|
export { createStructuredConsoleLogger, createStructuredBufferLogger, } from './structured-logger.js';
|
|
27
28
|
// Watch mode
|
|
28
29
|
export { startWatch } from './watch.js';
|
|
30
|
+
// Priority scoring (PPA)
|
|
31
|
+
export { computePriority, rankWorkItems, } from './priority.js';
|
|
29
32
|
// Agent orchestration
|
|
30
33
|
export { createPipelineOrchestration, executePipelineOrchestration, validatePipelineHandoffs, sequential, parallel, hybrid, hierarchical, swarm, validateHandoff, simpleSchemaValidate, } from './orchestration.js';
|
|
31
34
|
// Policy evaluators
|
|
32
35
|
export { createPipelineRegoEvaluator, createPipelineCELEvaluator, createPipelineABACHook, createPipelineExpressionEvaluator, createPipelineLLMEvaluator, evaluatePipelineGate, scorePipelineComplexity, evaluatePipelineComplexityRouting, } from './policy-evaluators.js';
|
|
33
36
|
// Adapter ecosystem
|
|
34
|
-
export { createPipelineAdapterRegistry, createPipelineWebhookBridge, resolveAdapterFromGit, resolveInfrastructure, scanPipelineAdapters, } from './adapters.js';
|
|
37
|
+
export { createPipelineAdapterRegistry, createPipelineWebhookBridge, resolveAdapterFromGit, resolveInfrastructure, resolveIssueTrackerFromConfig, scanPipelineAdapters, } from './adapters.js';
|
|
35
38
|
// Reconcilers (generalized names)
|
|
36
39
|
export { createPipelineReconciler, createGateReconciler, createAutonomyReconciler, hasResourceChanged, fingerprintResource, } from './reconcilers.js';
|
|
37
40
|
// Extended audit
|
|
@@ -41,7 +44,7 @@ export { checkFrameworkCompliance, getControlCatalog, getFrameworkMappings, list
|
|
|
41
44
|
// Extended telemetry
|
|
42
45
|
export { createSilentLogger, withPipelineSpanSync, getPipelineTracer, validateResourceSchema, } from './telemetry-extended.js';
|
|
43
46
|
// Runners
|
|
44
|
-
export { ClaudeCodeRunner, ClaudeCodeRunner as GitHubActionsRunner, GenericLLMRunner, CopilotRunner, CursorRunner, CodexRunner, RunnerRegistry, createRunnerRegistry, } from './runners/index.js';
|
|
47
|
+
export { ClaudeCodeRunner, ClaudeCodeRunner as GitHubActionsRunner, GenericLLMRunner, CopilotRunner, CursorRunner, CodexRunner, RunnerRegistry, createRunnerRegistry, SecurityTriageRunner, } from './runners/index.js';
|
|
45
48
|
// Notifications
|
|
46
49
|
export { SlackMessenger, TeamsMessenger, NotificationRouter } from './notifications/index.js';
|
|
47
50
|
// State store
|
package/dist/orchestrator.d.ts
CHANGED
|
@@ -74,7 +74,7 @@ export declare class Orchestrator {
|
|
|
74
74
|
/**
|
|
75
75
|
* Run the full pipeline for a single issue.
|
|
76
76
|
*/
|
|
77
|
-
run(
|
|
77
|
+
run(issueId: string, overrides?: Partial<ExecuteOptions>): Promise<PipelineResult>;
|
|
78
78
|
/**
|
|
79
79
|
* Start watch mode — continuous reconciliation loop.
|
|
80
80
|
*/
|
package/dist/orchestrator.js
CHANGED
|
@@ -8,6 +8,7 @@ import { executeFixCI } from './fix-ci.js';
|
|
|
8
8
|
import { loadConfig } from './config.js';
|
|
9
9
|
import { StateStore } from './state/index.js';
|
|
10
10
|
import { createLogger } from './logger.js';
|
|
11
|
+
import { issueIdToNumber } from './shared.js';
|
|
11
12
|
import { analyzeCodebase } from './analysis/analyzer.js';
|
|
12
13
|
import { buildCodebaseContext } from './analysis/context-builder.js';
|
|
13
14
|
import { DEFAULT_ANALYSIS_CACHE_TTL_MS } from './defaults.js';
|
|
@@ -48,14 +49,16 @@ export class Orchestrator {
|
|
|
48
49
|
/**
|
|
49
50
|
* Run the full pipeline for a single issue.
|
|
50
51
|
*/
|
|
51
|
-
async run(
|
|
52
|
-
const
|
|
52
|
+
async run(issueId, overrides) {
|
|
53
|
+
const issueNumber = issueIdToNumber(issueId);
|
|
54
|
+
const runId = `run-${Date.now()}-${issueId}`;
|
|
53
55
|
const startedAt = new Date().toISOString();
|
|
54
56
|
// Record pipeline start in state store
|
|
55
57
|
if (this._state) {
|
|
56
58
|
this._state.savePipelineRun({
|
|
57
59
|
runId,
|
|
58
|
-
|
|
60
|
+
issueId,
|
|
61
|
+
issueNumber: issueNumber ?? undefined,
|
|
59
62
|
pipelineType: 'execute',
|
|
60
63
|
status: 'running',
|
|
61
64
|
currentStage: 'init',
|
|
@@ -84,11 +87,16 @@ export class Orchestrator {
|
|
|
84
87
|
}
|
|
85
88
|
// Notify plugins before run
|
|
86
89
|
for (const plugin of this.plugins) {
|
|
87
|
-
await plugin.beforeRun?.({
|
|
90
|
+
await plugin.beforeRun?.({
|
|
91
|
+
runId,
|
|
92
|
+
issueId,
|
|
93
|
+
issueNumber: issueNumber ?? undefined,
|
|
94
|
+
startedAt,
|
|
95
|
+
});
|
|
88
96
|
}
|
|
89
97
|
const runStart = Date.now();
|
|
90
98
|
try {
|
|
91
|
-
const result = await executePipeline(
|
|
99
|
+
const result = await executePipeline(issueId, {
|
|
92
100
|
configDir: this.config.configDir,
|
|
93
101
|
workDir: this.config.workDir,
|
|
94
102
|
runner: this.config.runner,
|
|
@@ -109,7 +117,8 @@ export class Orchestrator {
|
|
|
109
117
|
}),
|
|
110
118
|
});
|
|
111
119
|
this._state.saveEpisodicRecord({
|
|
112
|
-
|
|
120
|
+
issueId,
|
|
121
|
+
issueNumber: issueNumber ?? undefined,
|
|
113
122
|
pipelineType: 'execute',
|
|
114
123
|
outcome: 'success',
|
|
115
124
|
filesChanged: result.filesChanged.length,
|
|
@@ -118,7 +127,13 @@ export class Orchestrator {
|
|
|
118
127
|
// Notify plugins after successful run
|
|
119
128
|
const durationMs = Date.now() - runStart;
|
|
120
129
|
for (const plugin of this.plugins) {
|
|
121
|
-
await plugin.afterRun?.({
|
|
130
|
+
await plugin.afterRun?.({
|
|
131
|
+
runId,
|
|
132
|
+
issueId,
|
|
133
|
+
issueNumber: issueNumber ?? undefined,
|
|
134
|
+
result,
|
|
135
|
+
durationMs,
|
|
136
|
+
});
|
|
122
137
|
}
|
|
123
138
|
return result;
|
|
124
139
|
}
|
|
@@ -131,7 +146,8 @@ export class Orchestrator {
|
|
|
131
146
|
}),
|
|
132
147
|
});
|
|
133
148
|
this._state.saveEpisodicRecord({
|
|
134
|
-
|
|
149
|
+
issueId,
|
|
150
|
+
issueNumber: issueNumber ?? undefined,
|
|
135
151
|
pipelineType: 'execute',
|
|
136
152
|
outcome: 'failure',
|
|
137
153
|
errorMessage: err instanceof Error ? err.message : String(err),
|
|
@@ -141,7 +157,13 @@ export class Orchestrator {
|
|
|
141
157
|
const errorDurationMs = Date.now() - runStart;
|
|
142
158
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
143
159
|
for (const plugin of this.plugins) {
|
|
144
|
-
await plugin.onError?.({
|
|
160
|
+
await plugin.onError?.({
|
|
161
|
+
runId,
|
|
162
|
+
issueId,
|
|
163
|
+
issueNumber: issueNumber ?? undefined,
|
|
164
|
+
error,
|
|
165
|
+
durationMs: errorDurationMs,
|
|
166
|
+
});
|
|
145
167
|
}
|
|
146
168
|
throw err;
|
|
147
169
|
}
|