aiwcli 0.13.8 → 0.15.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/README.md +11 -1
- package/dist/commands/launch.d.ts +8 -0
- package/dist/commands/launch.js +96 -5
- package/dist/templates/_shared/.claude/skills/codex/SKILL.md +42 -0
- package/dist/templates/_shared/.claude/skills/codex/prompt.md +30 -0
- package/dist/templates/_shared/lib-ts/agent-exec/backends/headless.ts +33 -0
- package/dist/templates/_shared/lib-ts/agent-exec/backends/index.ts +6 -0
- package/dist/templates/_shared/lib-ts/agent-exec/backends/tmux.ts +145 -0
- package/dist/templates/_shared/lib-ts/agent-exec/base-agent.ts +229 -0
- package/dist/templates/_shared/lib-ts/agent-exec/execution-backend.ts +50 -0
- package/dist/templates/_shared/lib-ts/agent-exec/index.ts +6 -0
- package/dist/templates/_shared/lib-ts/agent-exec/structured-output.ts +166 -0
- package/dist/templates/_shared/lib-ts/base/cli-args.ts +287 -0
- package/dist/templates/_shared/lib-ts/base/inference.ts +53 -47
- package/dist/templates/_shared/lib-ts/base/models.ts +16 -0
- package/dist/templates/_shared/lib-ts/base/preflight.ts +98 -0
- package/dist/templates/_shared/lib-ts/base/state-io.ts +1 -1
- package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +4 -3
- package/dist/templates/_shared/lib-ts/base/tmux-driver.ts +381 -0
- package/dist/templates/_shared/lib-ts/base/utils.ts +8 -0
- package/dist/templates/_shared/lib-ts/context/context-formatter.ts +35 -11
- package/dist/templates/_shared/lib-ts/context/context-store.ts +3 -0
- package/dist/templates/_shared/lib-ts/types.ts +17 -0
- package/dist/templates/_shared/scripts/status_line.ts +93 -47
- package/dist/templates/_shared/skills/prompt-codex/CLAUDE.md +71 -0
- package/dist/templates/_shared/skills/prompt-codex/scripts/launch-codex.ts +387 -0
- package/dist/templates/_shared/skills/prompt-codex/scripts/watch-codex.ts +257 -0
- package/dist/templates/cc-native/.claude/settings.json +121 -1
- package/dist/templates/cc-native/_cc-native/CLAUDE.md +73 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/CLAUDE.md +70 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +9 -133
- package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +120 -43
- package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +1 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +66 -12
- package/dist/templates/cc-native/_cc-native/plan-review/lib/agent-selection.ts +5 -4
- package/dist/templates/cc-native/_cc-native/plan-review/lib/orchestrator.ts +4 -4
- package/dist/templates/cc-native/_cc-native/plan-review/lib/preflight.ts +14 -80
- package/dist/templates/cc-native/_cc-native/plan-review/lib/review-pipeline.ts +16 -13
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/agent.ts +19 -7
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/base/base-agent.ts +4 -215
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/index.ts +1 -1
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/claude-agent.ts +9 -39
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/codex-agent.ts +19 -22
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/gemini-agent.ts +2 -1
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/orchestrator-claude-agent.ts +65 -36
- package/oclif.manifest.json +21 -3
- package/package.json +1 -1
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
// Re-export shared types used by cc-native consumers
|
|
8
8
|
export type { ContextState, HookInput, HookOutput } from "../../_shared/lib-ts/types.js";
|
|
9
9
|
|
|
10
|
+
// Import AgentConfig for local use and re-export
|
|
11
|
+
import type { AgentConfig as _AgentConfig } from "../../_shared/lib-ts/types.js";
|
|
12
|
+
export type AgentConfig = _AgentConfig;
|
|
13
|
+
|
|
10
14
|
// ---------------------------------------------------------------------------
|
|
11
15
|
// Verdict & Decision Types
|
|
12
16
|
// ---------------------------------------------------------------------------
|
|
@@ -118,22 +122,13 @@ export interface ReviewDecisionResult {
|
|
|
118
122
|
// Agent & Orchestrator Configuration
|
|
119
123
|
// ---------------------------------------------------------------------------
|
|
120
124
|
|
|
121
|
-
|
|
122
|
-
export interface AgentConfig {
|
|
123
|
-
name: string;
|
|
124
|
-
model: string;
|
|
125
|
-
provider: string; // e.g. "claude" | "codex" — assigned at runtime by assignModelsToAgents()
|
|
126
|
-
focus: string;
|
|
127
|
-
categories: string[];
|
|
128
|
-
description: string;
|
|
129
|
-
system_prompt: string; // Markdown body content for --system-prompt
|
|
130
|
-
reasoningEffort?: string; // e.g. "low", "medium", "high" — passed to codex -c model_reasoning_effort
|
|
131
|
-
}
|
|
125
|
+
// AgentConfig re-exported from _shared/lib-ts/types.ts above
|
|
132
126
|
|
|
133
127
|
/** Configuration for the plan orchestrator */
|
|
134
128
|
export interface OrchestratorConfig {
|
|
135
129
|
enabled: boolean;
|
|
136
130
|
model: string;
|
|
131
|
+
provider?: string;
|
|
137
132
|
timeout: number;
|
|
138
133
|
}
|
|
139
134
|
|
|
@@ -141,7 +136,6 @@ export interface OrchestratorConfig {
|
|
|
141
136
|
export interface ProviderConfig {
|
|
142
137
|
enabled: boolean;
|
|
143
138
|
models: string[];
|
|
144
|
-
reasoningEffort?: string; // e.g. "low", "medium", "high" — codex model_reasoning_effort
|
|
145
139
|
}
|
|
146
140
|
|
|
147
141
|
/** Model provider pool configuration */
|
|
@@ -149,6 +143,66 @@ export interface ModelsConfig {
|
|
|
149
143
|
providers: Record<string, ProviderConfig>;
|
|
150
144
|
}
|
|
151
145
|
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
147
|
+
// Settings Interfaces (typed output of loadSettings())
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
|
|
150
|
+
/** Agent selection count range for a single complexity tier */
|
|
151
|
+
export interface AgentSelectionRange {
|
|
152
|
+
min: number;
|
|
153
|
+
max: number;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Agent selection configuration (per-tier ranges + fallback) */
|
|
157
|
+
export interface AgentSelectionConfig {
|
|
158
|
+
simple?: AgentSelectionRange;
|
|
159
|
+
medium?: AgentSelectionRange;
|
|
160
|
+
high?: AgentSelectionRange;
|
|
161
|
+
fallbackCount?: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Preflight health-check configuration */
|
|
165
|
+
export interface PreflightSettings {
|
|
166
|
+
enabled?: boolean;
|
|
167
|
+
timeoutMs?: number;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Plan review section of merged settings (the "planReview" key) */
|
|
171
|
+
export interface PlanReviewSettings {
|
|
172
|
+
enabled?: boolean;
|
|
173
|
+
reviewers?: {
|
|
174
|
+
codex?: { enabled?: boolean; model?: string; timeout?: number };
|
|
175
|
+
gemini?: { enabled?: boolean; model?: string; timeout?: number };
|
|
176
|
+
};
|
|
177
|
+
display?: Partial<DisplaySettings>;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Agent review section of merged settings (the "agentReview" key) */
|
|
181
|
+
export interface AgentReviewSettings {
|
|
182
|
+
enabled?: boolean;
|
|
183
|
+
timeout?: number;
|
|
184
|
+
orchestrator?: OrchestratorConfig;
|
|
185
|
+
legacyMode?: boolean;
|
|
186
|
+
highIssueThreshold?: number;
|
|
187
|
+
maxIssuesPerAgent?: number;
|
|
188
|
+
mandatoryAgents?: string[] | Record<string, string[]>;
|
|
189
|
+
agentSelection?: AgentSelectionConfig;
|
|
190
|
+
agentDefaults?: { model?: string };
|
|
191
|
+
complexityCategories?: string[];
|
|
192
|
+
sanitization?: { maxSessionIdLength?: number; maxTitleLength?: number };
|
|
193
|
+
reviewIterations?: Record<string, number>;
|
|
194
|
+
display?: Partial<DisplaySettings>;
|
|
195
|
+
preflight?: PreflightSettings;
|
|
196
|
+
fallbackByComplexity?: Record<string, number>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Top-level settings object returned by loadSettings() */
|
|
200
|
+
export interface LoadedSettings {
|
|
201
|
+
planReview: PlanReviewSettings;
|
|
202
|
+
agentReview: AgentReviewSettings;
|
|
203
|
+
models: Record<string, unknown>;
|
|
204
|
+
}
|
|
205
|
+
|
|
152
206
|
// ---------------------------------------------------------------------------
|
|
153
207
|
// State Interfaces
|
|
154
208
|
// ---------------------------------------------------------------------------
|
|
@@ -7,6 +7,7 @@ import { logDebug, logInfo, logWarn } from "../../../_shared/lib-ts/base/logger.
|
|
|
7
7
|
import { findExecutable } from "../../../_shared/lib-ts/base/subprocess-utils.js";
|
|
8
8
|
import type {
|
|
9
9
|
AgentConfig,
|
|
10
|
+
AgentReviewSettings,
|
|
10
11
|
ModelsConfig,
|
|
11
12
|
OrchestratorResult,
|
|
12
13
|
AgentSelectionResult,
|
|
@@ -89,7 +90,7 @@ export function assignModelsToAgents(
|
|
|
89
90
|
}
|
|
90
91
|
return [name, config] as [string, typeof config];
|
|
91
92
|
})
|
|
92
|
-
.filter((entry): entry is [string, { enabled: boolean; models: string[]
|
|
93
|
+
.filter((entry): entry is [string, { enabled: boolean; models: string[] }] => entry !== null);
|
|
93
94
|
|
|
94
95
|
// Sort by provider priority (codex first)
|
|
95
96
|
enabledProviders.sort((a, b) => {
|
|
@@ -110,7 +111,7 @@ export function assignModelsToAgents(
|
|
|
110
111
|
return agents.map(agent => {
|
|
111
112
|
const modelIdx = Math.floor(Math.random() * providerConfig.models.length);
|
|
112
113
|
const model = providerConfig.models[modelIdx] ?? providerConfig.models[0] ?? agent.model;
|
|
113
|
-
return { ...agent, provider: providerName, model
|
|
114
|
+
return { ...agent, provider: providerName, model };
|
|
114
115
|
});
|
|
115
116
|
}
|
|
116
117
|
|
|
@@ -122,7 +123,7 @@ export interface AgentSelectionInput {
|
|
|
122
123
|
enabledAgents: AgentConfig[];
|
|
123
124
|
orchResult: OrchestratorResult | null;
|
|
124
125
|
mandatoryConfig: unknown;
|
|
125
|
-
agentSettings:
|
|
126
|
+
agentSettings: AgentReviewSettings;
|
|
126
127
|
legacyMode: boolean;
|
|
127
128
|
}
|
|
128
129
|
|
|
@@ -168,7 +169,7 @@ export function selectAgents(input: AgentSelectionInput): AgentSelectionResult {
|
|
|
168
169
|
}
|
|
169
170
|
|
|
170
171
|
// Enforce minimum agent count
|
|
171
|
-
const fallbackByComplexity = agentSettings.fallbackByComplexity ?? { simple: 0, medium: 2, high: 4 };
|
|
172
|
+
const fallbackByComplexity: Record<string, number> = agentSettings.fallbackByComplexity ?? { simple: 0, medium: 2, high: 4 };
|
|
172
173
|
const minAdditional = fallbackByComplexity[detectedComplexity] ?? 5;
|
|
173
174
|
if (orchSelected.length < minAdditional && nonMandatory.length > 0) {
|
|
174
175
|
const remaining = nonMandatory.filter(a => !orchSelected.includes(a));
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { OrchestratorClaudeAgent } from "./reviewers/providers/orchestrator-claude-agent.js";
|
|
8
8
|
import { logInfo, logWarn } from "../../../_shared/lib-ts/base/logger.js";
|
|
9
|
-
import type { AgentConfig, OrchestratorConfig, OrchestratorResult } from "../../lib-ts/types.js";
|
|
9
|
+
import type { AgentConfig, AgentReviewSettings, OrchestratorConfig, OrchestratorResult } from "../../lib-ts/types.js";
|
|
10
10
|
|
|
11
11
|
// Re-export for backward compatibility (moved to reviewers/schemas.ts)
|
|
12
12
|
export { buildOrchestratorSchema } from "./reviewers/schemas.js";
|
|
@@ -23,7 +23,7 @@ export async function runOrchestrator(
|
|
|
23
23
|
plan: string,
|
|
24
24
|
agentLibrary: AgentConfig[],
|
|
25
25
|
config: OrchestratorConfig,
|
|
26
|
-
settings:
|
|
26
|
+
settings: AgentReviewSettings,
|
|
27
27
|
mandatoryNames?: Set<string>,
|
|
28
28
|
): Promise<OrchestratorResult> {
|
|
29
29
|
logInfo("orchestrator", "Starting plan analysis...");
|
|
@@ -34,7 +34,7 @@ export async function runOrchestrator(
|
|
|
34
34
|
const orchestratorAgent: AgentConfig = {
|
|
35
35
|
name: "orchestrator",
|
|
36
36
|
model: config.model,
|
|
37
|
-
provider: "claude",
|
|
37
|
+
provider: config.provider ?? "claude",
|
|
38
38
|
focus: "plan analysis and agent selection",
|
|
39
39
|
categories: [],
|
|
40
40
|
description: "Plan orchestrator",
|
|
@@ -58,7 +58,7 @@ export async function runOrchestrator(
|
|
|
58
58
|
} catch (error) {
|
|
59
59
|
logWarn("orchestrator", `Unexpected error: ${error}`);
|
|
60
60
|
const nonMandatory = agentLibrary.filter((a) => !mandatory.has(a.name));
|
|
61
|
-
const fallbackCount =
|
|
61
|
+
const fallbackCount = settings.agentSelection?.fallbackCount ?? 2;
|
|
62
62
|
return {
|
|
63
63
|
complexity: "medium",
|
|
64
64
|
category: "code",
|
|
@@ -2,97 +2,29 @@
|
|
|
2
2
|
* Preflight health checks for plan review agents.
|
|
3
3
|
* Validates provider+model combos work before committing agents to them.
|
|
4
4
|
* Runs minimal "ping" requests in parallel per unique provider:model combo.
|
|
5
|
+
*
|
|
6
|
+
* Uses shared checkProviderModel() from _shared/lib-ts/base/preflight.ts.
|
|
7
|
+
* This module provides the batch orchestrator and provider registry specific
|
|
8
|
+
* to the plan review pipeline.
|
|
5
9
|
*/
|
|
6
10
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
11
|
+
import { preflightCommandConfig } from "../../../_shared/lib-ts/base/cli-args.js";
|
|
12
|
+
import { logInfo, logWarn } from "../../../_shared/lib-ts/base/logger.js";
|
|
13
|
+
import { checkProviderModel, type PreflightCommandConfig } from "../../../_shared/lib-ts/base/preflight.js";
|
|
9
14
|
import type { ModelsConfig, PreflightCheckResult, PreflightReport } from "../../lib-ts/types.js";
|
|
10
|
-
import { claudePreflightArgs, CLAUDE_PREFLIGHT_INPUT } from "./reviewers/providers/claude-agent.js";
|
|
11
|
-
import { codexPreflightArgs, CODEX_PREFLIGHT_INPUT } from "./reviewers/providers/codex-agent.js";
|
|
12
15
|
|
|
13
16
|
const HOOK = "preflight";
|
|
14
17
|
const DEFAULT_TIMEOUT_MS = 15000;
|
|
15
18
|
|
|
16
19
|
// ---------------------------------------------------------------------------
|
|
17
|
-
// Provider Registry
|
|
20
|
+
// Provider Registry (built from centralized cli-args)
|
|
18
21
|
// ---------------------------------------------------------------------------
|
|
19
22
|
|
|
20
|
-
interface PreflightCommandConfig {
|
|
21
|
-
cliName: string;
|
|
22
|
-
buildArgs: (model: string) => string[];
|
|
23
|
-
input: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
23
|
const PREFLIGHT_COMMANDS: Record<string, PreflightCommandConfig> = {
|
|
27
|
-
claude:
|
|
28
|
-
codex:
|
|
24
|
+
claude: preflightCommandConfig("claude"),
|
|
25
|
+
codex: preflightCommandConfig("codex"),
|
|
29
26
|
};
|
|
30
27
|
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
// Error Classification
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
|
|
35
|
-
function classifyError(stderr: string, exitCode: number | null, killed: boolean, signal: string | null): string {
|
|
36
|
-
if (killed || signal === "SIGTERM") return "Preflight timed out";
|
|
37
|
-
if (/model.*not found|not available/i.test(stderr)) return "Model not available for this account";
|
|
38
|
-
if (/rate limit|429/i.test(stderr)) return "Rate limited";
|
|
39
|
-
if (/auth|api key|401/i.test(stderr)) return "Authentication failed";
|
|
40
|
-
if (/quota|billing/i.test(stderr)) return "Quota/billing issue";
|
|
41
|
-
return `Exit code ${exitCode}`;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// ---------------------------------------------------------------------------
|
|
45
|
-
// Single Check
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
|
-
|
|
48
|
-
async function checkProviderModel(
|
|
49
|
-
provider: string,
|
|
50
|
-
model: string,
|
|
51
|
-
timeoutMs: number,
|
|
52
|
-
): Promise<PreflightCheckResult> {
|
|
53
|
-
const config = PREFLIGHT_COMMANDS[provider];
|
|
54
|
-
if (!config) {
|
|
55
|
-
return { provider, model, available: false, latencyMs: 0, error: `Unknown provider: ${provider}` };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const cliPath = findExecutable(config.cliName);
|
|
59
|
-
if (!cliPath) {
|
|
60
|
-
return { provider, model, available: false, latencyMs: 0, error: `CLI '${config.cliName}' not found on PATH` };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const start = Date.now();
|
|
64
|
-
try {
|
|
65
|
-
const env = getInternalSubprocessEnv();
|
|
66
|
-
const result = await execFileAsync(cliPath, config.buildArgs(model), {
|
|
67
|
-
input: config.input,
|
|
68
|
-
timeout: timeoutMs,
|
|
69
|
-
env: env as Record<string, string>,
|
|
70
|
-
maxBuffer: 1 * 1024 * 1024,
|
|
71
|
-
shell: process.platform === "win32",
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
const latencyMs = Date.now() - start;
|
|
75
|
-
|
|
76
|
-
if (result.killed || result.signal === "SIGTERM") {
|
|
77
|
-
return { provider, model, available: false, latencyMs, error: "Preflight timed out" };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (result.exitCode !== 0) {
|
|
81
|
-
const error = classifyError(result.stderr, result.exitCode, result.killed, result.signal);
|
|
82
|
-
logWarn(HOOK, `${provider}:${model} failed: ${error} (stderr: ${result.stderr.slice(-200)})`);
|
|
83
|
-
return { provider, model, available: false, latencyMs, error };
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
logDebug(HOOK, `${provider}:${model} passed (${latencyMs}ms)`);
|
|
87
|
-
return { provider, model, available: true, latencyMs };
|
|
88
|
-
} catch (err) {
|
|
89
|
-
const latencyMs = Date.now() - start;
|
|
90
|
-
const error = err instanceof Error ? err.message : String(err);
|
|
91
|
-
logWarn(HOOK, `${provider}:${model} exception: ${error}`);
|
|
92
|
-
return { provider, model, available: false, latencyMs, error };
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
28
|
// ---------------------------------------------------------------------------
|
|
97
29
|
// Run All Checks
|
|
98
30
|
// ---------------------------------------------------------------------------
|
|
@@ -130,9 +62,11 @@ export async function runPreflight(
|
|
|
130
62
|
|
|
131
63
|
logInfo(HOOK, `Checking ${checks.length} provider:model combo(s): ${checks.map(c => `${c.provider}:${c.model}`).join(", ")}`);
|
|
132
64
|
|
|
133
|
-
// Run all checks in parallel
|
|
65
|
+
// Run all checks in parallel (pass provider-specific config from registry)
|
|
134
66
|
const results = await Promise.all(
|
|
135
|
-
checks.map(({ provider, model }) =>
|
|
67
|
+
checks.map(({ provider, model }) =>
|
|
68
|
+
checkProviderModel(provider, model, PREFLIGHT_COMMANDS[provider]!, effectiveTimeout, HOOK),
|
|
69
|
+
),
|
|
136
70
|
);
|
|
137
71
|
|
|
138
72
|
// Build available map
|
|
@@ -43,7 +43,10 @@ import { loadSettings, loadModelsConfig, loadAgentLibrary, DEFAULT_ORCHESTRATOR
|
|
|
43
43
|
import { DEFAULT_REVIEW_ITERATIONS, loadIterationState, saveIterationState } from "../../lib-ts/state.js";
|
|
44
44
|
import type {
|
|
45
45
|
AgentConfig,
|
|
46
|
+
AgentReviewSettings,
|
|
47
|
+
LoadedSettings,
|
|
46
48
|
OrchestratorConfig,
|
|
49
|
+
PlanReviewSettings,
|
|
47
50
|
ReviewerResult,
|
|
48
51
|
CombinedReviewResult,
|
|
49
52
|
OrchestratorResult,
|
|
@@ -66,7 +69,7 @@ function getActiveContextForReview(sessionId: string, projectRoot: string): Cont
|
|
|
66
69
|
return ctx;
|
|
67
70
|
}
|
|
68
71
|
const allActive = getAllContexts("active", projectRoot);
|
|
69
|
-
const planning = allActive.filter(c => c.mode === "active" || c.mode === "
|
|
72
|
+
const planning = allActive.filter(c => c.mode === "active" || c.mode === "has_staged_work");
|
|
70
73
|
if (planning.length === 1) {
|
|
71
74
|
logInfo(HOOK, `Found single planning context: ${planning[0]!.id}`);
|
|
72
75
|
return planning[0]!;
|
|
@@ -89,9 +92,9 @@ export async function runReviewPipeline(input: PipelineInput): Promise<PipelineR
|
|
|
89
92
|
const { sessionId, base, aiwcliDir, transcriptPath, payload } = input;
|
|
90
93
|
|
|
91
94
|
// 1. Load settings
|
|
92
|
-
const settings = loadSettings(aiwcliDir);
|
|
93
|
-
const planSettings = settings.planReview
|
|
94
|
-
const agentSettings = settings.agentReview
|
|
95
|
+
const settings: LoadedSettings = loadSettings(aiwcliDir);
|
|
96
|
+
const planSettings: PlanReviewSettings = settings.planReview;
|
|
97
|
+
const agentSettings: AgentReviewSettings = settings.agentReview;
|
|
95
98
|
|
|
96
99
|
const planReviewEnabled = planSettings.enabled ?? true;
|
|
97
100
|
const agentReviewEnabled = agentSettings.enabled ?? true;
|
|
@@ -162,8 +165,8 @@ export async function runReviewPipeline(input: PipelineInput): Promise<PipelineR
|
|
|
162
165
|
// 5. Questions gate
|
|
163
166
|
if (!wasPlanQuestionsAgentAsked(sessionId, base)) {
|
|
164
167
|
logInfo(HOOK, "Questions gate: plan-questions agent has not run yet, running now");
|
|
165
|
-
const
|
|
166
|
-
const questionsResult = await runPlanQuestions(plan, aiwcliDir,
|
|
168
|
+
const questionsTimeout = agentSettings.timeout ?? 120;
|
|
169
|
+
const questionsResult = await runPlanQuestions(plan, aiwcliDir, questionsTimeout, undefined, sessionId);
|
|
167
170
|
|
|
168
171
|
markQuestionsAsked(sessionId, base, "agent");
|
|
169
172
|
|
|
@@ -227,12 +230,12 @@ export async function runReviewPipeline(input: PipelineInput): Promise<PipelineR
|
|
|
227
230
|
let detectedComplexity = "medium";
|
|
228
231
|
|
|
229
232
|
// Preflight: validate provider+model combos before committing agents or orchestrator
|
|
230
|
-
const preflightEnabled =
|
|
233
|
+
const preflightEnabled = agentSettings.preflight?.enabled ?? true;
|
|
231
234
|
let preflightAvailable: Map<string, Set<string>> | undefined;
|
|
232
235
|
|
|
233
236
|
if (preflightEnabled && agentReviewEnabled) {
|
|
234
237
|
logInfo(HOOK, "=== PREFLIGHT: Checking provider availability ===");
|
|
235
|
-
const preflightTimeoutMs =
|
|
238
|
+
const preflightTimeoutMs = agentSettings.preflight?.timeoutMs;
|
|
236
239
|
const modelsConfig = loadModelsConfig(settings);
|
|
237
240
|
const preflightReport = await runPreflight(modelsConfig, preflightTimeoutMs);
|
|
238
241
|
|
|
@@ -257,13 +260,14 @@ export async function runReviewPipeline(input: PipelineInput): Promise<PipelineR
|
|
|
257
260
|
const agentLibrary = agentReviewEnabled ? loadAgentLibrary(aiwcliDir, agentSettings) : [];
|
|
258
261
|
const originalAgentCount = agentLibrary.length;
|
|
259
262
|
const enabledAgents = agentLibrary.filter(a => !graduatedSet.has(a.name));
|
|
260
|
-
const timeout =
|
|
263
|
+
const timeout = agentSettings.timeout ?? 120;
|
|
261
264
|
const legacyMode = agentSettings.legacyMode === true;
|
|
262
265
|
|
|
263
266
|
const orchSettings = agentSettings.orchestrator ?? DEFAULT_ORCHESTRATOR;
|
|
264
267
|
const orchestratorConfig: OrchestratorConfig = {
|
|
265
268
|
enabled: (orchSettings.enabled ?? true) && agentReviewEnabled,
|
|
266
269
|
model: orchSettings.model ?? "haiku",
|
|
270
|
+
provider: orchSettings.provider,
|
|
267
271
|
timeout: orchSettings.timeout ?? 30,
|
|
268
272
|
};
|
|
269
273
|
|
|
@@ -278,7 +282,7 @@ export async function runReviewPipeline(input: PipelineInput): Promise<PipelineR
|
|
|
278
282
|
|
|
279
283
|
if (orchestratorConfig.enabled && enabledAgents.length > 0 && !legacyMode) {
|
|
280
284
|
// Guard orchestrator against preflight failures (always uses claude provider)
|
|
281
|
-
const orchProvider = "claude";
|
|
285
|
+
const orchProvider = orchestratorConfig.provider ?? "claude";
|
|
282
286
|
const orchModel = orchestratorConfig.model;
|
|
283
287
|
const orchPassed = !preflightAvailable ||
|
|
284
288
|
(preflightAvailable.has(orchProvider) && preflightAvailable.get(orchProvider)!.has(orchModel));
|
|
@@ -395,8 +399,7 @@ export async function runReviewPipeline(input: PipelineInput): Promise<PipelineR
|
|
|
395
399
|
}
|
|
396
400
|
|
|
397
401
|
// 10. Issue truncation + verdict override
|
|
398
|
-
const maxIssuesPerAgent =
|
|
399
|
-
? agentSettings.maxIssuesPerAgent : 3;
|
|
402
|
+
const maxIssuesPerAgent = agentSettings.maxIssuesPerAgent ?? 3;
|
|
400
403
|
truncateAgentIssues(agentResults, maxIssuesPerAgent);
|
|
401
404
|
|
|
402
405
|
const passEligible = computePassEligible(agentResults);
|
|
@@ -404,7 +407,7 @@ export async function runReviewPipeline(input: PipelineInput): Promise<PipelineR
|
|
|
404
407
|
logInfo(HOOK, `Pass-eligible agents this iteration: ${passEligible.join(", ")}`);
|
|
405
408
|
}
|
|
406
409
|
|
|
407
|
-
const highIssueThreshold =
|
|
410
|
+
const highIssueThreshold = agentSettings.highIssueThreshold ?? 3;
|
|
408
411
|
overrideVerdictsByThreshold(agentResults, highIssueThreshold);
|
|
409
412
|
|
|
410
413
|
// PHASE 4: Generate Output
|
|
@@ -4,19 +4,24 @@
|
|
|
4
4
|
* See cc-native-plan-review-spec.md §4.10
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import type { ExecutionBackend } from "../../../../_shared/lib-ts/agent-exec/execution-backend.js";
|
|
8
|
+
import { logWarn } from "../../../../_shared/lib-ts/base/logger.js";
|
|
9
|
+
import { debugLog, debugRaw } from "../../../lib-ts/debug.js";
|
|
10
|
+
import type { AgentConfig, ReviewerResult, ReviewOptions } from "../../../lib-ts/types.js";
|
|
7
11
|
import { ClaudeAgent } from "./providers/claude-agent.js";
|
|
8
12
|
import { CodexAgent } from "./providers/codex-agent.js";
|
|
9
13
|
import { GeminiAgent } from "./providers/gemini-agent.js";
|
|
10
14
|
import type { Reviewer } from "./types.js";
|
|
11
15
|
import { makeResult } from "./types.js";
|
|
12
|
-
import { logWarn } from "../../../../_shared/lib-ts/base/logger.js";
|
|
13
|
-
import type { AgentConfig, ReviewerResult, ReviewOptions } from "../../../lib-ts/types.js";
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Agent reviewer — runs a CLI instance with a custom persona.
|
|
17
19
|
*/
|
|
18
20
|
export class AgentReviewer implements Reviewer {
|
|
19
|
-
constructor(
|
|
21
|
+
constructor(
|
|
22
|
+
private agent: AgentConfig,
|
|
23
|
+
private backend?: ExecutionBackend,
|
|
24
|
+
) {}
|
|
20
25
|
|
|
21
26
|
async review(
|
|
22
27
|
plan: string,
|
|
@@ -30,6 +35,7 @@ export class AgentReviewer implements Reviewer {
|
|
|
30
35
|
options.timeout,
|
|
31
36
|
options.context_path,
|
|
32
37
|
options.session_name ?? "unknown",
|
|
38
|
+
this.backend,
|
|
33
39
|
);
|
|
34
40
|
}
|
|
35
41
|
}
|
|
@@ -46,21 +52,27 @@ export async function runAgentReview(
|
|
|
46
52
|
timeout: number,
|
|
47
53
|
contextPath?: string,
|
|
48
54
|
sessionName = "unknown",
|
|
55
|
+
backend?: ExecutionBackend,
|
|
49
56
|
): Promise<ReviewerResult> {
|
|
50
57
|
try {
|
|
51
|
-
|
|
58
|
+
const config = {
|
|
59
|
+
agent, schema, timeout, contextPath, sessionName,
|
|
60
|
+
debugLogger: { log: debugLog, raw: debugRaw },
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
let reviewer: ClaudeAgent | CodexAgent | GeminiAgent;
|
|
52
64
|
|
|
53
65
|
switch (agent.provider) {
|
|
54
66
|
case "codex": {
|
|
55
|
-
reviewer = new CodexAgent(
|
|
67
|
+
reviewer = new CodexAgent(config, backend);
|
|
56
68
|
break;
|
|
57
69
|
}
|
|
58
70
|
case "gemini": {
|
|
59
|
-
reviewer = new GeminiAgent(
|
|
71
|
+
reviewer = new GeminiAgent(config, backend);
|
|
60
72
|
break;
|
|
61
73
|
}
|
|
62
74
|
default: {
|
|
63
|
-
reviewer = new ClaudeAgent(
|
|
75
|
+
reviewer = new ClaudeAgent(config, backend);
|
|
64
76
|
break;
|
|
65
77
|
}
|
|
66
78
|
}
|