1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
6#[serde(rename_all = "lowercase")]
7pub enum Task {
8 Summary,
9 Guide,
10 Flow,
11}
12
13impl Task {
14 pub const ALL: [Task; 3] = [Task::Summary, Task::Guide, Task::Flow];
15
16 pub fn name(self) -> &'static str {
17 match self {
18 Task::Summary => "summary",
19 Task::Guide => "guide",
20 Task::Flow => "flow",
21 }
22 }
23
24 pub fn parse(s: &str) -> Option<Task> {
25 Task::ALL.into_iter().find(|t| t.name() == s)
26 }
27
28 pub fn builtin(self) -> &'static str {
30 match self {
31 Task::Summary => "You document code for a search index.",
32 Task::Guide => {
33 "You are a senior engineer documenting ONE section of a codebase's house-style \
34 guide so an AI coding agent writes code INDISTINGUISHABLE from this repo's. You are \
35 given REAL evidence (signatures, code excerpts, dependency facts, measured stats) for \
36 this section only. Make the repo's tacit conventions explicit.\n\
37 Hard rules:\n\
38 - Cite a real FILE PATH (and symbol/signature) for every non-trivial claim; quote a \
39 short real snippet as the example. Where useful, show a correct vs incorrect example.\n\
40 - Prefer the repo's OWN wrapper/abstraction over a raw library when the evidence \
41 shows one; name it exactly.\n\
42 - NEVER output generic advice that would apply to any codebase ('use meaningful \
43 names', 'write tests', 'handle errors gracefully'). Delete such lines.\n\
44 - Strength tags: **MUST**/**NEVER** for patterns across ≥3 files or enforced by \
45 config; 'prefer' for weaker signals. Give a one-line reason where non-obvious."
46 }
47 Task::Flow => {
48 "You explain how a code flow works to a developer new to the codebase. The \
49 narration is a 2-5 sentence walkthrough of what happens step by step, referencing \
50 the actual symbol names."
51 }
52 }
53 }
54
55 pub fn format(self) -> &'static str {
57 match self {
58 Task::Summary => {
59 "Reply as JSON: \"summary\" is one concise sentence describing what this does; \
60 \"queries\" are 3 natural-language questions a developer might ask that this code \
61 answers."
62 }
63 Task::Guide => {
64 "Reply as JSON: \"rules\" holds this section's rules, one terse markdown rule per \
65 item, with no heading, preamble or closing note; \"observed\" is false, with no \
66 rules, when the evidence shows no consistent convention."
67 }
68 Task::Flow => {
69 "You get an entry point and its call trace (each line: depth, relation, symbol, \
70 location). Reply as JSON: \"narration\" is the walkthrough; \"queries\" are 3 \
71 questions a developer might ask about this flow."
72 }
73 }
74 }
75}
76
77#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
79pub struct Version {
80 pub task: Task,
81 pub version: u32,
82 pub text: String,
83 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
85 pub sections: BTreeMap<String, String>,
86 #[serde(default, skip_serializing_if = "Option::is_none")]
87 pub note: Option<String>,
88 pub author: String,
89 pub created_at: String,
90 #[serde(default, skip_serializing_if = "Option::is_none")]
92 pub based_on: Option<String>,
93}