@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.
@@ -3,7 +3,8 @@
3
3
  * webhook bridge, git-based adapter resolver, and adapter registry/scanner
4
4
  * into the dogfood pipeline.
5
5
  */
6
- import { type AdapterRegistry, type ScanOptions, type ScanResult, type WebhookBridge, type GitAdapterFetcher, type GitResolveResult, type AuditLog, type AuditSink, type Sandbox, type SecretStore, type MemoryStore, type EventBus, type CIPipeline } from '@ai-sdlc/reference';
6
+ import type { AiSdlcConfig } from './config.js';
7
+ import { type IssueTracker, type AdapterRegistry, type ScanOptions, type ScanResult, type WebhookBridge, type GitAdapterFetcher, type GitResolveResult, type AuditLog, type AuditSink, type Sandbox, type SecretStore, type MemoryStore, type EventBus, type CIPipeline } from '@ai-sdlc/reference';
7
8
  /**
8
9
  * Create an adapter registry pre-loaded with all built-in and community adapters.
9
10
  */
@@ -55,6 +56,20 @@ export declare function scanPipelineAdapters(options: ScanOptions): Promise<Scan
55
56
  * Requires `GITHUB_REPOSITORY_OWNER` and `GITHUB_REPOSITORY` env vars.
56
57
  */
57
58
  export declare function createPipelineCIAdapter(): CIPipeline;
