@kognai/orchestrator-core 0.2.0 → 0.2.1

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/lib/acp.js CHANGED
@@ -66,11 +66,25 @@ const REGISTRY = [
66
66
  max_model_tier: 'power',
67
67
  },
68
68
  {
69
+ // TICKET-346 Finding 8: the supervisor reviews code on the cloud tier (T2.5/
70
+ // haiku) but lacked llm_call_cloud, so every review tripped the ClawRouter
71
+ // spend-gate shadow-downgrade ("agent supervisor lacks llm_call_cloud — T2.5
72
+ // WOULD be downgraded"), slowing/degrading review quality. Supervisors are
73
+ // sovereign — their review tier must not be role-gated. Grant cloud routing.
69
74
  agent_id: 'supervisor', display_name: 'Supervisor', tier: 'T3',
70
- capabilities: ['read_files', 'search_code', 'git_read', 'llm_call_local', 'db_query'],
75
+ capabilities: ['read_files', 'search_code', 'git_read', 'llm_call_local', 'llm_call_cloud', 'db_query'],
71
76
  denied: ['write_files', 'shell_exec', 'deploy', 'git_push'],
72
77
  scope: 'Sprint review, quality validation. Read-only analysis.',
73
- max_model_tier: 'power',
78
+ max_model_tier: 'cloud',
79
+ },
80
+ {
81
+ // Second independent reviewer (haiku). Registered so it is GOVERNED by the
82
+ // spend-gate rather than silently passing through as an unknown agent_id.
83
+ agent_id: 'supervisor-2', display_name: 'Supervisor (2nd opinion)', tier: 'T3',
84
+ capabilities: ['read_files', 'search_code', 'git_read', 'llm_call_local', 'llm_call_cloud', 'db_query'],
85
+ denied: ['write_files', 'shell_exec', 'deploy', 'git_push'],
86
+ scope: 'Independent second-opinion review (haiku). Read-only analysis.',
87
+ max_model_tier: 'cloud',
74
88
  },
75
89
  {
76
90
  agent_id: 'devops', display_name: 'DevOps', tier: 'T4',
@@ -55,7 +55,7 @@ async function callAnthropic(opts) {
55
55
  throw new Error('ANTHROPIC_API_KEY not set');
56
56
  const body = JSON.stringify({
57
57
  model: opts.model,
58
- max_tokens: opts.max_tokens ?? 800,
58
+ max_tokens: opts.max_tokens ?? 4096,
59
59
  temperature: opts.temperature ?? 0.4,
60
60
  system: opts.system,
61
61
  messages: [{ role: 'user', content: opts.user }],
@@ -149,6 +149,33 @@ async function requestCTOApproval(proposal, projectRoot, product = 'kognai') {
149
149
  timestamp,
150
150
  };
151
151
  }
152
+ // TICKET-346: CEO-approved autonomous proposals are sanctioned work — the CEO
153
+ // approval IS the plan authorization (exactly as 'queue-prescribed' means "the
154
+ // queue IS the plan"). The dispatcher (dispatch-approved-proposals.ts) only
155
+ // authors these from reports/cto/approved-proposals.json AFTER CEO approval,
156
+ // so the plan-alignment LLM must not reject them for NOT_IN_PLAN. Without this
157
+ // the autonomous loop fought its own governance: dispatcher authored → CTO gate
158
+ // rejected → $0 output (the 2026-06-12 diagnostic). Capability + Police checks
159
+ // belong here but the established sanctioned-source pattern (human, queue-
160
+ // prescribed) bypasses them too; the CEO approval is the upstream safety gate.
161
+ if (proposal.source === 'cto-autonomous') {
162
+ logCTODecision({
163
+ approved: true,
164
+ sprint_id: proposal.sprint_id,
165
+ reason: 'CEO-approved autonomous proposal — approval is the plan authorization (TICKET-346).',
166
+ plan_reference: 'CEO_APPROVED_AUTONOMOUS',
167
+ cto_confidence: 100,
168
+ timestamp,
169
+ }, projectRoot, product);
170
+ return {
171
+ approved: true,
172
+ sprint_id: proposal.sprint_id,
173
+ reason: 'CEO-approved autonomous proposal — approval is the plan authorization (TICKET-346).',
174
+ plan_reference: 'CEO_APPROVED_AUTONOMOUS',
175
+ cto_confidence: 100,
176
+ timestamp,
177
+ };
178
+ }
152
179
  // Sprint 650: ACP pre-check — reject if agents lack required capabilities
153
180
  if (proposal.agent_capabilities && proposal.agent_capabilities.length > 0) {
154
181
  const violations = [];
@@ -11,7 +11,7 @@ export interface SprintProposal {
11
11
  description: string;
12
12
  tasks: string[];
13
13
  estimated_complexity: string;
14
- source: 'autonomous_loop' | 'human' | 'cto_backlog' | 'queue-prescribed' | 'auto-queue-empty' | 'queue-empty-autonomous';
14
+ source: 'autonomous_loop' | 'human' | 'cto_backlog' | 'queue-prescribed' | 'auto-queue-empty' | 'queue-empty-autonomous' | 'cto-autonomous';
15
15
  /** Sprint TICKET-005-RULE2: research | implementation phase gate */
16
16
  phase?: 'research' | 'implementation';
17
17
  /** ID of the research sprint that must be done before this implementation sprint can run */
@@ -743,7 +743,8 @@ ${originalContent}
743
743
  task_type: 'json_repair', tier_class: 'text', complexity: 'nano',
744
744
  context_tokens: Math.ceil(repairPrompt.length / 4), constitutional_flag: false,
745
745
  agent_id: 'json-repair',
746
- payload: { prompt: repairPrompt, max_tokens: 2048 },
746
+ // TICKET-346 Finding 6: repair returns the WHOLE file; cap must hold it.
747
+ payload: { prompt: repairPrompt, max_tokens: parseInt(process.env.KOGNAI_DEBUG_REPAIR_MAX_TOKENS ?? process.env.KOGNAI_MAX_OUTPUT_TOKENS ?? '8192', 10) },
747
748
  });
748
749
  const fixed = result.content.trim();
749
750
  try {
@@ -671,6 +671,13 @@ async function typecheckChangedFiles(filePaths) {
671
671
  }
672
672
  return { pass: true, errorCount: 0, firstError: `${projects.size} project(s) typechecked clean` };
673
673
  }
674
+ // TICKET-346 Finding 6 (TICKET-336): the repair OUTPUT cap must be decoupled
675
+ // from issue severity. tieredDebug returns the WHOLE fixed file, so a "minor"
676
+ // fix to a 400-line file still needs room to emit all 400 lines. The old caps
677
+ // (4096/2048/1024) truncated full-file repairs → [TRUNCATION] rejection → repair
678
+ // exhausted (this killed scorer.ts in sprint-1665). Severity still selects the
679
+ // MODEL tier (exec vs power); only the output ceiling is now uniform & generous.
680
+ const DEBUG_REPAIR_MAX_TOKENS = parseInt(process.env.KOGNAI_DEBUG_REPAIR_MAX_TOKENS ?? process.env.KOGNAI_MAX_OUTPUT_TOKENS ?? '8192', 10);
674
681
  // B.11: Tiered debugger — routes debug effort by issue severity via ClawRouter v2.0
675
682
  async function tieredDebug(task, review, _systemPrompt) {
676
683
  const issueText = (review.issues || []).map(i => `[${i.severity}] ${i.file}: ${i.description}`).join('\n');
@@ -683,7 +690,7 @@ async function tieredDebug(task, review, _systemPrompt) {
683
690
  task_type: 'debug_architectural', tier_class: 'text', complexity: 'exec',
684
691
  context_tokens: Math.ceil((issueText.length + 800) / 4), constitutional_flag: false,
685
692
  agent_id: 'tiered-debugger',
686
- payload: { prompt: `Fix this code. Issues:\n${issueText}\n\nTask: ${task.context.substring(0, 800)}`, max_tokens: 4096 },
693
+ payload: { prompt: `Fix this code. Issues:\n${issueText}\n\nTask: ${task.context.substring(0, 800)}`, max_tokens: DEBUG_REPAIR_MAX_TOKENS },
687
694
  });
688
695
  return result.content || null;
689
696
  }
@@ -693,7 +700,7 @@ async function tieredDebug(task, review, _systemPrompt) {
693
700
  task_type: 'debug_systemic', tier_class: 'text', complexity: 'power',
694
701
  context_tokens: Math.ceil((issueText.length + 600) / 4), constitutional_flag: false,
695
702
  agent_id: 'tiered-debugger',
696
- payload: { prompt: `Fix these code issues:\n${issueText}\n\nTask: ${task.context.substring(0, 600)}`, max_tokens: 2048 },
703
+ payload: { prompt: `Fix these code issues:\n${issueText}\n\nTask: ${task.context.substring(0, 600)}`, max_tokens: DEBUG_REPAIR_MAX_TOKENS },
697
704
  });
698
705
  return result.content;
699
706
  }
