aiwcli 0.12.6 → 0.12.7
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/bin/dev.cmd +3 -3
- package/bin/dev.js +16 -16
- package/bin/run.cmd +3 -3
- package/bin/run.js +21 -21
- package/dist/commands/branch.js +7 -2
- package/dist/lib/bmad-installer.js +37 -37
- package/dist/lib/terminal.d.ts +2 -0
- package/dist/lib/terminal.js +57 -7
- package/dist/templates/CLAUDE.md +205 -205
- package/dist/templates/_shared/.claude/commands/handoff-resume.md +12 -12
- package/dist/templates/_shared/.claude/commands/handoff.md +12 -12
- package/dist/templates/_shared/.claude/settings.json +65 -65
- package/dist/templates/_shared/.codex/workflows/handoff.md +226 -226
- package/dist/templates/_shared/.windsurf/workflows/handoff.md +226 -226
- package/dist/templates/_shared/handoff-system/CLAUDE.md +421 -421
- package/dist/templates/_shared/handoff-system/lib/document-generator.ts +215 -215
- package/dist/templates/_shared/handoff-system/lib/handoff-reader.ts +158 -158
- package/dist/templates/_shared/handoff-system/scripts/resume_handoff.ts +373 -373
- package/dist/templates/_shared/handoff-system/scripts/save_handoff.ts +469 -469
- package/dist/templates/_shared/handoff-system/workflows/handoff-resume.md +66 -66
- package/dist/templates/_shared/handoff-system/workflows/handoff.md +254 -254
- package/dist/templates/_shared/hooks-ts/_utils/git-state.ts +2 -2
- package/dist/templates/_shared/hooks-ts/archive_plan.ts +159 -159
- package/dist/templates/_shared/hooks-ts/context_monitor.ts +147 -147
- package/dist/templates/_shared/hooks-ts/file-suggestion.ts +128 -128
- package/dist/templates/_shared/hooks-ts/pre_compact.ts +49 -49
- package/dist/templates/_shared/hooks-ts/session_end.ts +196 -196
- package/dist/templates/_shared/hooks-ts/session_start.ts +163 -163
- package/dist/templates/_shared/hooks-ts/task_create_capture.ts +48 -48
- package/dist/templates/_shared/hooks-ts/task_update_capture.ts +74 -74
- package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +93 -93
- package/dist/templates/_shared/lib-ts/CLAUDE.md +367 -367
- package/dist/templates/_shared/lib-ts/base/atomic-write.ts +138 -138
- package/dist/templates/_shared/lib-ts/base/constants.ts +303 -303
- package/dist/templates/_shared/lib-ts/base/git-state.ts +58 -58
- package/dist/templates/_shared/lib-ts/base/hook-utils.ts +582 -582
- package/dist/templates/_shared/lib-ts/base/inference.ts +301 -301
- package/dist/templates/_shared/lib-ts/base/logger.ts +247 -247
- package/dist/templates/_shared/lib-ts/base/state-io.ts +202 -202
- package/dist/templates/_shared/lib-ts/base/stop-words.ts +184 -184
- package/dist/templates/_shared/lib-ts/base/utils.ts +184 -184
- package/dist/templates/_shared/lib-ts/context/context-formatter.ts +566 -566
- package/dist/templates/_shared/lib-ts/context/context-selector.ts +524 -524
- package/dist/templates/_shared/lib-ts/context/context-store.ts +712 -712
- package/dist/templates/_shared/lib-ts/context/plan-manager.ts +312 -312
- package/dist/templates/_shared/lib-ts/context/task-tracker.ts +185 -185
- package/dist/templates/_shared/lib-ts/package.json +20 -20
- package/dist/templates/_shared/lib-ts/templates/formatters.ts +102 -102
- package/dist/templates/_shared/lib-ts/templates/plan-context.ts +58 -58
- package/dist/templates/_shared/lib-ts/tsconfig.json +13 -13
- package/dist/templates/_shared/lib-ts/types.ts +186 -186
- package/dist/templates/_shared/scripts/resolve_context.ts +33 -33
- package/dist/templates/_shared/scripts/status_line.ts +690 -690
- package/dist/templates/cc-native/.claude/commands/cc-native/rlm/ask.md +136 -136
- package/dist/templates/cc-native/.claude/commands/cc-native/rlm/index.md +21 -21
- package/dist/templates/cc-native/.claude/commands/cc-native/rlm/overview.md +56 -56
- package/dist/templates/cc-native/.claude/commands/cc-native/specdev.md +10 -10
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/fix.md +8 -8
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/implement.md +8 -8
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/research.md +8 -8
- package/dist/templates/cc-native/CC-NATIVE-README.md +189 -189
- package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +304 -304
- package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +143 -143
- package/dist/templates/cc-native/_cc-native/agents/PLAN-ORCHESTRATOR.md +213 -213
- package/dist/templates/cc-native/_cc-native/agents/plan-questions/PLAN-QUESTIONER.md +70 -70
- package/dist/templates/cc-native/_cc-native/cc-native.config.json +96 -96
- package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +247 -247
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +76 -76
- package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_subagent.ts +54 -54
- package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_write.ts +51 -51
- package/dist/templates/cc-native/_cc-native/hooks/mark_questions_asked.ts +53 -53
- package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +61 -61
- package/dist/templates/cc-native/_cc-native/lib-ts/agent-selection.ts +163 -163
- package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +156 -156
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/format.ts +597 -597
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/index.ts +26 -26
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/tracker.ts +107 -107
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/write.ts +119 -119
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +21 -21
- package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +319 -319
- package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +144 -144
- package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +57 -57
- package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +83 -83
- package/dist/templates/cc-native/_cc-native/lib-ts/corroboration.ts +119 -119
- package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +79 -79
- package/dist/templates/cc-native/_cc-native/lib-ts/graduation.ts +132 -132
- package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +116 -116
- package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +168 -168
- package/dist/templates/cc-native/_cc-native/lib-ts/orchestrator.ts +70 -70
- package/dist/templates/cc-native/_cc-native/lib-ts/output-builder.ts +130 -130
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +80 -80
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-enhancement.ts +41 -41
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-questions.ts +101 -101
- package/dist/templates/cc-native/_cc-native/lib-ts/review-pipeline.ts +511 -511
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/agent.ts +71 -71
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/base/base-agent.ts +217 -217
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/index.ts +12 -12
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/claude-agent.ts +66 -66
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/codex-agent.ts +184 -184
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/gemini-agent.ts +39 -39
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/orchestrator-claude-agent.ts +196 -196
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/schemas.ts +201 -201
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/types.ts +21 -21
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/CLAUDE.md +480 -480
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +287 -287
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +148 -148
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +54 -54
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +58 -58
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +208 -208
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +460 -460
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +446 -446
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +280 -280
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +274 -274
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +201 -201
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +278 -278
- package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +184 -184
- package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +275 -275
- package/dist/templates/cc-native/_cc-native/lib-ts/tsconfig.json +18 -18
- package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +329 -329
- package/dist/templates/cc-native/_cc-native/lib-ts/verdict.ts +72 -72
- package/dist/templates/cc-native/_cc-native/workflows/specdev.md +9 -9
- package/oclif.manifest.json +1 -1
- package/package.json +108 -108
- package/dist/templates/cc-native/_cc-native/lib-ts/nul +0 -3
|
@@ -1,116 +1,116 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CC-Native plan review library — package entry point.
|
|
3
|
-
* Re-exports the public API from all modules.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Agent aggregation
|
|
7
|
-
export {
|
|
8
|
-
aggregateAgents,
|
|
9
|
-
extractBody,
|
|
10
|
-
extractFrontmatter,
|
|
11
|
-
} from "./aggregate-agents.js";
|
|
12
|
-
|
|
13
|
-
// Artifacts
|
|
14
|
-
export {
|
|
15
|
-
buildCombinedJson,
|
|
16
|
-
buildHighIssuesDocument,
|
|
17
|
-
buildInlineReviewSummary,
|
|
18
|
-
extractTopIssuesText,
|
|
19
|
-
formatCombinedMarkdown,
|
|
20
|
-
formatReviewMarkdown,
|
|
21
|
-
generateReviewIndex,
|
|
22
|
-
writeCombinedArtifacts,
|
|
23
|
-
} from "./artifacts.js";
|
|
24
|
-
|
|
25
|
-
// CC-native state
|
|
26
|
-
export {
|
|
27
|
-
getCcNativeState,
|
|
28
|
-
isPlanAlreadyReviewed,
|
|
29
|
-
markPlanReviewed,
|
|
30
|
-
markQuestionsAsked,
|
|
31
|
-
saveCcNativeState,
|
|
32
|
-
wasPlanPreviouslyDenied,
|
|
33
|
-
wasQuestionsAsked,
|
|
34
|
-
} from "./cc-native-state.js";
|
|
35
|
-
|
|
36
|
-
// CLI output parsing
|
|
37
|
-
export { parseCliOutput } from "./cli-output-parser.js";
|
|
38
|
-
|
|
39
|
-
// Configuration
|
|
40
|
-
export { getDisplaySettings, loadConfig } from "./config.js";
|
|
41
|
-
|
|
42
|
-
// Constants & security
|
|
43
|
-
export {
|
|
44
|
-
ENABLE_PLAN_NOTIFICATIONS,
|
|
45
|
-
ENABLE_ROBUST_PLAN_WRITES,
|
|
46
|
-
MAX_ERROR_FILE_SIZE,
|
|
47
|
-
MAX_PLAN_PATH_LENGTH,
|
|
48
|
-
MAX_RETRY_ATTEMPTS,
|
|
49
|
-
MAX_TOTAL_RETRY_TIME_MS,
|
|
50
|
-
PLANS_DIR,
|
|
51
|
-
RETRY_BACKOFF_MS,
|
|
52
|
-
validatePlanPath,
|
|
53
|
-
} from "./constants.js";
|
|
54
|
-
|
|
55
|
-
// Debug logging
|
|
56
|
-
export { cleanupDebugFolder, debugLog, debugRaw, getDebugDir } from "./debug.js";
|
|
57
|
-
|
|
58
|
-
// JSON parsing
|
|
59
|
-
export { coerceToReview, parseJsonMaybe } from "./json-parser.js";
|
|
60
|
-
|
|
61
|
-
// Orchestrator
|
|
62
|
-
export { buildOrchestratorSchema, runOrchestrator } from "./orchestrator.js";
|
|
63
|
-
|
|
64
|
-
// Reviewers
|
|
65
|
-
export {
|
|
66
|
-
AgentReviewer,
|
|
67
|
-
runAgentReview,
|
|
68
|
-
} from "./reviewers/index.js";
|
|
69
|
-
|
|
70
|
-
// Iteration state
|
|
71
|
-
export {
|
|
72
|
-
DEFAULT_REVIEW_ITERATIONS,
|
|
73
|
-
deleteState,
|
|
74
|
-
getIterationState,
|
|
75
|
-
getStateFilePath,
|
|
76
|
-
loadState,
|
|
77
|
-
saveStateToPlan,
|
|
78
|
-
shouldContinueIterating,
|
|
79
|
-
updateIterationState,
|
|
80
|
-
} from "./state.js";
|
|
81
|
-
|
|
82
|
-
// Types & schemas
|
|
83
|
-
export type {
|
|
84
|
-
AgentConfig,
|
|
85
|
-
CcNativeState,
|
|
86
|
-
CombinedReviewResult,
|
|
87
|
-
ComplexityCategory,
|
|
88
|
-
DisplaySettings,
|
|
89
|
-
IterationEntry,
|
|
90
|
-
IterationState,
|
|
91
|
-
OrchestratorConfig,
|
|
92
|
-
OrchestratorResult,
|
|
93
|
-
PlanReviewConfig,
|
|
94
|
-
PlanReviewState,
|
|
95
|
-
QuestionsAskedState,
|
|
96
|
-
ReviewData,
|
|
97
|
-
ReviewDecision,
|
|
98
|
-
ReviewDecisionResult,
|
|
99
|
-
Reviewer,
|
|
100
|
-
ReviewerResult,
|
|
101
|
-
ReviewIssue,
|
|
102
|
-
ReviewOptions,
|
|
103
|
-
Verdict,
|
|
104
|
-
} from "./types.js";
|
|
105
|
-
|
|
106
|
-
export {
|
|
107
|
-
AGENT_REVIEW_PROMPT_PREFIX,
|
|
108
|
-
DEFAULT_DISPLAY,
|
|
109
|
-
DEFAULT_SANITIZATION,
|
|
110
|
-
ORCHESTRATOR_SCHEMA,
|
|
111
|
-
REVIEW_PROMPT_PREFIX,
|
|
112
|
-
REVIEW_SCHEMA,
|
|
113
|
-
} from "./types.js";
|
|
114
|
-
|
|
115
|
-
// Verdict aggregation
|
|
116
|
-
export { computeReviewDecision, worstVerdict } from "./verdict.js";
|
|
1
|
+
/**
|
|
2
|
+
* CC-Native plan review library — package entry point.
|
|
3
|
+
* Re-exports the public API from all modules.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Agent aggregation
|
|
7
|
+
export {
|
|
8
|
+
aggregateAgents,
|
|
9
|
+
extractBody,
|
|
10
|
+
extractFrontmatter,
|
|
11
|
+
} from "./aggregate-agents.js";
|
|
12
|
+
|
|
13
|
+
// Artifacts
|
|
14
|
+
export {
|
|
15
|
+
buildCombinedJson,
|
|
16
|
+
buildHighIssuesDocument,
|
|
17
|
+
buildInlineReviewSummary,
|
|
18
|
+
extractTopIssuesText,
|
|
19
|
+
formatCombinedMarkdown,
|
|
20
|
+
formatReviewMarkdown,
|
|
21
|
+
generateReviewIndex,
|
|
22
|
+
writeCombinedArtifacts,
|
|
23
|
+
} from "./artifacts.js";
|
|
24
|
+
|
|
25
|
+
// CC-native state
|
|
26
|
+
export {
|
|
27
|
+
getCcNativeState,
|
|
28
|
+
isPlanAlreadyReviewed,
|
|
29
|
+
markPlanReviewed,
|
|
30
|
+
markQuestionsAsked,
|
|
31
|
+
saveCcNativeState,
|
|
32
|
+
wasPlanPreviouslyDenied,
|
|
33
|
+
wasQuestionsAsked,
|
|
34
|
+
} from "./cc-native-state.js";
|
|
35
|
+
|
|
36
|
+
// CLI output parsing
|
|
37
|
+
export { parseCliOutput } from "./cli-output-parser.js";
|
|
38
|
+
|
|
39
|
+
// Configuration
|
|
40
|
+
export { getDisplaySettings, loadConfig } from "./config.js";
|
|
41
|
+
|
|
42
|
+
// Constants & security
|
|
43
|
+
export {
|
|
44
|
+
ENABLE_PLAN_NOTIFICATIONS,
|
|
45
|
+
ENABLE_ROBUST_PLAN_WRITES,
|
|
46
|
+
MAX_ERROR_FILE_SIZE,
|
|
47
|
+
MAX_PLAN_PATH_LENGTH,
|
|
48
|
+
MAX_RETRY_ATTEMPTS,
|
|
49
|
+
MAX_TOTAL_RETRY_TIME_MS,
|
|
50
|
+
PLANS_DIR,
|
|
51
|
+
RETRY_BACKOFF_MS,
|
|
52
|
+
validatePlanPath,
|
|
53
|
+
} from "./constants.js";
|
|
54
|
+
|
|
55
|
+
// Debug logging
|
|
56
|
+
export { cleanupDebugFolder, debugLog, debugRaw, getDebugDir } from "./debug.js";
|
|
57
|
+
|
|
58
|
+
// JSON parsing
|
|
59
|
+
export { coerceToReview, parseJsonMaybe } from "./json-parser.js";
|
|
60
|
+
|
|
61
|
+
// Orchestrator
|
|
62
|
+
export { buildOrchestratorSchema, runOrchestrator } from "./orchestrator.js";
|
|
63
|
+
|
|
64
|
+
// Reviewers
|
|
65
|
+
export {
|
|
66
|
+
AgentReviewer,
|
|
67
|
+
runAgentReview,
|
|
68
|
+
} from "./reviewers/index.js";
|
|
69
|
+
|
|
70
|
+
// Iteration state
|
|
71
|
+
export {
|
|
72
|
+
DEFAULT_REVIEW_ITERATIONS,
|
|
73
|
+
deleteState,
|
|
74
|
+
getIterationState,
|
|
75
|
+
getStateFilePath,
|
|
76
|
+
loadState,
|
|
77
|
+
saveStateToPlan,
|
|
78
|
+
shouldContinueIterating,
|
|
79
|
+
updateIterationState,
|
|
80
|
+
} from "./state.js";
|
|
81
|
+
|
|
82
|
+
// Types & schemas
|
|
83
|
+
export type {
|
|
84
|
+
AgentConfig,
|
|
85
|
+
CcNativeState,
|
|
86
|
+
CombinedReviewResult,
|
|
87
|
+
ComplexityCategory,
|
|
88
|
+
DisplaySettings,
|
|
89
|
+
IterationEntry,
|
|
90
|
+
IterationState,
|
|
91
|
+
OrchestratorConfig,
|
|
92
|
+
OrchestratorResult,
|
|
93
|
+
PlanReviewConfig,
|
|
94
|
+
PlanReviewState,
|
|
95
|
+
QuestionsAskedState,
|
|
96
|
+
ReviewData,
|
|
97
|
+
ReviewDecision,
|
|
98
|
+
ReviewDecisionResult,
|
|
99
|
+
Reviewer,
|
|
100
|
+
ReviewerResult,
|
|
101
|
+
ReviewIssue,
|
|
102
|
+
ReviewOptions,
|
|
103
|
+
Verdict,
|
|
104
|
+
} from "./types.js";
|
|
105
|
+
|
|
106
|
+
export {
|
|
107
|
+
AGENT_REVIEW_PROMPT_PREFIX,
|
|
108
|
+
DEFAULT_DISPLAY,
|
|
109
|
+
DEFAULT_SANITIZATION,
|
|
110
|
+
ORCHESTRATOR_SCHEMA,
|
|
111
|
+
REVIEW_PROMPT_PREFIX,
|
|
112
|
+
REVIEW_SCHEMA,
|
|
113
|
+
} from "./types.js";
|
|
114
|
+
|
|
115
|
+
// Verdict aggregation
|
|
116
|
+
export { computeReviewDecision, worstVerdict } from "./verdict.js";
|
|
@@ -1,168 +1,168 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JSON parsing utilities for LLM responses.
|
|
3
|
-
* See cc-native-plan-review-spec.md §4.10-4.11
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { ReviewData, Verdict } from "./types.js";
|
|
7
|
-
import { logDebug, logWarn } from "../../_shared/lib-ts/base/logger.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Try strict JSON parse. If that fails, attempt to extract the first {...} block.
|
|
11
|
-
*
|
|
12
|
-
* @param text - Raw text that may contain JSON
|
|
13
|
-
* @param requireFields - Optional list of field names to check for
|
|
14
|
-
* @returns Parsed dict or null if parsing failed entirely
|
|
15
|
-
*/
|
|
16
|
-
export function parseJsonMaybe(
|
|
17
|
-
text: string,
|
|
18
|
-
requireFields?: string[],
|
|
19
|
-
): null | Record<string, unknown> {
|
|
20
|
-
const trimmed = text.trim();
|
|
21
|
-
if (!trimmed) return null;
|
|
22
|
-
|
|
23
|
-
let obj: null | Record<string, unknown> = null;
|
|
24
|
-
let parseMethod: null | string = null;
|
|
25
|
-
|
|
26
|
-
// Strict parse
|
|
27
|
-
try {
|
|
28
|
-
const parsed: unknown = JSON.parse(trimmed);
|
|
29
|
-
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
30
|
-
obj = parsed as Record<string, unknown>;
|
|
31
|
-
parseMethod = "strict";
|
|
32
|
-
}
|
|
33
|
-
} catch {
|
|
34
|
-
// Fall through to heuristic
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Heuristic: try to extract a JSON object substring
|
|
38
|
-
if (obj === null) {
|
|
39
|
-
const start = trimmed.indexOf("{");
|
|
40
|
-
const end = trimmed.lastIndexOf("}");
|
|
41
|
-
if (start !== -1 && end !== -1 && end > start) {
|
|
42
|
-
const candidate = trimmed.slice(start, end + 1);
|
|
43
|
-
try {
|
|
44
|
-
const parsed: unknown = JSON.parse(candidate);
|
|
45
|
-
if (
|
|
46
|
-
parsed !== null &&
|
|
47
|
-
typeof parsed === "object" &&
|
|
48
|
-
!Array.isArray(parsed)
|
|
49
|
-
) {
|
|
50
|
-
obj = parsed as Record<string, unknown>;
|
|
51
|
-
parseMethod = "heuristic";
|
|
52
|
-
logDebug(
|
|
53
|
-
"parse",
|
|
54
|
-
`Used heuristic extraction (chars ${start}-${end})`,
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
} catch {
|
|
58
|
-
logDebug(
|
|
59
|
-
"parse",
|
|
60
|
-
`Heuristic extraction failed for candidate at chars ${start}-${end}`,
|
|
61
|
-
);
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Validate required fields if parsed
|
|
68
|
-
if (obj && requireFields) {
|
|
69
|
-
const missing = requireFields.filter((f) => !(f in obj!) || !obj![f]);
|
|
70
|
-
if (missing.length > 0) {
|
|
71
|
-
logWarn(
|
|
72
|
-
"parse",
|
|
73
|
-
`Parsed JSON (${parseMethod}) missing/empty fields: ${JSON.stringify(missing)}`,
|
|
74
|
-
);
|
|
75
|
-
logDebug("parse", `Keys present: ${JSON.stringify(Object.keys(obj))}`);
|
|
76
|
-
// Heuristic extraction grabbed the wrong object — reject it.
|
|
77
|
-
// Strict parse still returns partial objects (caller handles defaults).
|
|
78
|
-
if (parseMethod === "heuristic") {
|
|
79
|
-
logWarn("parse", "Rejecting heuristic result due to missing required fields");
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return obj;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Validate/normalize parsed JSON to ReviewData shape with safe defaults.
|
|
90
|
-
*
|
|
91
|
-
* @param obj - Parsed JSON object (possibly null)
|
|
92
|
-
* @param defaultFixMsg - Default suggested_fix message for error case
|
|
93
|
-
* @returns Tuple of [ok, verdict, normalizedData]
|
|
94
|
-
*/
|
|
95
|
-
export function coerceToReview(
|
|
96
|
-
obj: null | Record<string, unknown>,
|
|
97
|
-
defaultFixMsg = "Retry or check configuration.",
|
|
98
|
-
): [boolean, Verdict, ReviewData] {
|
|
99
|
-
if (!obj) {
|
|
100
|
-
logWarn("coerce", "No object provided to coerceToReview");
|
|
101
|
-
return [
|
|
102
|
-
false,
|
|
103
|
-
"error",
|
|
104
|
-
{
|
|
105
|
-
verdict: "fail",
|
|
106
|
-
summary: "No structured output returned.",
|
|
107
|
-
summary_source: "default",
|
|
108
|
-
issues: [
|
|
109
|
-
{
|
|
110
|
-
severity: "high",
|
|
111
|
-
category: "tooling",
|
|
112
|
-
issue: "Reviewer returned no JSON.",
|
|
113
|
-
suggested_fix: defaultFixMsg,
|
|
114
|
-
},
|
|
115
|
-
],
|
|
116
|
-
missing_sections: [],
|
|
117
|
-
questions: [],
|
|
118
|
-
},
|
|
119
|
-
];
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const rawVerdict = obj.verdict;
|
|
123
|
-
let verdict: Verdict;
|
|
124
|
-
if (rawVerdict === "pass" || rawVerdict === "warn" || rawVerdict === "fail") {
|
|
125
|
-
verdict = rawVerdict;
|
|
126
|
-
} else {
|
|
127
|
-
logWarn(
|
|
128
|
-
"coerce",
|
|
129
|
-
`Invalid or missing verdict '${String(rawVerdict)}', defaulting to 'warn'`,
|
|
130
|
-
);
|
|
131
|
-
verdict = "warn";
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Log when fields are being defaulted
|
|
135
|
-
const summaryRaw = String(obj.summary ?? "").trim();
|
|
136
|
-
if (!summaryRaw) {
|
|
137
|
-
logWarn(
|
|
138
|
-
"coerce",
|
|
139
|
-
"summary missing or empty from parsed output, using default",
|
|
140
|
-
);
|
|
141
|
-
logDebug("coerce", `Raw object keys: ${JSON.stringify(Object.keys(obj))}`);
|
|
142
|
-
logDebug(
|
|
143
|
-
"coerce",
|
|
144
|
-
`verdict=${obj.verdict}, issues_count=${Array.isArray(obj.issues) ? (obj.issues as unknown[]).length : 0}`,
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (!obj.issues) {
|
|
149
|
-
logDebug("coerce", "issues array empty or missing");
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const norm: ReviewData = {
|
|
153
|
-
verdict,
|
|
154
|
-
summary: summaryRaw || "No summary provided.",
|
|
155
|
-
summary_source: summaryRaw ? "reviewer" : "default",
|
|
156
|
-
issues: Array.isArray(obj.issues)
|
|
157
|
-
? (obj.issues as ReviewData["issues"])
|
|
158
|
-
: [],
|
|
159
|
-
missing_sections: Array.isArray(obj.missing_sections)
|
|
160
|
-
? (obj.missing_sections as string[])
|
|
161
|
-
: [],
|
|
162
|
-
questions: Array.isArray(obj.questions)
|
|
163
|
-
? (obj.questions as string[])
|
|
164
|
-
: [],
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
return [true, verdict, norm];
|
|
168
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* JSON parsing utilities for LLM responses.
|
|
3
|
+
* See cc-native-plan-review-spec.md §4.10-4.11
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ReviewData, Verdict } from "./types.js";
|
|
7
|
+
import { logDebug, logWarn } from "../../_shared/lib-ts/base/logger.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Try strict JSON parse. If that fails, attempt to extract the first {...} block.
|
|
11
|
+
*
|
|
12
|
+
* @param text - Raw text that may contain JSON
|
|
13
|
+
* @param requireFields - Optional list of field names to check for
|
|
14
|
+
* @returns Parsed dict or null if parsing failed entirely
|
|
15
|
+
*/
|
|
16
|
+
export function parseJsonMaybe(
|
|
17
|
+
text: string,
|
|
18
|
+
requireFields?: string[],
|
|
19
|
+
): null | Record<string, unknown> {
|
|
20
|
+
const trimmed = text.trim();
|
|
21
|
+
if (!trimmed) return null;
|
|
22
|
+
|
|
23
|
+
let obj: null | Record<string, unknown> = null;
|
|
24
|
+
let parseMethod: null | string = null;
|
|
25
|
+
|
|
26
|
+
// Strict parse
|
|
27
|
+
try {
|
|
28
|
+
const parsed: unknown = JSON.parse(trimmed);
|
|
29
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
30
|
+
obj = parsed as Record<string, unknown>;
|
|
31
|
+
parseMethod = "strict";
|
|
32
|
+
}
|
|
33
|
+
} catch {
|
|
34
|
+
// Fall through to heuristic
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Heuristic: try to extract a JSON object substring
|
|
38
|
+
if (obj === null) {
|
|
39
|
+
const start = trimmed.indexOf("{");
|
|
40
|
+
const end = trimmed.lastIndexOf("}");
|
|
41
|
+
if (start !== -1 && end !== -1 && end > start) {
|
|
42
|
+
const candidate = trimmed.slice(start, end + 1);
|
|
43
|
+
try {
|
|
44
|
+
const parsed: unknown = JSON.parse(candidate);
|
|
45
|
+
if (
|
|
46
|
+
parsed !== null &&
|
|
47
|
+
typeof parsed === "object" &&
|
|
48
|
+
!Array.isArray(parsed)
|
|
49
|
+
) {
|
|
50
|
+
obj = parsed as Record<string, unknown>;
|
|
51
|
+
parseMethod = "heuristic";
|
|
52
|
+
logDebug(
|
|
53
|
+
"parse",
|
|
54
|
+
`Used heuristic extraction (chars ${start}-${end})`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
logDebug(
|
|
59
|
+
"parse",
|
|
60
|
+
`Heuristic extraction failed for candidate at chars ${start}-${end}`,
|
|
61
|
+
);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Validate required fields if parsed
|
|
68
|
+
if (obj && requireFields) {
|
|
69
|
+
const missing = requireFields.filter((f) => !(f in obj!) || !obj![f]);
|
|
70
|
+
if (missing.length > 0) {
|
|
71
|
+
logWarn(
|
|
72
|
+
"parse",
|
|
73
|
+
`Parsed JSON (${parseMethod}) missing/empty fields: ${JSON.stringify(missing)}`,
|
|
74
|
+
);
|
|
75
|
+
logDebug("parse", `Keys present: ${JSON.stringify(Object.keys(obj))}`);
|
|
76
|
+
// Heuristic extraction grabbed the wrong object — reject it.
|
|
77
|
+
// Strict parse still returns partial objects (caller handles defaults).
|
|
78
|
+
if (parseMethod === "heuristic") {
|
|
79
|
+
logWarn("parse", "Rejecting heuristic result due to missing required fields");
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return obj;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Validate/normalize parsed JSON to ReviewData shape with safe defaults.
|
|
90
|
+
*
|
|
91
|
+
* @param obj - Parsed JSON object (possibly null)
|
|
92
|
+
* @param defaultFixMsg - Default suggested_fix message for error case
|
|
93
|
+
* @returns Tuple of [ok, verdict, normalizedData]
|
|
94
|
+
*/
|
|
95
|
+
export function coerceToReview(
|
|
96
|
+
obj: null | Record<string, unknown>,
|
|
97
|
+
defaultFixMsg = "Retry or check configuration.",
|
|
98
|
+
): [boolean, Verdict, ReviewData] {
|
|
99
|
+
if (!obj) {
|
|
100
|
+
logWarn("coerce", "No object provided to coerceToReview");
|
|
101
|
+
return [
|
|
102
|
+
false,
|
|
103
|
+
"error",
|
|
104
|
+
{
|
|
105
|
+
verdict: "fail",
|
|
106
|
+
summary: "No structured output returned.",
|
|
107
|
+
summary_source: "default",
|
|
108
|
+
issues: [
|
|
109
|
+
{
|
|
110
|
+
severity: "high",
|
|
111
|
+
category: "tooling",
|
|
112
|
+
issue: "Reviewer returned no JSON.",
|
|
113
|
+
suggested_fix: defaultFixMsg,
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
missing_sections: [],
|
|
117
|
+
questions: [],
|
|
118
|
+
},
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const rawVerdict = obj.verdict;
|
|
123
|
+
let verdict: Verdict;
|
|
124
|
+
if (rawVerdict === "pass" || rawVerdict === "warn" || rawVerdict === "fail") {
|
|
125
|
+
verdict = rawVerdict;
|
|
126
|
+
} else {
|
|
127
|
+
logWarn(
|
|
128
|
+
"coerce",
|
|
129
|
+
`Invalid or missing verdict '${String(rawVerdict)}', defaulting to 'warn'`,
|
|
130
|
+
);
|
|
131
|
+
verdict = "warn";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Log when fields are being defaulted
|
|
135
|
+
const summaryRaw = String(obj.summary ?? "").trim();
|
|
136
|
+
if (!summaryRaw) {
|
|
137
|
+
logWarn(
|
|
138
|
+
"coerce",
|
|
139
|
+
"summary missing or empty from parsed output, using default",
|
|
140
|
+
);
|
|
141
|
+
logDebug("coerce", `Raw object keys: ${JSON.stringify(Object.keys(obj))}`);
|
|
142
|
+
logDebug(
|
|
143
|
+
"coerce",
|
|
144
|
+
`verdict=${obj.verdict}, issues_count=${Array.isArray(obj.issues) ? (obj.issues as unknown[]).length : 0}`,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (!obj.issues) {
|
|
149
|
+
logDebug("coerce", "issues array empty or missing");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const norm: ReviewData = {
|
|
153
|
+
verdict,
|
|
154
|
+
summary: summaryRaw || "No summary provided.",
|
|
155
|
+
summary_source: summaryRaw ? "reviewer" : "default",
|
|
156
|
+
issues: Array.isArray(obj.issues)
|
|
157
|
+
? (obj.issues as ReviewData["issues"])
|
|
158
|
+
: [],
|
|
159
|
+
missing_sections: Array.isArray(obj.missing_sections)
|
|
160
|
+
? (obj.missing_sections as string[])
|
|
161
|
+
: [],
|
|
162
|
+
questions: Array.isArray(obj.questions)
|
|
163
|
+
? (obj.questions as string[])
|
|
164
|
+
: [],
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
return [true, verdict, norm];
|
|
168
|
+
}
|