58
- export { createGitHubCIPipeline, createDockerSandbox, createLinearIssueTracker, resolveSecret, createGitLabSourceControl, createGitLabCIPipeline, createJiraIssueTracker, createBacklogMdIssueTracker, createWebhookServer, createGitHubWebhookProvider, verifyGitHubSignature, createGitLabWebhookProvider, verifyGitLabToken, createJiraWebhookProvider, createLinearWebhookProvider, verifyLinearSignature, createAdapterRegistry, validateAdapterMetadata, parseMetadataYaml, scanLocalAdapters, createStubCodeAnalysis, createStubMessenger, createStubDeploymentTarget, createStubGitLabCI, createStubGitLabSource, createStubJira, createStubBitbucket, createStubSonarQube, createStubSemgrep, createInMemoryAuditSink, createFileSink, createEnvSecretStore, createInMemoryMemoryStore, createInProcessEventBus, createStubSandbox, createWebhookBridge, parseGitAdapterRef, buildRawUrl, createGitAdapterFetcher, createStubGitAdapterFetcher, resolveGitAdapter, } from '@ai-sdlc/reference';
59
- export type { AdapterRegistry, AdapterMetadata, AdapterStability, AdapterFactory, MetadataValidationResult, ScanOptions, ScanResult, WebhookBridge, WebhookTransformer, GitAdapterReference, GitAdapterFetcher, GitResolveResult, CIPipeline, CodeAnalysis, Messenger, DeploymentTarget, EventBus, IssueTracker, LinearClientLike, IssueComment, AdapterInterfaces, EventStream, IssueFilter, CommitStatus, TestResults, CoverageReport, Finding, SeveritySummary, DeploymentStatus, StubCodeAnalysisConfig, StubCodeAnalysisAdapter, NotificationLogEntry, StubMessengerAdapter, StubDeploymentTargetAdapter, StubGitLabCIAdapter, StubGitLabSourceAdapter, StubJiraAdapter, StubBitbucketAdapter, StubSonarQubeConfig, StubSonarQubeAdapter, StubSemgrepConfig, StubSemgrepAdapter, AuditSink, AuditLog, InMemoryAuditSink, SecretStore, Sandbox, MemoryStore, InMemoryMemoryStore, InProcessEventBus, DockerSandboxConfig, BuildStatus, GitLabConfig, JiraConfig, BacklogMdConfig, BacklogFs, WebhookServer, WebhookServerConfig, WebhookProviderConfig, GitHubWebhookConfig, GitHubWebhookBridges, GitLabWebhookConfig, JiraWebhookConfig, LinearWebhookConfig, } from '@ai-sdlc/reference';
59
+ /**
60
+ * Resolve an IssueTracker from the adapterBindings in config.
61
+ *
62
+ * - 0 bindings → falls back to GitHub IssueTracker
63
+ * - 1 binding → returns that tracker directly
64
+ * - N bindings → wraps in CompositeIssueTracker
65
+ */
66
+ export declare function resolveIssueTrackerFromConfig(config: AiSdlcConfig, fallbackGitHubConfig: {
67
+ org: string;
68
+ repo: string;
69
+ token: {
70
+ secretRef: string;
71
+ };
72
+ }): IssueTracker;
73
+ export { createGitHubCIPipeline, createDockerSandbox, createLinearIssueTracker, resolveSecret, createGitLabSourceControl, createGitLabCIPipeline, createJiraIssueTracker, createBacklogMdIssueTracker, createWebhookServer, createGitHubWebhookProvider, verifyGitHubSignature, createGitLabWebhookProvider, verifyGitLabToken, createJiraWebhookProvider, createLinearWebhookProvider, verifyLinearSignature, createAdapterRegistry, validateAdapterMetadata, parseMetadataYaml, scanLocalAdapters, createStubCodeAnalysis, createStubMessenger, createStubDeploymentTarget, createStubGitLabCI, createStubGitLabSource, createStubJira, createStubBitbucket, createStubSonarQube, createStubSemgrep, createInMemoryAuditSink, createFileSink, createEnvSecretStore, createInMemoryMemoryStore, createInProcessEventBus, createStubSandbox, createCompositeIssueTracker, createWebhookBridge, parseGitAdapterRef, buildRawUrl, createGitAdapterFetcher, createStubGitAdapterFetcher, resolveGitAdapter, } from '@ai-sdlc/reference';
74
+ export type { AdapterRegistry, AdapterMetadata, AdapterStability, AdapterFactory, MetadataValidationResult, ScanOptions, ScanResult, WebhookBridge, WebhookTransformer, GitAdapterReference, GitAdapterFetcher, GitResolveResult, CIPipeline, CodeAnalysis, Messenger, DeploymentTarget, EventBus, IssueTracker, LinearClientLike, IssueComment, AdapterInterfaces, EventStream, IssueFilter, CommitStatus, TestResults, CoverageReport, Finding, SeveritySummary, DeploymentStatus, StubCodeAnalysisConfig, StubCodeAnalysisAdapter, NotificationLogEntry, StubMessengerAdapter, StubDeploymentTargetAdapter, StubGitLabCIAdapter, StubGitLabSourceAdapter, StubJiraAdapter, StubBitbucketAdapter, StubSonarQubeConfig, StubSonarQubeAdapter, StubSemgrepConfig, StubSemgrepAdapter, AuditSink, AuditLog, InMemoryAuditSink, SecretStore, Sandbox, MemoryStore, InMemoryMemoryStore, InProcessEventBus, DockerSandboxConfig, BuildStatus, GitLabConfig, JiraConfig, BacklogMdConfig, BacklogFs, WebhookServer, WebhookServerConfig, WebhookProviderConfig, GitHubWebhookConfig, GitHubWebhookBridges, GitLabWebhookConfig, JiraWebhookConfig, LinearWebhookConfig, CompositeIssueTrackerConfig, BackendRoute, } from '@ai-sdlc/reference';
60
75
  //# sourceMappingURL=adapters.d.ts.map
package/dist/adapters.js CHANGED
@@ -14,6 +14,8 @@ createStubCodeAnalysis, createStubMessenger, createStubDeploymentTarget, createS
14
14
  createInMemoryAuditSink, createFileSink, createAuditLog, createEnvSecretStore, createInMemoryMemoryStore, createInProcessEventBus, createStubSandbox,
15
15
  // Docker sandbox
16
16
  createDockerSandbox,
17
+ // OpenShell sandbox
18
+ createOpenShellSandbox,
17
19
  // Backlog.md adapter
18
20
  createBacklogMdIssueTracker,
19
21
  // Webhook bridge (used in function body)
@@ -21,7 +23,13 @@ createWebhookBridge,
21
23
  // Git resolver (used in function bodies)
22
24
  createStubGitAdapterFetcher, createGitAdapterFetcher, resolveGitAdapter,
23
25
  // GitHub CI adapter
