docit 0.5.0 → 0.7.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.
@@ -1,127 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "json"
4
-
5
- module Docit
6
- module Ai
7
- class SystemInsightGenerator
8
- # mode: :nodes -> explain an arbitrary selection (diagram "AI Explain")
9
- # :section -> explain one resource and how its endpoints work together
10
- def initialize(graph:, selected_node_ids: [], mode: :nodes)
11
- @graph = graph
12
- @selected_node_ids = selected_node_ids
13
- @mode = mode
14
- end
15
-
16
- def generate
17
- config = Configuration.load
18
- Client.for(config).generate(prompt)
19
- end
20
-
21
- private
22
-
23
- attr_reader :graph, :selected_node_ids, :mode
24
-
25
- def prompt
26
- mode == :section ? section_prompt : nodes_prompt
27
- end
28
-
29
- def nodes_prompt
30
- <<~PROMPT
31
- You are a senior engineer explaining a Rails system architecture to a developer. Keep your explanation extremely concise, professional, and clear. Avoid fluff, unnecessary details, or general tutorial information. Focus only on the provided components.
32
-
33
- FORMAT YOUR RESPONSE EXACTLY LIKE THIS:
34
-
35
- ## Overview
36
- A 1-2 sentence plain-English summary of what this component/action does.
37
-
38
- ## Data Flow
39
- Show a simple, linear flow diagram using text and arrows (→). Keep it to 1 line if possible.
40
- Example:
41
- Client → GET /api/v1/users → UsersController#index → queries User model
42
-
43
- ## Connections & Interactions
44
- List only the direct, relevant relationships from the graph (max 3 bullets):
45
- - **Component** (type): Action details/purpose.
46
-
47
- Do not invent or assume anything outside of the provided graph. Keep the total response under 150 words.
48
-
49
- ---
50
-
51
- Selected node ids:
52
- #{selected_node_ids.join("\n")}
53
-
54
- Graph JSON:
55
- #{JSON.pretty_generate(compact_graph)}
56
- PROMPT
57
- end
58
-
59
- def section_prompt
60
- <<~PROMPT
61
- You are a senior engineer writing the introduction to a section of API documentation. The section covers ONE resource and all of its endpoints. Explain, for a developer new to this codebase, what the resource is for and how its endpoints work together as a workflow.
62
-
63
- Use the documented summaries where available. Where an endpoint has no documentation, infer cautiously from its HTTP method and path, and do not fabricate behavior.
64
-
65
- FORMAT YOUR RESPONSE EXACTLY LIKE THIS:
66
-
67
- ## What this section does
68
- 1-2 sentences on the resource and its overall purpose.
69
-
70
- ## How the endpoints work together
71
- A short narrative (2-4 sentences) describing the typical flow across these endpoints — e.g. how a client lists, creates, then updates this resource. Reference endpoints by their HTTP method and path.
72
-
73
- ## Notes
74
- Up to 2 bullets on related models/services or anything a consumer must know. Omit this section if there is nothing concrete to say.
75
-
76
- Do not invent endpoints, fields, or behavior not present in the graph. Keep the total response under 180 words.
77
-
78
- ---
79
-
80
- Endpoint node ids in this section:
81
- #{selected_node_ids.join("\n")}
82
-
83
- Graph JSON:
84
- #{JSON.pretty_generate(compact_graph)}
85
- PROMPT
86
- end
87
-
88
- def compact_graph
89
- nodes = selected_nodes
90
- node_ids = nodes.map { |node| node[:id] }
91
-
92
- # Include edges where at least one end is in the selection
93
- related_edges = graph[:edges].select do |edge|
94
- node_ids.include?(edge[:source]) || node_ids.include?(edge[:target])
95
- end
96
-
97
- # Also include neighbor nodes (one hop away) for context
98
- neighbor_ids = Set.new(node_ids)
99
- related_edges.each do |edge|
100
- neighbor_ids.add(edge[:source])
101
- neighbor_ids.add(edge[:target])
102
- end
103
-
104
- neighbor_nodes = graph[:nodes].select { |node| neighbor_ids.include?(node[:id]) }
105
-
106
- {
107
- selected_nodes: nodes.map { |node| compact_hash(node, %i[id type label status file metadata]) },
108
- context_nodes: (neighbor_nodes - nodes).map { |node| compact_hash(node, %i[id type label status]) },
109
- edges: related_edges.map { |edge| compact_hash(edge, %i[source target type confidence evidence]) },
110
- stats: graph[:stats]
111
- }
112
- end
113
-
114
- def selected_nodes
115
- return graph[:nodes] if selected_node_ids.empty?
116
-
117
- graph[:nodes].select { |node| selected_node_ids.include?(node[:id]) }
118
- end
119
-
120
- def compact_hash(hash, keys)
121
- keys.each_with_object({}) do |key, result|
122
- result[key] = hash[key] if hash.key?(key)
123
- end
124
- end
125
- end
126
- end
127
- end