agentic-orchestrator 0.1.0 → 0.1.2

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/.dockerignore CHANGED
@@ -20,5 +20,4 @@ prompts
20
20
 
21
21
  # Local/editor artifacts
22
22
  *.iml
23
- *.log
24
23
  .DS_Store
package/README.md CHANGED
@@ -231,8 +231,8 @@ Behavior:
231
231
  - `feature_id` is derived from file stem (strips `.spec` or `-spec` suffixes when present).
232
232
  - each ingested feature runs `feature.init`, then state source metadata is patched with source path/hash.
233
233
  - Provider selection precedence:
234
- 1. CLI flags (`--agent-provider`, `--agent-model`, `--provider-config-env`)
235
- 2. env vars (`AOP_AGENT_PROVIDER`, `AOP_AGENT_MODEL`, `AOP_PROVIDER_CONFIG_ENV`)
234
+ 1. CLI flags (`--agent-provider`, `--agent-model`, `--agent-config`, `--provider-config-env`)
235
+ 2. env vars (`AOP_AGENT_PROVIDER`, `AOP_AGENT_MODEL`, `AOP_AGENT_CONFIG`/`AOP_AGENT_CONFIG_JSON`, `AOP_PROVIDER_CONFIG_ENV`)
236
236
  3. `agentic/orchestrator/agents.yaml` runtime defaults
237
237
  - Runtime start:
238
238
  - starts `SupervisorRuntime` with `max_active_features=5`, `max_parallel_gate_runs=3`.
@@ -355,8 +355,9 @@ Supported options:
355
355
  |-------------------------------------------------------|-----------------------------------------------------------------------------------|
356
356
  | `-fi <path>` | Run exactly one spec file |
357
357
  | `-fl <path>` | Resolve all `**/*.md` files recursively in a folder (deterministic lexical order) |
358
- | `--agent-provider <codex\\|claude\\|gemini\\|custom>` | Provider selection |
358
+ | `--agent-provider <codex\\|claude\\|gemini\\|custom\\|kiro-cli\\|copilot>` | Provider selection |
359
359
  | `--agent-model <model-id>` | Model selection |
360
+ | `--agent-config <json-object>` | Additional provider-specific agent config (for example command/args payload) |
360
361
  | `--provider-config-env <ENV_VAR>` | Provider auth/config environment variable name |
361
362
  | `--transport <mcp\\|inprocess>` | Tool transport selection (default `mcp`) |
362
363
  | `--takeover-stale-run` | Allow stale run-lease takeover during `run` |
@@ -386,7 +387,7 @@ Feature ID derivation for non-canonical inputs:
386
387
  Provider resolution precedence:
387
388
 
388
389
  1. CLI flags
389
- 2. env vars (`AOP_AGENT_PROVIDER`, `AOP_AGENT_MODEL`, `AOP_PROVIDER_CONFIG_ENV`)
390
+ 2. env vars (`AOP_AGENT_PROVIDER`, `AOP_AGENT_MODEL`, `AOP_AGENT_CONFIG`/`AOP_AGENT_CONFIG_JSON`, `AOP_PROVIDER_CONFIG_ENV`)
390
391
  3. `agentic/orchestrator/agents.yaml` runtime defaults
391
392
 
392
393
  Transport behavior:
@@ -430,6 +431,7 @@ Coverage parser:
430
431
 
431
432
  - role-specific system prompt paths
432
433
  - default provider/model/config-env fallback values
434
+ - optional `runtime.provider_configs.<provider>` objects for provider-specific payloads (for example `kiro-cli chat --agent dev`)
433
435
  - stack-specific examples: [`example-configurations/node/`](example-configurations/node) and [`example-configurations/java/`](example-configurations/java)
434
436
 
435
437
  ### Example configuration bundles
@@ -11,4 +11,14 @@ runtime:
11
11
  default_provider: custom
12
12
  default_model: local-default
13
13
  provider_config_env: AOP_PROVIDER_CONFIG_ENV
14
+ provider_configs:
15
+ kiro-cli:
16
+ command: kiro-cli
17
+ args:
18
+ - chat
19
+ - --agent
20
+ - dev
21
+ copilot:
22
+ command: copilot
23
+ args: []
14
24
  role_provider_overrides: {}