24
- createGitHubCIPipeline, } from '@ai-sdlc/reference';
26
+ createGitHubCIPipeline,
27
+ // GitHub issue tracker
28
+ createGitHubIssueTracker,
29
+ // Composite issue tracker
30
+ createCompositeIssueTracker,
31
+ // Production adapters (for resolveIssueTrackerFromConfig)
32
+ createJiraIssueTracker, createLinearIssueTracker, } from '@ai-sdlc/reference';
25
33
  /**
26
34
  * Create an adapter registry pre-loaded with all built-in and community adapters.
27
35
  */
@@ -69,6 +77,24 @@ export function createPipelineAdapterRegistry() {
69
77
  };
70
78
  return createDockerSandbox(exec, config);
71
79
  });
80
+ registry.register(stubMeta('openshell-sandbox', 'OpenShell Sandbox', 'Sandbox@v1', 'openshell'), () => {
81
+ const exec = async (cmd) => {
82
+ const { exec: cpExec } = await import('node:child_process');
83
+ const { promisify } = await import('node:util');
84
+ const execAsync = promisify(cpExec);
85
+ const { stdout } = await execAsync(cmd);
86
+ return stdout;
87
+ };
88
+ const config = {
89
+ workDir: process.env.AI_SDLC_WORK_DIR,
90
+ binaryPath: process.env.AI_SDLC_OPENSHELL_BIN,
91
+ autoProviders: [
92
+ { name: 'claude', type: 'claude' },
93
+ { name: 'github', type: 'github' },
94
+ ],
95
+ };
96
+ return createOpenShellSandbox(exec, config);
97
+ });
72
98
  registry.register(stubMeta('env-secret-store', 'Environment Secret Store', 'SecretStore@v1', 'env'), () => createEnvSecretStore());
73
99
  registry.register(stubMeta('memory-store', 'In-Memory Memory Store', 'MemoryStore@v1', 'memory'), () => createInMemoryMemoryStore());
74
100
  registry.register(stubMeta('in-process-event-bus', 'In-Process Event Bus', 'EventBus@v1', 'in-process'), () => createInProcessEventBus());
@@ -87,7 +113,12 @@ export function resolveInfrastructure(registry, config) {
87
113
  const auditLog = createAuditLog(auditSink);
88
114
  // Resolve from registry — factories are guaranteed present when using
89
115
  // createPipelineAdapterRegistry(), but we guard for custom registries.
90
- const sandboxProvider = process.env.AI_SDLC_SANDBOX_PROVIDER === 'docker' ? 'docker-sandbox' : 'stub-sandbox';
116
+ const sandboxEnv = process.env.AI_SDLC_SANDBOX_PROVIDER;
117
+ const sandboxProvider = sandboxEnv === 'openshell'
118
+ ? 'openshell-sandbox'
119
+ : sandboxEnv === 'docker'
120
+ ? 'docker-sandbox'
121
+ : 'stub-sandbox';
91
122
  const sandbox = registry.getFactory(sandboxProvider)?.() ?? createStubSandbox();
92
123
  const secretStore = registry.getFactory('env-secret-store')?.() ??
93
124
  createEnvSecretStore();
@@ -140,6 +171,63 @@ export function createPipelineCIAdapter() {
140
171
  workflowFile: process.env.AI_SDLC_WORKFLOW_FILE ?? DEFAULT_WORKFLOW_FILE,
141
172
  });
142
173
  }
