aiwcli 0.12.7 → 0.13.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.
- package/dist/commands/clean.d.ts +7 -0
- package/dist/commands/clean.js +17 -8
- package/dist/commands/clear.d.ts +85 -0
- package/dist/commands/clear.js +455 -347
- package/dist/commands/init/index.d.ts +15 -0
- package/dist/commands/init/index.js +79 -38
- package/dist/lib/gitignore-manager.js +12 -13
- package/dist/lib/settings-hierarchy.d.ts +13 -1
- package/dist/lib/settings-hierarchy.js +1 -1
- package/dist/lib/template-linter.d.ts +4 -0
- package/dist/lib/template-linter.js +1 -1
- package/dist/lib/tty-detection.d.ts +1 -0
- package/dist/lib/tty-detection.js +1 -0
- package/dist/templates/CLAUDE.md +27 -0
- package/dist/templates/_shared/.claude/settings.json +7 -7
- package/dist/templates/_shared/.claude/{commands/handoff.md → skills/handoff/SKILL.md} +4 -3
- package/dist/templates/_shared/.claude/{commands/handoff-resume.md → skills/handoff-resume/SKILL.md} +3 -2
- package/dist/templates/_shared/.claude/skills/meta-plan/SKILL.md +43 -0
- package/dist/templates/_shared/.codex/workflows/handoff.md +1 -1
- package/dist/templates/_shared/.codex/workflows/meta-plan.md +347 -0
- package/dist/templates/_shared/.windsurf/workflows/handoff.md +1 -1
- package/dist/templates/_shared/.windsurf/workflows/meta-plan.md +347 -0
- package/dist/templates/_shared/hooks-ts/lint_after_edit.ts +59 -0
- package/dist/templates/_shared/hooks-ts/session_end.ts +11 -10
- package/dist/templates/_shared/hooks-ts/session_start.ts +15 -12
- package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +12 -12
- package/dist/templates/_shared/lib-ts/CLAUDE.md +3 -3
- package/dist/templates/_shared/lib-ts/base/constants.ts +324 -306
- package/dist/templates/_shared/lib-ts/base/hook-utils.ts +26 -7
- package/dist/templates/_shared/lib-ts/base/inference.ts +19 -19
- package/dist/templates/_shared/lib-ts/base/lint-dispatch.ts +287 -0
- package/dist/templates/_shared/lib-ts/base/state-io.ts +4 -3
- package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +3 -3
- package/dist/templates/_shared/lib-ts/context/CLAUDE.md +134 -0
- package/dist/templates/_shared/lib-ts/context/context-formatter.ts +16 -15
- package/dist/templates/_shared/lib-ts/context/context-selector.ts +16 -16
- package/dist/templates/_shared/lib-ts/context/context-store.ts +15 -14
- package/dist/templates/_shared/lib-ts/context/plan-manager.ts +2 -2
- package/dist/templates/_shared/scripts/resolve-run.ts +61 -0
- package/dist/templates/_shared/scripts/resolve_context.ts +1 -1
- package/dist/templates/_shared/scripts/status_line.ts +100 -94
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/CLAUDE.md +433 -421
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/lib/document-generator.ts +5 -4
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/lib/handoff-reader.ts +2 -1
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/scripts/resume_handoff.ts +6 -6
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/scripts/save_handoff.ts +16 -17
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/workflows/handoff-resume.md +2 -2
- package/dist/templates/_shared/{handoff-system → skills/handoff-system}/workflows/handoff.md +3 -3
- package/dist/templates/_shared/skills/meta-plan/CLAUDE.md +44 -0
- package/dist/templates/_shared/skills/meta-plan/workflows/meta-plan.md +347 -0
- package/dist/templates/cc-native/.claude/commands/cc-native/specdev.md +1 -1
- package/dist/templates/cc-native/.claude/settings.json +86 -57
- package/dist/templates/cc-native/_cc-native/artifacts/CLAUDE.md +64 -0
- package/dist/templates/cc-native/_cc-native/{lib-ts/artifacts → artifacts/lib}/format.ts +599 -597
- package/dist/templates/cc-native/_cc-native/{lib-ts/artifacts → artifacts/lib}/index.ts +26 -26
- package/dist/templates/cc-native/_cc-native/{lib-ts/artifacts → artifacts/lib}/tracker.ts +107 -106
- package/dist/templates/cc-native/_cc-native/{lib-ts/artifacts → artifacts/lib}/write.ts +119 -118
- package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +237 -247
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +76 -74
- package/dist/templates/cc-native/_cc-native/hooks/validate_task_prompt.ts +76 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +163 -156
- package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +15 -16
- package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +116 -116
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +3 -3
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +16 -12
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +2 -3
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +31 -31
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +7 -6
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +9 -7
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +17 -14
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +41 -37
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +43 -33
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +20 -20
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +9 -8
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +4 -3
- package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +9 -10
- package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +20 -19
- package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +329 -329
- package/dist/templates/cc-native/_cc-native/plan-review/CLAUDE.md +149 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/CLAUDE.md +143 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/PLAN-ORCHESTRATOR.md +213 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-questions/PLAN-QUESTIONER.md +70 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-EVOLUTION.md +62 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-PATTERNS.md +61 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-STRUCTURE.md +62 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ASSUMPTION-TRACER.md +56 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CLARITY-AUDITOR.md +53 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-FEASIBILITY.md +66 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-GAPS.md +70 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-ORDERING.md +62 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CONSTRAINT-VALIDATOR.md +72 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-ADR-VALIDATOR.md +61 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-SCALE-MATCHER.md +64 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DEVILS-ADVOCATE.md +56 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DOCUMENTATION-PHILOSOPHY.md +86 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HANDOFF-READINESS.md +59 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HIDDEN-COMPLEXITY.md +58 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/INCREMENTAL-DELIVERY.md +66 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-DEPENDENCY.md +62 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-FMEA.md +66 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-PREMORTEM.md +71 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-REVERSIBILITY.md +74 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SCOPE-BOUNDARY.md +77 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SIMPLICITY-GUARDIAN.md +62 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SKEPTIC.md +68 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-BEHAVIOR-AUDITOR.md +61 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-CHARACTERIZATION.md +71 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-FIRST-VALIDATOR.md +61 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-PYRAMID-ANALYZER.md +61 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-COSTS.md +67 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-STAKEHOLDERS.md +65 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-COVERAGE.md +74 -0
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-STRENGTH.md +69 -0
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/agent-selection.ts +162 -163
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/corroboration.ts +119 -119
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/graduation.ts +132 -132
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/orchestrator.ts +70 -70
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/output-builder.ts +121 -130
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/plan-questions.ts +101 -102
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/review-pipeline.ts +507 -511
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/agent.ts +73 -74
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/base/base-agent.ts +217 -217
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/index.ts +12 -12
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/providers/claude-agent.ts +66 -66
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/providers/codex-agent.ts +185 -185
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/providers/gemini-agent.ts +39 -39
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/providers/orchestrator-claude-agent.ts +196 -196
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/schemas.ts +201 -201
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/types.ts +23 -23
- package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/verdict.ts +72 -72
- package/dist/templates/cc-native/_cc-native/{workflows → plan-review/workflows}/specdev.md +9 -9
- package/oclif.manifest.json +1 -1
- package/package.json +6 -5
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +0 -21
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* PreToolUse:Task Hook: Prompt Validation Gate
|
|
4
|
+
*
|
|
5
|
+
* Validates that Task tool calls have self-contained, goal-oriented prompts.
|
|
6
|
+
* Short-circuits immediately for resume calls (no prompt to validate).
|
|
7
|
+
*
|
|
8
|
+
* Design:
|
|
9
|
+
* - Resume calls (tool_input.resume present) → allow through, no inference
|
|
10
|
+
* - Missing/empty prompt → allow through (fail open)
|
|
11
|
+
* - Non-empty prompt → run AI validation via inference(), block if ok:false
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
loadHookInput,
|
|
16
|
+
runHook,
|
|
17
|
+
logInfo,
|
|
18
|
+
logDebug,
|
|
19
|
+
logWarn,
|
|
20
|
+
emitContextAndBlock,
|
|
21
|
+
getToolInput,
|
|
22
|
+
} from "../../_shared/lib-ts/base/hook-utils.js";
|
|
23
|
+
import { inference } from "../../_shared/lib-ts/base/inference.js";
|
|
24
|
+
import { isInternalCall } from "../../_shared/lib-ts/base/subprocess-utils.js";
|
|
25
|
+
|
|
26
|
+
const VALIDATION_SYSTEM_PROMPT = `The sub-agent receives ONLY the prompt text — no conversation history, no prior context.
|
|
27
|
+
|
|
28
|
+
Check 1 — Dangling References: Does the prompt use pronouns or demonstratives that ONLY make sense with prior conversation? Violations: 'the file we looked at', 'as discussed above', 'that approach we chose', 'the error from earlier', 'fix the issue mentioned above'. NOT violations: relative paths ('_output/', 'src/lib/'), search terms ('context-manager', 'auth module'), directory exploration ('find files matching X'), tool names, or any concrete noun — even if imprecise. Only flag references that are truly UNRESOLVABLE without conversation history.
|
|
29
|
+
|
|
30
|
+
Check 2 — Implicit Contract: Does the prompt have ANY discernible goal? 'Explore the _output directory and find context files' IS a clear goal. 'Search for hooks that handle Task events' IS a clear goal. 'Read and summarize all files in X' IS a clear goal. Only flag if the prompt is truly goalless — e.g., a sentence fragment with no verb, or pure context with no request.
|
|
31
|
+
|
|
32
|
+
If both checks pass, return ok:true. When in doubt, pass — false negatives (letting a vague prompt through) are far less costly than false positives (blocking legitimate work).
|
|
33
|
+
|
|
34
|
+
When returning ok:false, end your response with: 'Retry: Re-invoke the Task tool with a revised prompt that resolves the issues above.'`;
|
|
35
|
+
|
|
36
|
+
function main(): void {
|
|
37
|
+
if (isInternalCall()) return;
|
|
38
|
+
|
|
39
|
+
const payload = loadHookInput();
|
|
40
|
+
if (!payload) return;
|
|
41
|
+
|
|
42
|
+
const toolInput = getToolInput(payload);
|
|
43
|
+
|
|
44
|
+
// Resume calls: tool_input contains `resume: "<agent-id>"` (may also have prompt/description).
|
|
45
|
+
// The resume field being present is the authoritative discriminator — skip all validation.
|
|
46
|
+
if (toolInput?.resume) {
|
|
47
|
+
logInfo("validate_task_prompt", `Resume call detected (agent: ${toolInput.resume}) — skipping validation`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const prompt: string = toolInput?.prompt ?? "";
|
|
52
|
+
if (!prompt.trim()) {
|
|
53
|
+
logDebug("validate_task_prompt", "No prompt field — allowing through (fail open)");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
logInfo("validate_task_prompt", `Validating Task prompt (${prompt.length} chars)`);
|
|
58
|
+
const result = inference(VALIDATION_SYSTEM_PROMPT, prompt, "fast");
|
|
59
|
+
|
|
60
|
+
if (!result.success) {
|
|
61
|
+
logWarn("validate_task_prompt", `inference() failed (${result.error}) — failing open`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const {output} = result;
|
|
66
|
+
if (output.includes("ok:false")) {
|
|
67
|
+
// Extract the Retry line if present; fall back to full output
|
|
68
|
+
const retryMatch = output.match(/Retry:.*$/m);
|
|
69
|
+
const retryMessage = retryMatch ? retryMatch[0] : "Retry: Re-invoke the Task tool with a revised, self-contained prompt.";
|
|
70
|
+
logInfo("validate_task_prompt", "Blocking Task — prompt failed validation");
|
|
71
|
+
emitContextAndBlock(output, retryMessage);
|
|
72
|
+
}
|
|
73
|
+
// ok:true or anything else → allow through (no output = no block)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
runHook(main, "validate_task_prompt");
|
|
@@ -1,156 +1,163 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent frontmatter parser — discovers and loads agent configs from markdown files.
|
|
3
|
-
* See cc-native-plan-review-spec.md §4.14
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Agent frontmatter parser — discovers and loads agent configs from markdown files.
|
|
3
|
+
* See cc-native-plan-review-spec.md §4.14
|
|
4
|
+
*
|
|
5
|
+
* NOTE: This file intentionally stays in lib-ts/ rather than plan-review/lib/.
|
|
6
|
+
* Both settings.ts (shared cc-native infra) and plan-questions.ts (plan-review) import it.
|
|
7
|
+
* Moving it to plan-review/ would create a forbidden backward dependency: lib-ts → plan-review.
|
|
8
|
+
* Do not move this file without first moving settings.ts out of lib-ts/.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import * as fs from "node:fs";
|
|
12
|
+
import * as path from "node:path";
|
|
13
|
+
|
|
14
|
+
import type { AgentConfig } from "./types.js";
|
|
15
|
+
import { logDebug, logInfo, logWarn } from "../../_shared/lib-ts/base/logger.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Extract simple YAML frontmatter from markdown content.
|
|
19
|
+
* Only handles flat key: value pairs (no nested YAML).
|
|
20
|
+
*/
|
|
21
|
+
export function extractFrontmatter(
|
|
22
|
+
content: string,
|
|
23
|
+
): Record<string, unknown> | null {
|
|
24
|
+
const lines = content.split(/\r?\n/);
|
|
25
|
+
if (lines[0]?.trim() !== "---") return null;
|
|
26
|
+
|
|
27
|
+
const frontmatterLines: string[] = [];
|
|
28
|
+
let endIndex = -1;
|
|
29
|
+
|
|
30
|
+
for (let i = 1; i < lines.length; i++) {
|
|
31
|
+
if (lines[i]?.trim() === "---") {
|
|
32
|
+
endIndex = i;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
const line = lines[i];
|
|
36
|
+
if (line !== undefined) {
|
|
37
|
+
frontmatterLines.push(line);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (endIndex === -1) return null;
|
|
42
|
+
|
|
43
|
+
const result: Record<string, unknown> = {};
|
|
44
|
+
for (const line of frontmatterLines) {
|
|
45
|
+
const colonIdx = line.indexOf(":");
|
|
46
|
+
if (colonIdx === -1) continue;
|
|
47
|
+
|
|
48
|
+
const key = line.slice(0, colonIdx).trim();
|
|
49
|
+
let value: unknown = line.slice(colonIdx + 1).trim();
|
|
50
|
+
|
|
51
|
+
// Handle arrays: [item1, item2]
|
|
52
|
+
if (typeof value === "string" && value.startsWith("[") && value.endsWith("]")) {
|
|
53
|
+
value = value
|
|
54
|
+
.slice(1, -1)
|
|
55
|
+
.split(",")
|
|
56
|
+
.map((s) => s.trim().replaceAll(/^["']|["']$/g, ""))
|
|
57
|
+
.filter(Boolean);
|
|
58
|
+
}
|
|
59
|
+
// Handle booleans
|
|
60
|
+
else if (value === "true") value = true;
|
|
61
|
+
else if (value === "false") value = false;
|
|
62
|
+
// Handle quoted strings
|
|
63
|
+
else if (
|
|
64
|
+
typeof value === "string" &&
|
|
65
|
+
((value.startsWith('"') && value.endsWith('"')) ||
|
|
66
|
+
(value.startsWith("'") && value.endsWith("'")))
|
|
67
|
+
) {
|
|
68
|
+
value = value.slice(1, -1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (key) result[key] = value;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Extract markdown body after frontmatter.
|
|
79
|
+
*/
|
|
80
|
+
export function extractBody(content: string): string {
|
|
81
|
+
const lines = content.split(/\r?\n/);
|
|
82
|
+
if (lines[0]?.trim() !== "---") return content;
|
|
83
|
+
|
|
84
|
+
for (let i = 1; i < lines.length; i++) {
|
|
85
|
+
if (lines[i]?.trim() === "---") {
|
|
86
|
+
return lines
|
|
87
|
+
.slice(i + 1)
|
|
88
|
+
.join("\n")
|
|
89
|
+
.trim();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return content;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Discover and load all agent configs from a directory of markdown files.
|
|
98
|
+
* Skips the plan-orchestrator agent. Defaults categories to ["code"].
|
|
99
|
+
*
|
|
100
|
+
* @param agentsDir - Path to agents directory. Callers must pass an explicit path.
|
|
101
|
+
* Known call sites: settings.ts → plan-review/agents/plan-review,
|
|
102
|
+
* plan-questions.ts → plan-review/agents/plan-questions
|
|
103
|
+
* @returns Array of AgentConfig objects
|
|
104
|
+
*/
|
|
105
|
+
export function aggregateAgents(agentsDir?: string): AgentConfig[] {
|
|
106
|
+
const dir = agentsDir ?? path.join("_cc-native", "plan-review", "agents");
|
|
107
|
+
|
|
108
|
+
if (!fs.existsSync(dir)) {
|
|
109
|
+
logWarn("aggregate", `Agents directory not found: ${dir}`);
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const files = fs
|
|
114
|
+
.readdirSync(dir)
|
|
115
|
+
.filter((f) => f.endsWith(".md"))
|
|
116
|
+
.sort();
|
|
117
|
+
|
|
118
|
+
const agents: AgentConfig[] = [];
|
|
119
|
+
|
|
120
|
+
for (const file of files) {
|
|
121
|
+
const filePath = path.join(dir, file);
|
|
122
|
+
let content: string;
|
|
123
|
+
try {
|
|
124
|
+
content = fs.readFileSync(filePath, "utf-8");
|
|
125
|
+
} catch (error: unknown) {
|
|
126
|
+
logWarn("aggregate", `Failed to read ${file}: ${error}`);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const fm = extractFrontmatter(content);
|
|
131
|
+
if (!fm) {
|
|
132
|
+
logDebug("aggregate", `No frontmatter in ${file}, skipping`);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const name = (fm.name as string) ?? path.basename(file, ".md");
|
|
137
|
+
|
|
138
|
+
// Skip the plan orchestrator — it's not a reviewer
|
|
139
|
+
if (name === "plan-orchestrator") {
|
|
140
|
+
logDebug("aggregate", `Skipping plan-orchestrator agent`);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const agent: AgentConfig = {
|
|
145
|
+
name,
|
|
146
|
+
model: (fm.model as string) ?? "sonnet",
|
|
147
|
+
provider: "claude", // Default; overwritten by assignModelsToAgents() at runtime
|
|
148
|
+
focus: (fm.focus as string) ?? "",
|
|
149
|
+
categories: Array.isArray(fm.categories)
|
|
150
|
+
? (fm.categories as string[])
|
|
151
|
+
: ["code"],
|
|
152
|
+
description: (fm.description as string) ?? "",
|
|
153
|
+
system_prompt: extractBody(content),
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
agents.push(agent);
|
|
157
|
+
logDebug("aggregate", `Loaded agent: ${agent.name} [${agent.categories.join(", ")}]`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
logInfo("aggregate", `Loaded ${agents.length} agents from ${dir}`);
|
|
161
|
+
return agents;
|
|
162
|
+
}
|
|
163
|
+
|
|
@@ -4,16 +4,15 @@
|
|
|
4
4
|
* See cc-native-plan-review-spec.md §4.5
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { getContextBySessionId, saveState } from "../../_shared/lib-ts/context/context-store.js";
|
|
8
|
-
import { logInfo, logWarn } from "../../_shared/lib-ts/base/logger.js";
|
|
9
|
-
import { nowIso } from "../../_shared/lib-ts/base/utils.js";
|
|
10
7
|
import type {
|
|
11
8
|
CcNativeState,
|
|
12
9
|
PlanReviewState,
|
|
13
|
-
QuestionsAskedState,
|
|
14
10
|
IterationState,
|
|
15
11
|
StuckDetectionState,
|
|
16
12
|
} from "./types.js";
|
|
13
|
+
import { logInfo, logWarn } from "../../_shared/lib-ts/base/logger.js";
|
|
14
|
+
import { nowIso } from "../../_shared/lib-ts/base/utils.js";
|
|
15
|
+
import { getContextBySessionId, saveState } from "../../_shared/lib-ts/context/context-store.js";
|
|
17
16
|
import type { ContextState } from "../../_shared/lib-ts/types.js";
|
|
18
17
|
|
|
19
18
|
/**
|
|
@@ -62,8 +61,8 @@ export function saveCcNativeState(
|
|
|
62
61
|
saveState(state.id, state, projectRoot);
|
|
63
62
|
return true;
|
|
64
63
|
}
|
|
65
|
-
} catch (
|
|
66
|
-
logWarn("utils", `Failed to save cc_native state: ${
|
|
64
|
+
} catch (error: unknown) {
|
|
65
|
+
logWarn("utils", `Failed to save cc_native state: ${error}`);
|
|
67
66
|
}
|
|
68
67
|
return false;
|
|
69
68
|
}
|
|
@@ -145,9 +144,9 @@ export function markPlanReviewed(
|
|
|
145
144
|
max: iterationState.max ?? 1,
|
|
146
145
|
complexity: iterationState.complexity ?? "unknown",
|
|
147
146
|
};
|
|
148
|
-
const history = iterationState
|
|
147
|
+
const {history} = iterationState;
|
|
149
148
|
if (history && history.length > 0) {
|
|
150
|
-
const lastEntry = history
|
|
149
|
+
const lastEntry = history.at(-1);
|
|
151
150
|
if (lastEntry) {
|
|
152
151
|
reviewData.iteration.latest_verdict = lastEntry.verdict ?? "unknown";
|
|
153
152
|
}
|
|
@@ -167,8 +166,8 @@ export function markPlanReviewed(
|
|
|
167
166
|
`Failed to save plan review state for session ${sessionId}`,
|
|
168
167
|
);
|
|
169
168
|
}
|
|
170
|
-
} catch (
|
|
171
|
-
logWarn(hookName, `Failed to mark plan reviewed: ${
|
|
169
|
+
} catch (error: unknown) {
|
|
170
|
+
logWarn(hookName, `Failed to mark plan reviewed: ${error}`);
|
|
172
171
|
}
|
|
173
172
|
}
|
|
174
173
|
|
|
@@ -255,8 +254,8 @@ export function markQuestionsAsked(
|
|
|
255
254
|
ccNative.questions_asked.asked_at = timestamp;
|
|
256
255
|
|
|
257
256
|
return saveCcNativeState(sessionId, projectRoot, ccNative);
|
|
258
|
-
} catch (
|
|
259
|
-
logWarn("utils", `Failed to mark questions asked: ${
|
|
257
|
+
} catch (error: unknown) {
|
|
258
|
+
logWarn("utils", `Failed to mark questions asked: ${error}`);
|
|
260
259
|
return false;
|
|
261
260
|
}
|
|
262
261
|
}
|
|
@@ -278,8 +277,8 @@ export function resetPlanQuestionsAsked(
|
|
|
278
277
|
};
|
|
279
278
|
}
|
|
280
279
|
return saveCcNativeState(sessionId, projectRoot, ccNative);
|
|
281
|
-
} catch (
|
|
282
|
-
logWarn("utils", `Failed to reset plan questions asked: ${
|
|
280
|
+
} catch (error: unknown) {
|
|
281
|
+
logWarn("utils", `Failed to reset plan questions asked: ${error}`);
|
|
283
282
|
return false;
|
|
284
283
|
}
|
|
285
284
|
}
|
|
@@ -311,8 +310,8 @@ export function updateStuckDetectionState(
|
|
|
311
310
|
const ccNative = getCcNativeState(sessionId, projectRoot) ?? {};
|
|
312
311
|
ccNative.stuck_detection = stuckState;
|
|
313
312
|
return saveCcNativeState(sessionId, projectRoot, ccNative);
|
|
314
|
-
} catch (
|
|
315
|
-
logWarn("utils", `Failed to update stuck detection state: ${
|
|
313
|
+
} catch (error: unknown) {
|
|
314
|
+
logWarn("utils", `Failed to update stuck detection state: ${error}`);
|
|
316
315
|
return false;
|
|
317
316
|
}
|
|
318
317
|
}
|