@@ -25,10 +25,19 @@
25
25
  "properties": {
26
26
  "default_provider": {
27
27
  "type": "string",
28
- "enum": ["codex", "claude", "gemini", "custom"]
28
+ "enum": ["codex", "claude", "gemini", "custom", "kiro-cli", "copilot"]
29
29
  },
30
30
  "default_model": { "type": "string" },
31
+ "default_agent_config": {
32
+ "type": "object"
33
+ },
31
34
  "provider_config_env": { "type": "string" },
35
+ "provider_configs": {
36
+ "type": "object",
37
+ "additionalProperties": {
38
+ "type": "object"
39
+ }
40
+ },
32
41
  "role_provider_overrides": {
33
42
  "type": "object"
34
43
  }
@@ -37,7 +37,7 @@ assertContains(dockerfile, /apt-get install[^]*\bgit\b/m, 'docker image must inc
37
37
  assertContains(dockerfile, /ENV\s+AOP_REPO_ROOT=\/repo/m, 'docker image must declare /repo root');
38
38
  assertContains(
39
39
  dockerfile,
40
- /ENTRYPOINT\s+\["\/bin\/sh",\s*"\/app\/docker\/mcp\.entrypoint\.sh"\]/m,
40
+ /ENTRYPOINT\s+\["\/bin\/sh",\s*"\/app\/docker\/mcp\.entrypoint\.sh"]/m,
41
41
  'docker entrypoint must enforce runtime preflight checks'
42
42
  );
43
43
 
@@ -45,7 +45,7 @@ assertContains(compose, /aop-mcp:/m, 'compose must declare aop-mcp service');
45
45
  assertContains(compose, /- \.\.\/:\/repo/m, 'compose must bind-mount repository to /repo');
46
46
  assertContains(compose, /working_dir:\s*\/repo/m, 'compose service must execute from /repo');
47
47
 
48
- assertContains(entrypoint, /if \[ ! -d "\/repo" \]/m, 'entrypoint must enforce /repo mount check');
48
+ assertContains(entrypoint, /if \[ ! -d "\/repo" ]/m, 'entrypoint must enforce /repo mount check');
49
49
  assertContains(entrypoint, /for tool in node npm npx git;/m, 'entrypoint must verify required toolchains');
50
50
 
51
51
  if (!runSmoke) {
@@ -293,7 +293,7 @@ export class FeatureDeletionService {
293
293
  const indexUpdate = await this.port.withIndexLock(async () => {
294
294
  const index = await this.port.readIndex();
295
295
  let changed = false;
296
- let blockedQueueRemoved = 0;
296
+ let blockedQueueRemoved: number;
297
297
  let runtimeSessionRemoved = false;
298
298
 
299
299
  const active = asStringArray(index.active);
@@ -79,6 +79,11 @@ export class CliArgumentParser {
79
79
  index += 1;
80
80
  continue;
81
81
  }
82
+ if (token === '--agent-config') {
83
+ options.agent_config = next;
84
+ index += 1;
85
+ continue;
86
+ }
82
87
  if (token === '--provider-config-env') {
83
88
  options.provider_config_env = next;
84
89
  index += 1;
@@ -189,7 +189,6 @@ export class ResumeCommandHandler {
189
189
  sources: [...(sourcesByFeature.get(featureId) ?? new Set<string>())].sort((a, b) => a.localeCompare(b))
190
190
  });
191
191
  } catch (_error) {
192
- continue;
193
192
  }
194
193
  }
195
194
 
@@ -9,6 +9,7 @@ export interface CliOptions {
9
9
  remove_branch?: string;
10
10
  agent_provider?: string;
11
11
  agent_model?: string;
12
+ agent_config?: string;
12
13
  provider_config_env?: string;
13
14
  transport?: string;
14
15
  takeover_stale_run?: boolean;
@@ -41,6 +41,8 @@ export interface AgentsRuntimeConfig {
41
41
  default_provider?: string;
42
42
  default_model?: string;
43
43
  provider_config_env?: string;
44
+ default_agent_config?: Record<string, unknown>;
45
+ provider_configs?: Record<string, Record<string, unknown>>;
44
46
  }
45
47
 
46
48
  export interface AgentsConfigSnapshot {
@@ -376,12 +378,12 @@ export class AopKernel {
376
378
  return fail(ERROR_CODES.INTERNAL_ERROR, 'Unknown error');
377
379
  }
378
380
 
379
- if (typeof error === 'object' && error !== null && 'normalizedResponse' in error) {
381
+ if (typeof error === 'object' && 'normalizedResponse' in error) {
380
382
  return (error as { normalizedResponse: ToolResponse }).normalizedResponse;
381
383
  }
382
384
 
383
385
  const message =
384
- typeof error === 'object' && error !== null && 'message' in error
386
+ typeof error === 'object' && true && 'message' in error
385
387
  ? (error as { message?: unknown }).message
386
388
  : undefined;
387
389
  const text = String(message ?? error);
@@ -7,10 +7,11 @@ export interface AppError extends Error {
7
7
  }
8
8
 
9
9
  export interface ProviderSelection {
10
- provider: 'codex' | 'claude' | 'gemini' | 'custom';
10
+ provider: 'codex' | 'claude' | 'gemini' | 'custom' | 'kiro-cli' | 'copilot';
11
11
  model: string;
12
12
  provider_config_env: string | null;
13
13
  provider_config_ref: string | null;
14
+ agent_config?: Record<string, unknown> | null;
14
15
  }
15
16
 
16
17
  interface ResolveSelectionInput {
@@ -21,11 +22,78 @@ interface ResolveSelectionInput {
21
22
  default_provider?: string;
22
23
  default_model?: string;
23
24
  provider_config_env?: string;
25
+ default_agent_config?: unknown;
26
+ provider_configs?: Record<string, unknown>;
24
27
  };
25
28
  };
26
29
  }
27
30
 
28
- export const SUPPORTED_PROVIDERS = new Set<ProviderSelection['provider']>(['codex', 'claude', 'gemini', 'custom']);
31
+ type ResolveSelectionRuntimeConfig = NonNullable<ResolveSelectionInput['agentsConfig']>['runtime'];
32
+
33
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
34
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
35
+ }
36
+
37
+ function invalidAgentConfigError(details: Record<string, unknown>): AppError {
38
+ const error = new Error(ERROR_CODES.INVALID_CLI_ARGS) as AppError;
39
+ error.code = ERROR_CODES.INVALID_CLI_ARGS;
40
+ error.details = details;
41
+ return error;
42
+ }
43
+
44
+ function parseAgentConfigJson(raw: string, source: 'cli' | 'env'): Record<string, unknown> {
45
+ let parsed: unknown;
46
+ try {
47
+ parsed = JSON.parse(raw);
48
+ } catch (error) {
49
+ throw invalidAgentConfigError({
50
+ reason: 'Invalid agent config JSON',
51
+ source,
52
+ value: raw,
53
+ parse_error: error instanceof Error ? error.message : String(error)
54
+ });
55
+ }
56
+
57
+ if (!isPlainObject(parsed)) {
58
+ throw invalidAgentConfigError({
59
+ reason: 'Agent config JSON must be an object',
60
+ source,
61
+ value: raw
62
+ });
63
+ }
64
+
65
+ return parsed;
66
+ }
67
+
68
+ function resolveConfiguredAgentConfig(
69
+ provider: string,
70
+ runtime: ResolveSelectionRuntimeConfig
71
+ ): Record<string, unknown> | null {
72
+ if (!runtime) {
73
+ return null;
74
+ }
75
+
76
+ const providerSpecific = runtime.provider_configs?.[provider];
77
+ if (isPlainObject(providerSpecific)) {
78
+ return providerSpecific;
79
+ }
80
+
81
+ if (isPlainObject(runtime.default_agent_config)) {
82
+ return runtime.default_agent_config;
83
+ }
84
+
85
+ return null;
86
+ }
87
+
88
+ export const SUPPORTED_PROVIDERS = new Set<ProviderSelection['provider']>([
89
+ 'codex',
90
+ 'claude',
91
+ 'gemini',
92
+ 'custom',
93
+ 'kiro-cli',
94
+ 'copilot'
95
+ ]);
96
+ export const AUTH_REQUIRED_PROVIDERS = new Set<ProviderSelection['provider']>(['codex', 'claude', 'gemini']);
29
97
  export type ProviderSelectionResolver = (input: ResolveSelectionInput) => ProviderSelection;
30
98
 
31
99
  export const resolveProviderSelection: ProviderSelectionResolver = ({ cli, env, agentsConfig }) => {
@@ -60,7 +128,10 @@ export const resolveProviderSelection: ProviderSelectionResolver = ({ cli, env,
60
128
  throw error;
61
129
  }
62
130
 
63
- if (provider !== 'custom' && (!providerConfigEnv || !env[providerConfigEnv])) {
131
+ if (
132
+ AUTH_REQUIRED_PROVIDERS.has(provider as ProviderSelection['provider']) &&
133
+ (!providerConfigEnv || !env[providerConfigEnv])
134
+ ) {
64
135
  const error = new Error(ERROR_CODES.PROVIDER_AUTH_MISSING) as AppError;
65
136
  error.code = ERROR_CODES.PROVIDER_AUTH_MISSING;
66
137
  error.details = {
@@ -70,11 +141,21 @@ export const resolveProviderSelection: ProviderSelectionResolver = ({ cli, env,
70
141
  throw error;
71
142
  }
72
143
 
144
+ const agentConfig =
145
+ typeof cli.agent_config === 'string' && cli.agent_config.length > 0
146
+ ? parseAgentConfigJson(cli.agent_config, 'cli')
147
+ : typeof env.AOP_AGENT_CONFIG === 'string' && env.AOP_AGENT_CONFIG.length > 0
148
+ ? parseAgentConfigJson(env.AOP_AGENT_CONFIG, 'env')
149
+ : typeof env.AOP_AGENT_CONFIG_JSON === 'string' && env.AOP_AGENT_CONFIG_JSON.length > 0
150
+ ? parseAgentConfigJson(env.AOP_AGENT_CONFIG_JSON, 'env')
151
+ : resolveConfiguredAgentConfig(provider, agentsConfig?.runtime);
152
+
73
153
  return {
74
154
  provider: provider as ProviderSelection['provider'],
75
155
  model: model ?? `${provider}-default`,
76
156
  provider_config_env: providerConfigEnv,
77
- provider_config_ref: providerConfigEnv ? env[providerConfigEnv] ?? null : null
157
+ provider_config_ref: providerConfigEnv ? env[providerConfigEnv] ?? null : null,
158
+ agent_config: agentConfig
78
159
  };
79
160
  };
80
161
 
@@ -18,6 +18,8 @@ describe('cli helper modules', () => {
18
18
  'run',
19
19
  '--agent-model',
20
20
  'gpt-5',
21
+ '--agent-config',
22
+ '{"command":"kiro-cli","args":["chat","--agent","dev"]}',
21
23
  '--provider-config-env',
22
24
  'AOP_PROVIDER_CFG',
23
25
  '--transport',
@@ -27,6 +29,7 @@ describe('cli helper modules', () => {
27
29
  expect(parsed).toMatchObject({
28
30
  command: 'run',
29
31
  agent_model: 'gpt-5',
32
+ agent_config: '{"command":"kiro-cli","args":["chat","--agent","dev"]}',
30
33
  provider_config_env: 'AOP_PROVIDER_CFG',
31
34
  transport: 'mcp'
32
35
  });
@@ -87,6 +87,84 @@ describe('provider selection', () => {
87
87
  expect(selection.provider).toBe('custom');
88
88
  expect(selection.provider_config_ref).toBeNull();
89
89
  });
90
+
91
+ it('GIVEN_kiro_cli_provider_without_credentials_WHEN_resolving_THEN_allows_null_config_ref', () => {
92
+ const selection = resolveProviderSelection({
93
+ cli: {
94
+ agent_provider: 'kiro-cli'
95
+ },
96
+ env: {},
97
+ agentsConfig: {}
98
+ });
99
+
100
+ expect(selection.provider).toBe('kiro-cli');
101
+ expect(selection.provider_config_ref).toBeNull();
102
+ });
103
+
104
+ it('GIVEN_provider_configured_agent_config_WHEN_resolving_THEN_returns_provider_specific_config', () => {
105
+ const selection = resolveProviderSelection({
106
+ cli: {
107
+ agent_provider: 'kiro-cli'
108
+ },
109
+ env: {},
110
+ agentsConfig: {
111
+ runtime: {
112
+ provider_configs: {
113
+ 'kiro-cli': {
114
+ command: 'kiro-cli',
115
+ args: ['chat', '--agent', 'dev']
116
+ }
117
+ }
118
+ }
119
+ }
120
+ });
121
+
122
+ expect(selection.agent_config).toEqual({
123
+ command: 'kiro-cli',
124
+ args: ['chat', '--agent', 'dev']
125
+ });
126
+ });
127
+
128
+ it('GIVEN_cli_agent_config_WHEN_resolving_THEN_cli_agent_config_overrides_runtime_defaults', () => {
129
+ const selection = resolveProviderSelection({
130
+ cli: {
131
+ agent_provider: 'copilot',
132
+ agent_config: JSON.stringify({
133
+ command: 'copilot',
134
+ args: ['chat', '--agent', 'review']
135
+ })
136
+ },
137
+ env: {},
138
+ agentsConfig: {
139
+ runtime: {
140
+ provider_configs: {
141
+ copilot: {
142
+ command: 'copilot',
143
+ args: ['chat']
144
+ }
145
+ }
146
+ }
147
+ }
148
+ });
149
+
150
+ expect(selection.agent_config).toEqual({
151
+ command: 'copilot',
152
+ args: ['chat', '--agent', 'review']
153
+ });
154
+ });
155
+
156
+ it('GIVEN_invalid_cli_agent_config_json_WHEN_resolving_THEN_throws_invalid_cli_args', () => {
157
+ expect(() =>
158
+ resolveProviderSelection({
159
+ cli: {
160
+ agent_provider: 'kiro-cli',
161
+ agent_config: '{not-json'
162
+ },
163
+ env: {},
164
+ agentsConfig: {}
165
+ })
166
+ ).toThrow(ERROR_CODES.INVALID_CLI_ARGS);
167
+ });
90
168
  });
91
169
 
92
170
  describe('NullWorkerProvider', () => {
@@ -24,3 +24,5 @@ Important:
24
24
  - For Java projects, use the Java `gates.yaml` Maven commands (`./mvnw ...`) and `jacoco_xml` parser.
25
25
  - `policy.yaml -> supervisor.max_iterations_per_phase` controls planner/builder/qa loop reconciliation iterations (default `6`).
26
26
  - `policy.yaml -> rbac.orchestrator` includes `feature.delete` for the delete command path.
27
+ - `agents.yaml -> runtime.default_provider` supports `kiro-cli` and `copilot` in addition to existing providers.
28
+ - `agents.yaml -> runtime.provider_configs.<provider>` can hold provider-specific command payloads (for example `command: kiro-cli`, `args: [chat, --agent, dev]`).
@@ -11,4 +11,14 @@ runtime:
11
11
  default_provider: custom
12
12
  default_model: java-default
13
13
  provider_config_env: JAVA_PROVIDER_CONFIG_ENV
14
+ provider_configs:
15
+ kiro-cli:
16
+ command: kiro-cli
17
+ args:
18
+ - chat
19
+ - --agent
20
+ - dev
21
+ copilot:
22
+ command: copilot
23
+ args: []
14
24
  role_provider_overrides: {}
@@ -11,4 +11,14 @@ runtime:
11
11
  default_provider: custom
12
12
  default_model: node-default
13
13
  provider_config_env: NODE_PROVIDER_CONFIG_ENV
14
+ provider_configs:
15
+ kiro-cli:
16
+ command: kiro-cli
17
+ args:
18
+ - chat
19
+ - --agent
20
+ - dev
21
+ copilot:
22
+ command: copilot
23
+ args: []
14
24
  role_provider_overrides: {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-orchestrator",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "MCP-first, platform-agnostic multi-agent orchestrator control plane",