174
+ // ── Issue tracker resolution from config ────────────────────────────
175
+ /**
176
+ * Resolve an IssueTracker from the adapterBindings in config.
177
+ *
178
+ * - 0 bindings → falls back to GitHub IssueTracker
179
+ * - 1 binding → returns that tracker directly
180
+ * - N bindings → wraps in CompositeIssueTracker
181
+ */
182
+ export function resolveIssueTrackerFromConfig(config, fallbackGitHubConfig) {
183
+ const bindings = (config.adapterBindings ?? []).filter((b) => b.spec.interface === 'IssueTracker');
184
+ if (bindings.length === 0) {
185
+ return createGitHubIssueTracker(fallbackGitHubConfig);
186
+ }
187
+ const backends = bindings.map((binding) => {
188
+ const cfg = binding.spec.config ?? {};
189
+ switch (binding.spec.type) {
190
+ case 'backlog-md':
191
+ return {
192
+ prefix: cfg.taskPrefix ?? 'AISDLC',
193
+ adapter: createBacklogMdIssueTracker({
194
+ backlogDir: cfg.backlogDir ?? './backlog',
195
+ taskPrefix: cfg.taskPrefix,
196
+ }),
197
+ };
198
+ case 'github':
199
+ return {
200
+ prefix: null,
201
+ adapter: createGitHubIssueTracker({
202
+ org: cfg.org ?? fallbackGitHubConfig.org,
203
+ repo: cfg.repo ?? fallbackGitHubConfig.repo,
204
+ token: fallbackGitHubConfig.token,
205
+ }),
206
+ };
207
+ case 'jira':
208
+ return {
209
+ prefix: cfg.projectKey ?? null,
210
+ adapter: createJiraIssueTracker(cfg),
211
+ };
212
+ case 'linear':
213
+ return {
214
+ prefix: cfg.teamKey ?? null,
215
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
216
+ adapter: createLinearIssueTracker(cfg),
217
+ };
218
+ default:
219
+ // Unknown type — fall back to GitHub
220
+ return {
221
+ prefix: null,
222
+ adapter: createGitHubIssueTracker(fallbackGitHubConfig),
223
+ };
224
+ }
225
+ });
226
+ if (backends.length === 1) {
227
+ return backends[0].adapter;
228
+ }
229
+ return createCompositeIssueTracker({ backends });
230
+ }
143
231
  // Direct re-exports (passthrough)