@@ -703,7 +710,7 @@ async function tieredDebug(task, review, _systemPrompt) {
703
710
  task_type: 'debug_minor', tier_class: 'text', complexity: 'power',
704
711
  context_tokens: Math.ceil((issueText.length + 500) / 4), constitutional_flag: false,
705
712
  agent_id: 'tiered-debugger',
706
- payload: { prompt: `Fix these minor code issues:\n${issueText}\n\nTask: ${task.context.substring(0, 500)}`, max_tokens: 1024 },
713
+ payload: { prompt: `Fix these minor code issues:\n${issueText}\n\nTask: ${task.context.substring(0, 500)}`, max_tokens: DEBUG_REPAIR_MAX_TOKENS },
707
714
  });
708
715
  return result.content;
709
716
  }
@@ -21,7 +21,7 @@
21
21
  */
22
22
  export interface SprintRunnerOpts {
23
23
  orchestratorScript: string;
24
- postSprintHook?: () => void;
24
+ postSprintHook?: () => void | Promise<void>;
25
25
  }
26
26
  declare function runSprintCycle(opts: SprintRunnerOpts): Promise<void>;
27
27
  export { runSprintCycle };
@@ -1033,7 +1033,7 @@ async function runSprintCycle(opts) {
1033
1033
  // TICKET-201: post-sprint hook (e.g. dispatch-approved-proposals).
1034
1034
  // Supplied by the product entry so core stays product-agnostic.
1035
1035
  try {
1036
- opts.postSprintHook?.();
1036
+ await opts.postSprintHook?.();
1037
1037
  }
1038
1038
  catch (e) {
1039
1039
  log(`WARN: post-sprint hook failed (non-fatal): ${(e?.message || String(e)).substring(0, 200)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kognai/orchestrator-core",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Kognai sovereign orchestrator — core engine (template-agnostic). Shared by all products (Kognai/coding, Voxight/market-intel, Invoica/fin-compliance); each supplies only its template. Replaces per-repo forks of orchestrate-agents-v2 / sprint-runner / lib.",
5
5
  "license": "MIT",
6
6
  "author": "SkinGem",