@ai-sdlc/orchestrator 0.6.0 → 0.10.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/__test-helpers/git-env.d.ts +40 -0
- package/dist/__test-helpers/git-env.js +73 -0
- package/dist/admission-composite.d.ts +89 -0
- package/dist/admission-composite.js +241 -0
- package/dist/admission-enrichment.d.ts +142 -0
- package/dist/admission-enrichment.js +341 -0
- package/dist/admission-hc.d.ts +81 -0
- package/dist/admission-hc.js +94 -0
- package/dist/admission-score.d.ts +109 -5
- package/dist/admission-score.js +90 -11
- package/dist/analysis/analyzer.js +3 -2
- package/dist/analysis/convention-detector.d.ts +85 -2
- package/dist/analysis/convention-detector.js +375 -70
- package/dist/analysis/diff-analyzer.d.ts +33 -0
- package/dist/analysis/diff-analyzer.js +122 -0
- package/dist/analysis/hotspot-analyzer.js +3 -1
- package/dist/analysis/index.d.ts +2 -1
- package/dist/analysis/index.js +2 -1
- package/dist/artifacts/index.d.ts +65 -0
- package/dist/artifacts/index.js +142 -0
- package/dist/backlog-adapter.d.ts +121 -0
- package/dist/backlog-adapter.js +438 -0
- package/dist/calibration.d.ts +43 -0
- package/dist/calibration.js +76 -0
- package/dist/cli/commands/agents.d.ts +24 -0
- package/dist/cli/commands/agents.js +66 -1
- package/dist/cli/commands/git-remote.d.ts +74 -0
- package/dist/cli/commands/git-remote.js +170 -0
- package/dist/cli/commands/health.d.ts +4 -0
- package/dist/cli/commands/health.js +13 -1
- package/dist/cli/commands/init-features.d.ts +208 -0
- package/dist/cli/commands/init-features.js +473 -0
- package/dist/cli/commands/init-templates.d.ts +104 -0
- package/dist/cli/commands/init-templates.js +399 -0
- package/dist/cli/commands/init.d.ts +48 -0
- package/dist/cli/commands/init.js +322 -23
- package/dist/cli/commands/mcp-setup.d.ts +31 -0
- package/dist/cli/commands/mcp-setup.js +78 -8
- package/dist/cli/formatters/table.js +15 -2
- package/dist/cli/index.d.ts +14 -1
- package/dist/cli/index.js +81 -20
- package/dist/cli/versions.d.ts +57 -0
- package/dist/cli/versions.js +128 -0
- package/dist/code-area-classifier.d.ts +21 -0
- package/dist/code-area-classifier.js +48 -0
- package/dist/config.d.ts +33 -1
- package/dist/config.js +78 -8
- package/dist/database/adapters/external.d.ts +24 -0
- package/dist/database/adapters/external.js +80 -0
- package/dist/database/adapters/neon.d.ts +41 -0
- package/dist/database/adapters/neon.js +98 -0
- package/dist/database/adapters/pg-snapshot-restore.d.ts +28 -0
- package/dist/database/adapters/pg-snapshot-restore.js +68 -0
- package/dist/database/adapters/sqlite-copy.d.ts +32 -0
- package/dist/database/adapters/sqlite-copy.js +145 -0
- package/dist/database/connection-injection.d.ts +35 -0
- package/dist/database/connection-injection.js +93 -0
- package/dist/database/index.d.ts +12 -0
- package/dist/database/index.js +23 -0
- package/dist/database/registry.d.ts +13 -0
- package/dist/database/registry.js +27 -0
- package/dist/database/topology.d.ts +52 -0
- package/dist/database/topology.js +44 -0
- package/dist/database/types.d.ts +89 -0
- package/dist/database/types.js +26 -0
- package/dist/design-authority.d.ts +53 -0
- package/dist/design-authority.js +84 -0
- package/dist/design-lookahead.d.ts +64 -0
- package/dist/design-lookahead.js +86 -0
- package/dist/design-quality-trend.d.ts +87 -0
- package/dist/design-quality-trend.js +190 -0
- package/dist/design-system-context.d.ts +46 -0
- package/dist/design-system-context.js +80 -0
- package/dist/design-system-correction-loop.d.ts +64 -0
- package/dist/design-system-correction-loop.js +128 -0
- package/dist/design-system-metrics.d.ts +61 -0
- package/dist/design-system-metrics.js +104 -0
- package/dist/design-system-stewardship.d.ts +22 -0
- package/dist/design-system-stewardship.js +85 -0
- package/dist/design-system-validation.d.ts +37 -0
- package/dist/design-system-validation.js +88 -0
- package/dist/dispatch/index.d.ts +4 -0
- package/dist/dispatch/index.js +4 -0
- package/dist/dispatch/merge-gate.d.ts +46 -0
- package/dist/dispatch/merge-gate.js +90 -0
- package/dist/dispatch/requeue.d.ts +57 -0
- package/dist/dispatch/requeue.js +131 -0
- package/dist/dispatch/worker-pool.d.ts +62 -0
- package/dist/dispatch/worker-pool.js +60 -0
- package/dist/execute.d.ts +40 -0
- package/dist/execute.js +188 -15
- package/dist/fix-ci.js +8 -1
- package/dist/fix-review.js +8 -1
- package/dist/harness/adapters/claude-code.d.ts +29 -0
- package/dist/harness/adapters/claude-code.js +191 -0
- package/dist/harness/adapters/codex.d.ts +25 -0
- package/dist/harness/adapters/codex.js +61 -0
- package/dist/harness/independence.d.ts +51 -0
- package/dist/harness/independence.js +67 -0
- package/dist/harness/index.d.ts +14 -0
- package/dist/harness/index.js +20 -0
- package/dist/harness/registry.d.ts +17 -0
- package/dist/harness/registry.js +31 -0
- package/dist/harness/types.d.ts +123 -0
- package/dist/harness/types.js +8 -0
- package/dist/harness/version-probe.d.ts +14 -0
- package/dist/harness/version-probe.js +123 -0
- package/dist/index.d.ts +30 -4
- package/dist/index.js +35 -2
- package/dist/models/classifier.d.ts +78 -0
- package/dist/models/classifier.js +277 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.js +3 -0
- package/dist/models/registry.d.ts +97 -0
- package/dist/models/registry.js +173 -0
- package/dist/pillar-breakdown.d.ts +85 -0
- package/dist/pillar-breakdown.js +162 -0
- package/dist/priority.d.ts +5 -0
- package/dist/priority.js +18 -5
- package/dist/review-meta.d.ts +65 -0
- package/dist/review-meta.js +149 -0
- package/dist/review.d.ts +4 -0
- package/dist/review.js +12 -2
- package/dist/runners/claude-code-sdk.d.ts +31 -0
- package/dist/runners/claude-code-sdk.js +238 -0
- package/dist/runners/claude-code.d.ts +3 -0
- package/dist/runners/claude-code.js +30 -66
- package/dist/runners/codex.js +4 -1
- package/dist/runners/copilot.js +4 -1
- package/dist/runners/cursor.js +4 -1
- package/dist/runners/git-utils.d.ts +81 -0
- package/dist/runners/git-utils.js +201 -0
- package/dist/runners/index.d.ts +3 -0
- package/dist/runners/index.js +3 -0
- package/dist/runners/review-agent.d.ts +20 -0
- package/dist/runners/review-agent.js +171 -41
- package/dist/runners/runner-registry.js +10 -0
- package/dist/runners/sdk-review-runner.d.ts +65 -0
- package/dist/runners/sdk-review-runner.js +185 -0
- package/dist/runners/security-triage.d.ts +20 -4
- package/dist/runners/security-triage.js +39 -15
- package/dist/runners/types.d.ts +6 -0
- package/dist/runtime/attestations.d.ts +766 -0
- package/dist/runtime/attestations.js +1195 -0
- package/dist/runtime/git-env.d.ts +53 -0
- package/dist/runtime/git-env.js +60 -0
- package/dist/runtime/index.d.ts +7 -0
- package/dist/runtime/index.js +7 -0
- package/dist/runtime/parallelism-flag.d.ts +28 -0
- package/dist/runtime/parallelism-flag.js +39 -0
- package/dist/runtime/port-allocator.d.ts +32 -0
- package/dist/runtime/port-allocator.js +96 -0
- package/dist/runtime/worktree-pool.d.ts +86 -0
- package/dist/runtime/worktree-pool.js +204 -0
- package/dist/runtime/worktree.d.ts +25 -0
- package/dist/runtime/worktree.js +111 -0
- package/dist/sa-scoring/auto-calibrate.d.ts +69 -0
- package/dist/sa-scoring/auto-calibrate.js +107 -0
- package/dist/sa-scoring/c1-sa2-computable.d.ts +42 -0
- package/dist/sa-scoring/c1-sa2-computable.js +59 -0
- package/dist/sa-scoring/composite.d.ts +107 -0
- package/dist/sa-scoring/composite.js +139 -0
- package/dist/sa-scoring/depparse-client.d.ts +79 -0
- package/dist/sa-scoring/depparse-client.js +187 -0
- package/dist/sa-scoring/did-compiler.d.ts +122 -0
- package/dist/sa-scoring/did-compiler.js +286 -0
- package/dist/sa-scoring/drift-monitor.d.ts +84 -0
- package/dist/sa-scoring/drift-monitor.js +186 -0
- package/dist/sa-scoring/exemplar-bank.d.ts +78 -0
- package/dist/sa-scoring/exemplar-bank.js +154 -0
- package/dist/sa-scoring/feedback-store.d.ts +100 -0
- package/dist/sa-scoring/feedback-store.js +156 -0
- package/dist/sa-scoring/index.d.ts +71 -0
- package/dist/sa-scoring/index.js +158 -0
- package/dist/sa-scoring/layer1-deterministic.d.ts +115 -0
- package/dist/sa-scoring/layer1-deterministic.js +298 -0
- package/dist/sa-scoring/layer2-structural.d.ts +71 -0
- package/dist/sa-scoring/layer2-structural.js +151 -0
- package/dist/sa-scoring/layer3-llm.d.ts +86 -0
- package/dist/sa-scoring/layer3-llm.js +282 -0
- package/dist/sa-scoring/rescore-orchestrator.d.ts +52 -0
- package/dist/sa-scoring/rescore-orchestrator.js +47 -0
- package/dist/scheduling/burn-down.d.ts +27 -0
- package/dist/scheduling/burn-down.js +43 -0
- package/dist/scheduling/calibration.d.ts +42 -0
- package/dist/scheduling/calibration.js +150 -0
- package/dist/scheduling/index.d.ts +8 -0
- package/dist/scheduling/index.js +8 -0
- package/dist/scheduling/ledger.d.ts +59 -0
- package/dist/scheduling/ledger.js +216 -0
- package/dist/scheduling/off-peak.d.ts +27 -0
- package/dist/scheduling/off-peak.js +112 -0
- package/dist/scheduling/schedule-decision.d.ts +39 -0
- package/dist/scheduling/schedule-decision.js +89 -0
- package/dist/scheduling/tier-analysis.d.ts +47 -0
- package/dist/scheduling/tier-analysis.js +81 -0
- package/dist/scheduling/types.d.ts +140 -0
- package/dist/scheduling/types.js +11 -0
- package/dist/shared.d.ts +13 -0
- package/dist/shared.js +32 -0
- package/dist/state/schema.d.ts +5 -1
- package/dist/state/schema.js +223 -1
- package/dist/state/store.d.ts +55 -1
- package/dist/state/store.js +342 -7
- package/dist/state/types.d.ts +139 -0
- package/dist/types.d.ts +1 -1
- package/dist/validate-agent-output.js +4 -1
- package/dist/watch.js +6 -0
- package/package.json +3 -2
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded-concurrency worker pool per RFC-0010 §9. Accepts a stream of work items in
|
|
3
|
+
* PPA-priority order, dispatches up to `maxConcurrent` simultaneously, and surfaces
|
|
4
|
+
* structured admission/dispatch events.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Process all items with bounded concurrency. Items are dispatched in PPA score order
|
|
8
|
+
* (descending). Items that the admission gate rejects are returned in `deferred` for
|
|
9
|
+
* the caller to requeue or escalate. Failed executions are returned in `failed`; the
|
|
10
|
+
* pool does NOT auto-retry — that's the caller's responsibility (see RFC §9.4).
|
|
11
|
+
*/
|
|
12
|
+
export async function runWorkerPool(items, deps) {
|
|
13
|
+
if (deps.maxConcurrent < 1) {
|
|
14
|
+
throw new Error(`maxConcurrent must be >= 1 (got ${deps.maxConcurrent})`);
|
|
15
|
+
}
|
|
16
|
+
const sorted = [...items].sort((a, b) => b.ppaScore - a.ppaScore);
|
|
17
|
+
const result = { succeeded: [], failed: [], deferred: [] };
|
|
18
|
+
const onEvent = deps.onEvent ?? (() => { });
|
|
19
|
+
for (const item of sorted) {
|
|
20
|
+
onEvent({ type: 'queued', item, queueSize: sorted.length });
|
|
21
|
+
}
|
|
22
|
+
let inFlight = 0;
|
|
23
|
+
const queue = [...sorted];
|
|
24
|
+
// Spawn N workers that pull from the shared queue until empty.
|
|
25
|
+
const worker = async () => {
|
|
26
|
+
for (;;) {
|
|
27
|
+
const item = queue.shift();
|
|
28
|
+
if (!item)
|
|
29
|
+
return;
|
|
30
|
+
inFlight++;
|
|
31
|
+
try {
|
|
32
|
+
if (deps.admit) {
|
|
33
|
+
const admitted = await deps.admit(item);
|
|
34
|
+
if (!admitted) {
|
|
35
|
+
onEvent({ type: 'admission-deferred', item });
|
|
36
|
+
result.deferred.push(item);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const start = Date.now();
|
|
41
|
+
onEvent({ type: 'started', item, inFlight });
|
|
42
|
+
const r = await deps.execute(item);
|
|
43
|
+
onEvent({ type: 'completed', item, durationMs: Date.now() - start });
|
|
44
|
+
result.succeeded.push({ item, result: r });
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
48
|
+
onEvent({ type: 'failed', item, error });
|
|
49
|
+
result.failed.push({ item, error });
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
inFlight--;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const workers = Array.from({ length: Math.min(deps.maxConcurrent, sorted.length) }, () => worker());
|
|
57
|
+
await Promise.all(workers);
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=worker-pool.js.map
|
package/dist/execute.d.ts
CHANGED
|
@@ -76,9 +76,49 @@ export interface ExecuteOptions {
|
|
|
76
76
|
stateStore?: StateStore;
|
|
77
77
|
/** Priority score from PPA scoring (set by watch loop or caller). */
|
|
78
78
|
priorityScore?: PriorityScore;
|
|
79
|
+
/**
|
|
80
|
+
* Override the Pipeline resource selected for this execution. When set, takes
|
|
81
|
+
* precedence over the on-disk `config.pipeline` loaded from `.ai-sdlc/`. The
|
|
82
|
+
* watch loop uses this to pass the dispatcher-selected pipeline (e.g., the
|
|
83
|
+
* backlog pipeline for AISDLC-* issues) instead of letting executePipeline
|
|
84
|
+
* fall back to the canonical pipeline.yaml.
|
|
85
|
+
*/
|
|
86
|
+
pipelineOverride?: import('@ai-sdlc/reference').Pipeline;
|
|
79
87
|
}
|
|
80
88
|
/**
|
|
81
89
|
* Execute the full AI-SDLC pipeline for a given issue ID.
|
|
82
90
|
*/
|
|
83
91
|
export declare function executePipeline(issueId: string, options?: ExecuteOptions): Promise<PipelineResult>;
|
|
92
|
+
/**
|
|
93
|
+
* Capture the current branch name (or commit SHA in detached-HEAD state) so the
|
|
94
|
+
* pipeline can restore the user's worktree after the run. Returns null on git
|
|
95
|
+
* failure — callers treat null as "don't try to restore".
|
|
96
|
+
*
|
|
97
|
+
* @internal — exported for unit tests.
|
|
98
|
+
*/
|
|
99
|
+
export declare function captureCurrentBranch(workDir: string): Promise<string | null>;
|
|
100
|
+
/**
|
|
101
|
+
* Restore the user's original HEAD if the pipeline switched branches AND the
|
|
102
|
+
* working tree is clean. If the working tree has uncommitted changes (from a
|
|
103
|
+
* partial pipeline run), log a warning and leave HEAD where it is — better to
|
|
104
|
+
* preserve the pipeline's state than to clobber whatever the user has.
|
|
105
|
+
*
|
|
106
|
+
* @internal — exported for unit tests.
|
|
107
|
+
*/
|
|
108
|
+
export declare function restoreOriginalBranch(workDir: string, originalHead: string | null, log: {
|
|
109
|
+
info: (msg: string) => void;
|
|
110
|
+
} | undefined): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Push a branch to origin, rebasing onto the remote tip if it has advanced.
|
|
113
|
+
* Pre-AISDLC-68-rerun the pipeline did a plain `git push` and rejected with
|
|
114
|
+
* non-fast-forward when the remote branch had drifted (e.g. a previous run's
|
|
115
|
+
* commits or a manual edit). The fix: try push; on non-fast-forward, fetch +
|
|
116
|
+
* rebase HEAD onto origin/<branch>, retry once. Rebase conflicts surface as
|
|
117
|
+
* the original error so the operator can resolve manually.
|
|
118
|
+
*
|
|
119
|
+
* @internal — exported for unit tests.
|
|
120
|
+
*/
|
|
121
|
+
export declare function pushBranchWithRebase(workDir: string, branchName: string, log: {
|
|
122
|
+
info: (msg: string) => void;
|
|
123
|
+
} | undefined): Promise<void>;
|
|
84
124
|
//# sourceMappingURL=execute.d.ts.map
|
package/dist/execute.js
CHANGED
|
@@ -12,7 +12,8 @@ import { validateAgentOutput } from './validate-agent-output.js';
|
|
|
12
12
|
import { createLogger } from './logger.js';
|
|
13
13
|
import { createStructuredConsoleLogger, createStructuredBufferLogger, } from './structured-logger.js';
|
|
14
14
|
import { ClaudeCodeRunner } from './runners/claude-code.js';
|
|
15
|
-
import { execFileAsync, getGitHubConfig, resolveRepoRoot, createDefaultAuditLog, resolveAutonomyLevel, resolveConstraints, isAutonomousStrategy, recordMetric, evaluatePipelineCompliance, authorizeFilesChanged, interpolateBranchPattern, interpolatePRTitle, issueIdToNumber, formatIssueRef, } from './shared.js';
|
|
15
|
+
import { execFileAsync, getGitHubConfig, resolveRepoRoot, createDefaultAuditLog, resolveAutonomyLevel, resolveConstraints, isAutonomousStrategy, recordMetric, evaluatePipelineCompliance, authorizeFilesChanged, interpolateBranchPattern, interpolatePRTitle, issueIdToNumber, formatIssueRef, buildIssueTemplateVars, } from './shared.js';
|
|
16
|
+
import { cleanGitEnv } from './runtime/git-env.js';
|
|
16
17
|
import { checkKillSwitch, issueAgentCredentials, revokeAgentCredentials, classifyAndSubmitApproval, createPipelineSecurity, } from './security.js';
|
|
17
18
|
import { createPipelineOrchestration, executePipelineOrchestration, validatePipelineHandoffs, } from './orchestration.js';
|
|
18
19
|
import { createPipelineProvenance, attachProvenanceToPR, validatePipelineProvenance, } from './provenance.js';
|
|
@@ -23,7 +24,7 @@ import { verifyAuditIntegrity, createFileAuditLog, loadAuditEntries, computeAudi
|
|
|
23
24
|
import { renderTemplate } from './notifications.js';
|
|
24
25
|
import { admitIssueResource, createPipelineAdmission, } from './admission.js';
|
|
25
26
|
import { createPipelineAdapterRegistry, createPipelineWebhookBridge, resolveAdapterFromGit, scanPipelineAdapters, resolveIssueTrackerFromConfig, } from './adapters.js';
|
|
26
|
-
import { existsSync, readFileSync,
|
|
27
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
27
28
|
import { join } from 'node:path';
|
|
28
29
|
import { defaultSandboxConstraints, DEFAULT_CONFIG_DIR_NAME, DEFAULT_PR_FOOTER, DEFAULT_LINT_COMMAND, DEFAULT_FORMAT_COMMAND, DEFAULT_COMMIT_MESSAGE_TEMPLATE, DEFAULT_COMMIT_CO_AUTHOR, NOTIFICATION_TITLES, } from './defaults.js';
|
|
29
30
|
import { checkFrameworkCompliance, getControlCatalog, getFrameworkMappings, listSupportedFrameworks, } from './compliance-extended.js';
|
|
@@ -33,6 +34,7 @@ import { hasResourceChanged, fingerprintResource } from './reconcilers.js';
|
|
|
33
34
|
import { CostTracker } from './cost-tracker.js';
|
|
34
35
|
import { enrichAgentContext } from './context-enrichment.js';
|
|
35
36
|
import { reportGateCheckRuns } from './check-runs.js';
|
|
37
|
+
import { WorktreePoolManager, readParallelismMode } from './runtime/index.js';
|
|
36
38
|
/**
|
|
37
39
|
* Execute the full AI-SDLC pipeline for a given issue ID.
|
|
38
40
|
*/
|
|
@@ -43,10 +45,32 @@ export async function executePipeline(issueId, options = {}) {
|
|
|
43
45
|
(options.useStructuredLogger ? createStructuredConsoleLogger() : createLogger());
|
|
44
46
|
const auditLog = options.auditLog ?? createDefaultAuditLog(workDir);
|
|
45
47
|
const metricStore = options.metricStore;
|
|
48
|
+
// RFC-0010 §6/§7 Phase 2: parallelism. Per AISDLC-116 (maintainer directive 2026-05-01),
|
|
49
|
+
// AI_SDLC_PARALLELISM now defaults to 'on' — corpus-driven (no parallelism-related incidents
|
|
50
|
+
// in the trailing observation window) rather than calendar-driven. Explicit
|
|
51
|
+
// 'experimental' is preserved for callers pinning the pre-promotion mode; explicit
|
|
52
|
+
// 'off' / 'disabled' / 'false' / '0' is the opt-out path. When the resolved mode is
|
|
53
|
+
// not 'off', a WorktreePoolManager is instantiated for the worker-pool dispatcher
|
|
54
|
+
// (RFC-0010 §9). The manager is constructed but not yet routed through — Phase 2
|
|
55
|
+
// shipped the wire-in surface; Phase 3 wires the worker pool to consume it.
|
|
56
|
+
const parallelismMode = readParallelismMode();
|
|
57
|
+
let worktreePool;
|
|
58
|
+
if (parallelismMode !== 'off') {
|
|
59
|
+
worktreePool = new WorktreePoolManager(workDir);
|
|
60
|
+
log.info(`[parallelism] mode=${parallelismMode}, pool root=${worktreePool.rootDir}`);
|
|
61
|
+
}
|
|
62
|
+
void worktreePool; // referenced by Phase 3 dispatcher; silences unused-var lint until then
|
|
46
63
|
// 1. Load .ai-sdlc/ config (async: includes adapter scanning + manifest distribution)
|
|
47
64
|
log.stage('load-config');
|
|
48
65
|
const config = await loadConfigAsync(configDir);
|
|
49
66
|
log.stageEnd('load-config');
|
|
67
|
+
// If the caller (e.g., cli-watch's pipeline dispatcher) selected a specific
|
|
68
|
+
// Pipeline resource, override the on-disk default. Without this, multi-
|
|
69
|
+
// pipeline configs (RFC-0010 dual workflow: pipeline.yaml + pipeline-backlog.yaml)
|
|
70
|
+
// always fall back to pipeline.yaml because loadConfig prefers it as canonical.
|
|
71
|
+
if (options.pipelineOverride) {
|
|
72
|
+
config.pipeline = options.pipelineOverride;
|
|
73
|
+
}
|
|
50
74
|
// Kill switch check (before any work)
|
|
51
75
|
if (options.security) {
|
|
52
76
|
await checkKillSwitch(options.security);
|
|
@@ -102,6 +126,12 @@ export async function executePipeline(issueId, options = {}) {
|
|
|
102
126
|
description: issue.description,
|
|
103
127
|
});
|
|
104
128
|
}
|
|
129
|
+
// Capture the user's current HEAD so we can restore it after the pipeline.
|
|
130
|
+
// Without this, `git checkout <issue-branch>` inside the pipeline body
|
|
131
|
+
// leaves the user's working tree on the issue branch even after the run
|
|
132
|
+
// completes (the AISDLC-68 incident). Long-term fix is a worktree pool
|
|
133
|
+
// (RFC-0010 §7); this is the pragmatic save+restore.
|
|
134
|
+
const originalHead = await captureCurrentBranch(workDir);
|
|
105
135
|
// Wrap pipeline body in try/catch to record failure episodes
|
|
106
136
|
try {
|
|
107
137
|
return await executePipelineBody(issueId, issue, config, qualityGate, agentRole, autonomyPolicy, tracker, sc, auditLog, metricStore, options, log, workDir);
|
|
@@ -122,6 +152,121 @@ export async function executePipeline(issueId, options = {}) {
|
|
|
122
152
|
}
|
|
123
153
|
throw err;
|
|
124
154
|
}
|
|
155
|
+
finally {
|
|
156
|
+
await restoreOriginalBranch(workDir, originalHead, log);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Capture the current branch name (or commit SHA in detached-HEAD state) so the
|
|
161
|
+
* pipeline can restore the user's worktree after the run. Returns null on git
|
|
162
|
+
* failure — callers treat null as "don't try to restore".
|
|
163
|
+
*
|
|
164
|
+
* @internal — exported for unit tests.
|
|
165
|
+
*/
|
|
166
|
+
export async function captureCurrentBranch(workDir) {
|
|
167
|
+
// cleanGitEnv() strips GIT_DIR / GIT_WORK_TREE / GIT_INDEX_FILE so git
|
|
168
|
+
// resolves against `workDir`'s own .git rather than whatever a parent
|
|
169
|
+
// process (e.g. husky pre-push hook running in another worktree) leaked
|
|
170
|
+
// into the env (AISDLC-72).
|
|
171
|
+
try {
|
|
172
|
+
const { stdout } = await execFileAsync('git', ['symbolic-ref', '--short', 'HEAD'], {
|
|
173
|
+
cwd: workDir,
|
|
174
|
+
env: cleanGitEnv(),
|
|
175
|
+
});
|
|
176
|
+
return stdout.trim();
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// Detached HEAD or no git repo. Try the SHA fallback.
|
|
180
|
+
try {
|
|
181
|
+
const { stdout } = await execFileAsync('git', ['rev-parse', 'HEAD'], {
|
|
182
|
+
cwd: workDir,
|
|
183
|
+
env: cleanGitEnv(),
|
|
184
|
+
});
|
|
185
|
+
return stdout.trim();
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Restore the user's original HEAD if the pipeline switched branches AND the
|
|
194
|
+
* working tree is clean. If the working tree has uncommitted changes (from a
|
|
195
|
+
* partial pipeline run), log a warning and leave HEAD where it is — better to
|
|
196
|
+
* preserve the pipeline's state than to clobber whatever the user has.
|
|
197
|
+
*
|
|
198
|
+
* @internal — exported for unit tests.
|
|
199
|
+
*/
|
|
200
|
+
export async function restoreOriginalBranch(workDir, originalHead, log) {
|
|
201
|
+
if (!originalHead)
|
|
202
|
+
return;
|
|
203
|
+
try {
|
|
204
|
+
const current = await captureCurrentBranch(workDir);
|
|
205
|
+
if (current === originalHead)
|
|
206
|
+
return;
|
|
207
|
+
// Refuse to checkout if the worktree has uncommitted changes — git would
|
|
208
|
+
// either block the checkout or carry the changes across, both bad.
|
|
209
|
+
// cleanGitEnv() prevents leaked GIT_DIR from corrupting these calls (AISDLC-72).
|
|
210
|
+
const { stdout } = await execFileAsync('git', ['status', '--porcelain'], {
|
|
211
|
+
cwd: workDir,
|
|
212
|
+
env: cleanGitEnv(),
|
|
213
|
+
});
|
|
214
|
+
if (stdout.trim().length > 0) {
|
|
215
|
+
log?.info(`[pipeline] worktree dirty after pipeline; HEAD left at \`${current}\`. ` +
|
|
216
|
+
`To restore: \`git stash && git checkout ${originalHead}\``);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
await execFileAsync('git', ['checkout', originalHead], {
|
|
220
|
+
cwd: workDir,
|
|
221
|
+
env: cleanGitEnv(),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
log?.info(`[pipeline] failed to restore HEAD to \`${originalHead}\`: ${err.message}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Push a branch to origin, rebasing onto the remote tip if it has advanced.
|
|
230
|
+
* Pre-AISDLC-68-rerun the pipeline did a plain `git push` and rejected with
|
|
231
|
+
* non-fast-forward when the remote branch had drifted (e.g. a previous run's
|
|
232
|
+
* commits or a manual edit). The fix: try push; on non-fast-forward, fetch +
|
|
233
|
+
* rebase HEAD onto origin/<branch>, retry once. Rebase conflicts surface as
|
|
234
|
+
* the original error so the operator can resolve manually.
|
|
235
|
+
*
|
|
236
|
+
* @internal — exported for unit tests.
|
|
237
|
+
*/
|
|
238
|
+
export async function pushBranchWithRebase(workDir, branchName, log) {
|
|
239
|
+
// cleanGitEnv() ensures these git calls bind to `workDir`'s own .git, not
|
|
240
|
+
// a leaked GIT_DIR from a parent process (AISDLC-72).
|
|
241
|
+
const env = cleanGitEnv();
|
|
242
|
+
try {
|
|
243
|
+
await execFileAsync('git', ['push', 'origin', branchName], { cwd: workDir, env });
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
const stderr = err.stderr ?? err.message;
|
|
248
|
+
if (!/non-fast-forward|rejected/i.test(stderr)) {
|
|
249
|
+
throw err;
|
|
250
|
+
}
|
|
251
|
+
log?.info(`[pipeline] push rejected (non-fast-forward); rebasing onto origin/${branchName}`);
|
|
252
|
+
}
|
|
253
|
+
// Fetch + rebase + retry. If the rebase fails, surface a clear error.
|
|
254
|
+
try {
|
|
255
|
+
await execFileAsync('git', ['fetch', 'origin', branchName], { cwd: workDir, env });
|
|
256
|
+
await execFileAsync('git', ['rebase', `origin/${branchName}`], { cwd: workDir, env });
|
|
257
|
+
}
|
|
258
|
+
catch (rebaseErr) {
|
|
259
|
+
// Abort the partial rebase so the worktree isn't left in a half-merged state.
|
|
260
|
+
try {
|
|
261
|
+
await execFileAsync('git', ['rebase', '--abort'], { cwd: workDir, env });
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
/* nothing to abort */
|
|
265
|
+
}
|
|
266
|
+
throw new Error(`Push rebase failed for branch ${branchName}: ${rebaseErr.message}. ` +
|
|
267
|
+
`Resolve conflicts manually and re-run the pipeline.`);
|
|
268
|
+
}
|
|
269
|
+
await execFileAsync('git', ['push', 'origin', branchName], { cwd: workDir, env });
|
|
125
270
|
}
|
|
126
271
|
async function executePipelineBody(issueId, issue, config, qualityGate, agentRole, autonomyPolicy, tracker, sc, auditLog, metricStore, options, log, workDir) {
|
|
127
272
|
const issueNumber = issueIdToNumber(issueId);
|
|
@@ -262,11 +407,15 @@ async function executePipelineBody(issueId, issue, config, qualityGate, agentRol
|
|
|
262
407
|
const currentLevel = resolveAutonomyLevel(autonomyPolicy);
|
|
263
408
|
log.stageEnd('validate-issue');
|
|
264
409
|
// 7. Create branch and checkout locally (read pattern from pipeline config)
|
|
265
|
-
const branchVars =
|
|
410
|
+
const branchVars = buildIssueTemplateVars(issueId, issue.title);
|
|
266
411
|
const branchName = interpolateBranchPattern(config.pipeline?.spec.branching?.pattern, branchVars);
|
|
267
412
|
await sc.createBranch({ name: branchName });
|
|
268
|
-
|
|
269
|
-
await execFileAsync('git', ['
|
|
413
|
+
// cleanGitEnv() prevents leaked GIT_DIR from corrupting these calls (AISDLC-72).
|
|
414
|
+
await execFileAsync('git', ['fetch', 'origin', branchName], {
|
|
415
|
+
cwd: workDir,
|
|
416
|
+
env: cleanGitEnv(),
|
|
417
|
+
});
|
|
418
|
+
await execFileAsync('git', ['checkout', branchName], { cwd: workDir, env: cleanGitEnv() });
|
|
270
419
|
// 8. Resolve agent constraints
|
|
271
420
|
const resolved = resolveConstraints(agentRole.spec.constraints, currentLevel);
|
|
272
421
|
// 8b. Model selection: choose model based on complexity and budget pressure
|
|
@@ -423,9 +572,13 @@ async function executePipelineBody(issueId, issue, config, qualityGate, agentRol
|
|
|
423
572
|
`**${result.filesChanged.length} files changed.** Pushing branch...\n\n` +
|
|
424
573
|
activitySection);
|
|
425
574
|
await notifySlack(`:white_check_mark: Agent complete — ${result.filesChanged.length} files changed. Pushing...`);
|
|
426
|
-
// 12. Push branch (before validation to preserve work even if validation fails)
|
|
575
|
+
// 12. Push branch (before validation to preserve work even if validation fails).
|
|
576
|
+
// Fetch first + rebase if the remote has diverged so push fast-forwards
|
|
577
|
+
// cleanly. Without this, re-runs against an existing remote branch (e.g. when
|
|
578
|
+
// the issue branch was updated by another pipeline run or by a hand-edit)
|
|
579
|
+
// reject with non-fast-forward and the agent's work is stranded locally.
|
|
427
580
|
log.stage('push');
|
|
428
|
-
await
|
|
581
|
+
await pushBranchWithRebase(workDir, branchName, log);
|
|
429
582
|
log.stageEnd('push');
|
|
430
583
|
auditLog.record({
|
|
431
584
|
actor: 'system',
|
|
@@ -453,14 +606,24 @@ async function executePipelineBody(issueId, issue, config, qualityGate, agentRol
|
|
|
453
606
|
return validationResult;
|
|
454
607
|
});
|
|
455
608
|
if (!validation.passed) {
|
|
456
|
-
//
|
|
609
|
+
// One-line summary suitable for log lines + thrown error message.
|
|
610
|
+
const violationSummary = validation.violations.map((v) => `${v.rule}: ${v.message}`).join('; ');
|
|
611
|
+
// Record validation failure in audit log with full violation detail (rule
|
|
612
|
+
// + message), not just the rule names — the rule name alone doesn't tell
|
|
613
|
+
// the operator what to fix.
|
|
457
614
|
auditLog.record({
|
|
458
615
|
actor: 'system',
|
|
459
616
|
action: 'check',
|
|
460
617
|
resource: 'agent-output',
|
|
461
618
|
decision: 'denied',
|
|
462
|
-
details: {
|
|
619
|
+
details: {
|
|
620
|
+
violations: validation.violations.map((v) => ({ rule: v.rule, message: v.message })),
|
|
621
|
+
},
|
|
463
622
|
});
|
|
623
|
+
// Surface the rejection detail to the structured log so the operator sees
|
|
624
|
+
// it in stderr immediately. Without this the only signal was the
|
|
625
|
+
// (detail-free) thrown error message.
|
|
626
|
+
log.error(`[validate-output] rejected: ${violationSummary}`);
|
|
464
627
|
// Post comment explaining the violations
|
|
465
628
|
const violationList = validation.violations
|
|
466
629
|
.map((v) => `- **${v.rule}**: ${v.message}`)
|
|
@@ -468,8 +631,10 @@ async function executePipelineBody(issueId, issue, config, qualityGate, agentRol
|
|
|
468
631
|
await tracker.addComment(issueId, `## ${NOTIFICATION_TITLES.guardrailViolations}\n\n${violationList}\n\n` +
|
|
469
632
|
`The branch \`${branchName}\` has been pushed with your changes. You can review the work, ` +
|
|
470
633
|
`cherry-pick valid changes, or adjust the guardrails as needed.`);
|
|
471
|
-
// Exit without creating PR
|
|
472
|
-
|
|
634
|
+
// Exit without creating PR. Include the violation summary in the error
|
|
635
|
+
// message so cli-watch and downstream loggers see the actual rejection.
|
|
636
|
+
throw new Error(`Agent output failed guardrail validation: ${violationSummary}. ` +
|
|
637
|
+
`Branch ${branchName} preserved for review.`);
|
|
473
638
|
}
|
|
474
639
|
// Validation passed — record success
|
|
475
640
|
auditLog.record({
|
|
@@ -483,6 +648,7 @@ async function executePipelineBody(issueId, issue, config, qualityGate, agentRol
|
|
|
483
648
|
try {
|
|
484
649
|
const { stdout: headSha } = await execFileAsync('git', ['rev-parse', 'HEAD'], {
|
|
485
650
|
cwd: workDir,
|
|
651
|
+
env: cleanGitEnv(),
|
|
486
652
|
});
|
|
487
653
|
const gateResults = qualityGate.spec.gates.map((gate) => {
|
|
488
654
|
const evalResult = evaluatePipelineGate(gate, {
|
|
@@ -519,6 +685,7 @@ async function executePipelineBody(issueId, issue, config, qualityGate, agentRol
|
|
|
519
685
|
try {
|
|
520
686
|
const { stdout: diffStat } = await execFileAsync('git', ['diff', '--stat', 'HEAD~1'], {
|
|
521
687
|
cwd: workDir,
|
|
688
|
+
env: cleanGitEnv(),
|
|
522
689
|
});
|
|
523
690
|
const insertMatch = diffStat.match(/(\d+) insertions?\(\+\)/);
|
|
524
691
|
const deleteMatch = diffStat.match(/(\d+) deletions?\(-\)/);
|
|
@@ -578,7 +745,7 @@ async function executePipelineBody(issueId, issue, config, qualityGate, agentRol
|
|
|
578
745
|
}
|
|
579
746
|
provenanceBlock = '\n\n' + provenanceText;
|
|
580
747
|
}
|
|
581
|
-
const prVars =
|
|
748
|
+
const prVars = buildIssueTemplateVars(issueId, issue.title);
|
|
582
749
|
const prTitle = interpolatePRTitle(prConfig?.titleTemplate, prVars);
|
|
583
750
|
const closeKeyword = prConfig?.closeKeyword ?? 'Closes';
|
|
584
751
|
const targetBranch = config.pipeline?.spec.branching?.targetBranch ?? 'main';
|
|
@@ -878,11 +1045,17 @@ function ensureRuntimeGitignore(workDir) {
|
|
|
878
1045
|
try {
|
|
879
1046
|
const gitignorePath = join(workDir, '.gitignore');
|
|
880
1047
|
const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, 'utf-8') : '';
|
|
881
|
-
const
|
|
1048
|
+
const SENTINEL = '# ai-sdlc:runtime-gitignore';
|
|
1049
|
+
if (existing.includes(SENTINEL))
|
|
1050
|
+
return;
|
|
1051
|
+
const missing = RUNTIME_GITIGNORE_PATHS.filter((entry) => !existing.split('\n').some((line) => line.trim() === entry));
|
|
882
1052
|
if (missing.length === 0)
|
|
883
1053
|
return;
|
|
884
|
-
|
|
885
|
-
|
|
1054
|
+
// Write atomically (writeFileSync, not appendFileSync) to avoid race conditions
|
|
1055
|
+
// when parallel test processes both read before either writes.
|
|
1056
|
+
const block = `${SENTINEL}\n` + missing.join('\n') + '\n';
|
|
1057
|
+
const newContent = existing.length > 0 ? existing.trimEnd() + '\n' + block : block;
|
|
1058
|
+
writeFileSync(gitignorePath, newContent, 'utf-8');
|
|
886
1059
|
}
|
|
887
1060
|
catch {
|
|
888
1061
|
// Best-effort — workDir may not exist yet in tests or dry-run scenarios
|
package/dist/fix-ci.js
CHANGED
|
@@ -14,6 +14,7 @@ import { parseDuration } from './policy-evaluators.js';
|
|
|
14
14
|
import { checkKillSwitch, issueAgentCredentials, revokeAgentCredentials, } from './security.js';
|
|
15
15
|
import { DEFAULT_MAX_FIX_ATTEMPTS, DEFAULT_MAX_LOG_LINES, DEFAULT_GH_CLI_TIMEOUT_MS, DEFAULT_CONFIG_DIR_NAME, defaultSandboxConstraints, NOTIFICATION_TITLES, } from './defaults.js';
|
|
16
16
|
import { createCycleDetectorFromConfig, checkAndHandleCycle } from './cycle-utils.js';
|
|
17
|
+
import { cleanGitEnv } from './runtime/git-env.js';
|
|
17
18
|
export const MAX_FIX_ATTEMPTS = DEFAULT_MAX_FIX_ATTEMPTS;
|
|
18
19
|
export const MAX_LOG_LINES = DEFAULT_MAX_LOG_LINES;
|
|
19
20
|
export const RETRY_MARKER = '<!-- ai-sdlc-fix-ci-attempt -->';
|
|
@@ -180,8 +181,10 @@ export async function executeFixCI(prNumber, runId, options = {}) {
|
|
|
180
181
|
const ciLogs = await fetchCILogs(runId, options._ciLogs, options.ciAdapter);
|
|
181
182
|
log.stageEnd('fetch-logs');
|
|
182
183
|
// 4. Determine branch and issue number
|
|
184
|
+
// cleanGitEnv() prevents leaked GIT_DIR from binding to a parent repo (AISDLC-72).
|
|
183
185
|
const { stdout: branchStdout } = await execFileAsync('git', ['branch', '--show-current'], {
|
|
184
186
|
cwd: workDir,
|
|
187
|
+
env: cleanGitEnv(),
|
|
185
188
|
});
|
|
186
189
|
const currentBranch = branchStdout.trim();
|
|
187
190
|
const issueId = extractIssueId(currentBranch);
|
|
@@ -341,8 +344,12 @@ export async function executeFixCI(prNumber, runId, options = {}) {
|
|
|
341
344
|
});
|
|
342
345
|
});
|
|
343
346
|
// 10. Push to the same branch (CI re-runs automatically)
|
|
347
|
+
// cleanGitEnv() prevents leaked GIT_DIR from binding to a parent repo (AISDLC-72).
|
|
344
348
|
log.stage('push');
|
|
345
|
-
await execFileAsync('git', ['push', 'origin', currentBranch], {
|
|
349
|
+
await execFileAsync('git', ['push', 'origin', currentBranch], {
|
|
350
|
+
cwd: workDir,
|
|
351
|
+
env: cleanGitEnv(),
|
|
352
|
+
});
|
|
346
353
|
log.stageEnd('push');
|
|
347
354
|
auditLog.record({
|
|
348
355
|
actor: 'system',
|
package/dist/fix-review.js
CHANGED
|
@@ -14,6 +14,7 @@ import { parseDuration } from './policy-evaluators.js';
|
|
|
14
14
|
import { checkKillSwitch, issueAgentCredentials, revokeAgentCredentials, } from './security.js';
|
|
15
15
|
import { DEFAULT_GH_CLI_TIMEOUT_MS, DEFAULT_CONFIG_DIR_NAME, defaultSandboxConstraints, NOTIFICATION_TITLES, } from './defaults.js';
|
|
16
16
|
import { createCycleDetectorFromConfig, checkAndHandleCycle } from './cycle-utils.js';
|
|
17
|
+
import { cleanGitEnv } from './runtime/git-env.js';
|
|
17
18
|
// Default max review-fix attempts (lower than CI-fix since reviews are more deterministic)
|
|
18
19
|
export const MAX_REVIEW_FIX_ATTEMPTS = 2;
|
|
19
20
|
export const RETRY_MARKER = '<!-- ai-sdlc-fix-review-attempt -->';
|
|
@@ -210,8 +211,10 @@ export async function executeFixReview(prNumber, options = {}) {
|
|
|
210
211
|
return;
|
|
211
212
|
}
|
|
212
213
|
// 4. Determine branch and issue number
|
|
214
|
+
// cleanGitEnv() prevents leaked GIT_DIR from binding to a parent repo (AISDLC-72).
|
|
213
215
|
const { stdout: branchStdout } = await execFileAsync('git', ['branch', '--show-current'], {
|
|
214
216
|
cwd: workDir,
|
|
217
|
+
env: cleanGitEnv(),
|
|
215
218
|
});
|
|
216
219
|
const currentBranch = sanitizeBranchName(branchStdout.trim());
|
|
217
220
|
const issueId = extractIssueId(currentBranch);
|
|
@@ -371,8 +374,12 @@ export async function executeFixReview(prNumber, options = {}) {
|
|
|
371
374
|
});
|
|
372
375
|
});
|
|
373
376
|
// 10. Push to the same branch (review agents re-run automatically via pull_request.synchronize)
|
|
377
|
+
// cleanGitEnv() prevents leaked GIT_DIR from binding to a parent repo (AISDLC-72).
|
|
374
378
|
log.stage('push');
|
|
375
|
-
await execFileAsync('git', ['push', 'origin', currentBranch], {
|
|
379
|
+
await execFileAsync('git', ['push', 'origin', currentBranch], {
|
|
380
|
+
cwd: workDir,
|
|
381
|
+
env: cleanGitEnv(),
|
|
382
|
+
});
|
|
376
383
|
log.stageEnd('push');
|
|
377
384
|
auditLog.record({
|
|
378
385
|
actor: 'system',
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClaudeCodeAdapter — wraps Claude Code CLI behind the HarnessAdapter contract.
|
|
3
|
+
* Uses the local `claude` CLI in `-p --output-format stream-json` mode, authenticating
|
|
4
|
+
* via whatever credential the CLI is logged into (Pro/Max subscription or API key).
|
|
5
|
+
*/
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import type { HarnessAdapter, HarnessAvailability, HarnessCapabilities, HarnessEvent, HarnessInput, HarnessName, HarnessRequires, HarnessResult } from '../types.js';
|
|
8
|
+
export interface ClaudeCodeAdapterDeps {
|
|
9
|
+
env?: NodeJS.ProcessEnv;
|
|
10
|
+
/** Override the actual invocation path; tests inject a stub. */
|
|
11
|
+
invoke?: (input: HarnessInput, onEvent?: (e: HarnessEvent) => void) => Promise<HarnessResult>;
|
|
12
|
+
/** Override version probe for tests. */
|
|
13
|
+
probe?: () => Promise<HarnessAvailability>;
|
|
14
|
+
/** Override the spawn function (tests inject a fake child process). */
|
|
15
|
+
spawn?: typeof spawn;
|
|
16
|
+
}
|
|
17
|
+
export declare class ClaudeCodeAdapter implements HarnessAdapter {
|
|
18
|
+
private readonly deps;
|
|
19
|
+
readonly name: HarnessName;
|
|
20
|
+
readonly capabilities: HarnessCapabilities;
|
|
21
|
+
readonly requires: HarnessRequires;
|
|
22
|
+
private cachedAvailability;
|
|
23
|
+
constructor(deps?: ClaudeCodeAdapterDeps);
|
|
24
|
+
getAccountId(): Promise<string | null>;
|
|
25
|
+
isAvailable(): Promise<HarnessAvailability>;
|
|
26
|
+
invoke(input: HarnessInput, onEvent?: (e: HarnessEvent) => void): Promise<HarnessResult>;
|
|
27
|
+
availableModels(): Promise<string[]>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=claude-code.d.ts.map
|