144
232
  export {
145
233
  // Core adapters
@@ -158,6 +246,8 @@ createAdapterRegistry, validateAdapterMetadata, parseMetadataYaml, scanLocalAdap
158
246
  createStubCodeAnalysis, createStubMessenger, createStubDeploymentTarget, createStubGitLabCI, createStubGitLabSource, createStubJira, createStubBitbucket, createStubSonarQube, createStubSemgrep,
159
247
  // Infrastructure adapter stubs
160
248
  createInMemoryAuditSink, createFileSink, createEnvSecretStore, createInMemoryMemoryStore, createInProcessEventBus, createStubSandbox,
249
+ // Composite issue tracker
250
+ createCompositeIssueTracker,
161
251
  // Webhook bridge
162
252
  createWebhookBridge,
163
253
  // Git resolver
@@ -134,24 +134,20 @@ spec:
134
134
  action: demote-one-level
135
135
  cooldown: 2w
136
136
  `;
137
- const GITIGNORE_ENTRIES = [
138
- '# AI-SDLC runtime artifacts',
139
- '.ai-sdlc/state.db',
140
- '.ai-sdlc/state/',
141
- '.ai-sdlc/audit.jsonl',
142
- ];
137
+ const GITIGNORE_PATHS = ['.ai-sdlc/state.db', '.ai-sdlc/state/', '.ai-sdlc/audit.jsonl'];
143
138
  /** Ensure .gitignore includes AI-SDLC runtime artifact entries. */
144
139
  function ensureGitignore(projectDir, dryRun, prefix = '') {
145
140
  const gitignorePath = join(projectDir, '.gitignore');
146
141
  const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, 'utf-8') : '';
147
- const missing = GITIGNORE_ENTRIES.filter((entry) => !existing.includes(entry));
142
+ // Only check path entries (not comments) to avoid duplicate blocks
143
+ const missing = GITIGNORE_PATHS.filter((entry) => !existing.includes(entry));
148
144
  if (missing.length === 0)
149
145
  return;
150
146
  if (dryRun) {
151
147
  console.log(`${prefix} Would update .gitignore`);
152
148
  return;
153
149
  }
154
- const block = '\n' + missing.join('\n') + '\n';
150
+ const block = '\n# AI-SDLC runtime artifacts\n' + missing.join('\n') + '\n';
155
151
  appendFileSync(gitignorePath, block, 'utf-8');
156
152
  console.log(`${prefix} updated .gitignore`);
157
153
  }
@@ -6,7 +6,7 @@ import { Orchestrator } from '../../orchestrator.js';
6
6
  import { formatOutput } from '../formatters/index.js';
7
7
  export const runCommand = new Command('run')
8
8
  .description('Run the AI-SDLC pipeline for a specific issue')
9
- .requiredOption('-i, --issue <number>', 'Issue number to process', parseInt)
9
+ .requiredOption('-i, --issue <id>', 'Issue ID to process')
10
10
  .option('--state <path>', 'SQLite state database path')
11
11
  .action(async (opts, cmd) => {
12
12
  const globalOpts = cmd.parent?.opts() ?? {};
@@ -19,7 +19,7 @@ export const runCommand = new Command('run')
19
19
  const result = await orchestrator.run(opts.issue);
20
20
  console.log(formatOutput(format, {
21
21
  type: 'run',
22
- issueNumber: opts.issue,
22
+ issueId: opts.issue,
23
23
  prUrl: result.prUrl,
24
24
  filesChanged: result.filesChanged.length,
25
25
  promotionEligible: result.promotionEligible,
package/dist/config.d.ts CHANGED
@@ -11,7 +11,10 @@ export interface AiSdlcConfig {
11
11
  agentRole?: AgentRole;
12
12
  qualityGate?: QualityGate;
13
13
  autonomyPolicy?: AutonomyPolicy;
14
+ /** @deprecated Use `adapterBindings` instead. Returns the first binding if any exist. */
14
15
  adapterBinding?: AdapterBinding;
16
+ /** All AdapterBinding resources found in the config directory. */
17
+ adapterBindings?: AdapterBinding[];
15
18
  adapterRegistry?: AdapterRegistry;
16
19
  }
17
20
  /**
package/dist/config.js CHANGED
@@ -9,12 +9,12 @@ import { readFileSync, readdirSync, existsSync } from 'node:fs';
9
9
  import { resolve, join } from 'node:path';
10
10
  import { parse as parseYaml } from 'yaml';
11
11
  import { validateResource, createAdapterRegistry, scanLocalAdapters, } from '@ai-sdlc/reference';
12
+ /** Resource kinds that allow only a single instance. */
12
13
  const KIND_KEY = {
13
14
  Pipeline: 'pipeline',
14
15
  AgentRole: 'agentRole',
15
16
  QualityGate: 'qualityGate',
16
17
  AutonomyPolicy: 'autonomyPolicy',
17
- AdapterBinding: 'adapterBinding',
18
18
  };
19
19
  /**
20
20
  * Load all YAML files from the given directory, validate each against
@@ -39,11 +39,20 @@ export function loadConfig(configDir) {
39
39
  throw new Error(`Validation failed for ${file}:\n${msgs}`);
40
40
  }
41
41
  const resource = result.data;
42
- const key = KIND_KEY[resource.kind];
43
- if (key) {
44
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
- config[key] = resource;
42
+ if (resource.kind === 'AdapterBinding') {
43
+ (config.adapterBindings ??= []).push(resource);
46
44
  }
45
+ else {
46
+ const key = KIND_KEY[resource.kind];
47
+ if (key) {
48
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
+ config[key] = resource;
50
+ }
51
+ }
52
+ }
53
+ // Backward compat: set adapterBinding to the first binding
54
+ if (config.adapterBindings?.length) {
55
+ config.adapterBinding = config.adapterBindings[0];
47
56
  }
48
57
  return config;
49
58
  }
package/dist/execute.d.ts CHANGED
@@ -14,6 +14,7 @@ import type { CodebaseContext } from './analysis/types.js';
14
14
  import type { AutonomyTracker } from './autonomy-tracker.js';
15
15
  import { CostTracker } from './cost-tracker.js';
16
16
  import type { StateStore } from './state/store.js';
17
+ import type { PriorityScore } from './priority.js';
17
18
  export interface PipelineResult {
18
19
  prUrl: string;
19
20
  filesChanged: string[];
@@ -73,9 +74,11 @@ export interface ExecuteOptions {
73
74
  costTracker?: CostTracker;
74
75
  /** StateStore for episodic context enrichment. */
75
76
  stateStore?: StateStore;
77
+ /** Priority score from PPA scoring (set by watch loop or caller). */
78
+ priorityScore?: PriorityScore;
76
79
  }
77
80
  /**
78
- * Execute the full AI-SDLC pipeline for a given issue number.
81
+ * Execute the full AI-SDLC pipeline for a given issue ID.
79
82
  */
80
- export declare function executePipeline(issueNumber: number, options?: ExecuteOptions): Promise<PipelineResult>;
83
+ export declare function executePipeline(issueId: string, options?: ExecuteOptions): Promise<PipelineResult>;
81
84
  //# sourceMappingURL=execute.d.ts.map