@oriro/orirocli 0.1.9 → 0.1.12

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.
Files changed (166) hide show
  1. package/README.md +16 -18
  2. package/dist/cli.js +4776 -2964
  3. package/package.json +2 -2
  4. package/skills/craft/ai-engineering/SKILL.md +2 -2
  5. package/skills/graphify/SKILL.md +0 -619
  6. package/skills/graphify/__init__.py +0 -28
  7. package/skills/graphify/__main__.py +0 -4582
  8. package/skills/graphify/affected.py +0 -154
  9. package/skills/graphify/always_on/agents-md.md +0 -12
  10. package/skills/graphify/always_on/antigravity-rules.md +0 -14
  11. package/skills/graphify/always_on/claude-md.md +0 -9
  12. package/skills/graphify/always_on/gemini-md.md +0 -9
  13. package/skills/graphify/always_on/kiro-steering.md +0 -5
  14. package/skills/graphify/always_on/vscode-instructions.md +0 -17
  15. package/skills/graphify/analyze.py +0 -724
  16. package/skills/graphify/benchmark.py +0 -155
  17. package/skills/graphify/build.py +0 -487
  18. package/skills/graphify/cache.py +0 -417
  19. package/skills/graphify/callflow_html.py +0 -2020
  20. package/skills/graphify/cluster.py +0 -272
  21. package/skills/graphify/command-kilo.md +0 -15
  22. package/skills/graphify/dedup.py +0 -429
  23. package/skills/graphify/detect.py +0 -1379
  24. package/skills/graphify/diagnostics.py +0 -390
  25. package/skills/graphify/export.py +0 -1408
  26. package/skills/graphify/extract.py +0 -11570
  27. package/skills/graphify/global_graph.py +0 -159
  28. package/skills/graphify/google_workspace.py +0 -223
  29. package/skills/graphify/hooks.py +0 -457
  30. package/skills/graphify/ingest.py +0 -331
  31. package/skills/graphify/llm.py +0 -1896
  32. package/skills/graphify/manifest.py +0 -4
  33. package/skills/graphify/mcp_ingest.py +0 -392
  34. package/skills/graphify/multigraph_compat.py +0 -212
  35. package/skills/graphify/pg_introspect.py +0 -142
  36. package/skills/graphify/prs.py +0 -748
  37. package/skills/graphify/querylog.py +0 -70
  38. package/skills/graphify/report.py +0 -218
  39. package/skills/graphify/scip_ingest.py +0 -363
  40. package/skills/graphify/security.py +0 -336
  41. package/skills/graphify/semantic_cleanup.py +0 -319
  42. package/skills/graphify/serve.py +0 -1309
  43. package/skills/graphify/skill-aider.md +0 -1246
  44. package/skills/graphify/skill-amp.md +0 -613
  45. package/skills/graphify/skill-claw.md +0 -616
  46. package/skills/graphify/skill-codex.md +0 -613
  47. package/skills/graphify/skill-copilot.md +0 -616
  48. package/skills/graphify/skill-devin.md +0 -1372
  49. package/skills/graphify/skill-droid.md +0 -613
  50. package/skills/graphify/skill-kilo.md +0 -625
  51. package/skills/graphify/skill-kiro.md +0 -615
  52. package/skills/graphify/skill-opencode.md +0 -608
  53. package/skills/graphify/skill-pi.md +0 -615
  54. package/skills/graphify/skill-trae.md +0 -614
  55. package/skills/graphify/skill-vscode.md +0 -612
  56. package/skills/graphify/skill-windows.md +0 -651
  57. package/skills/graphify/skills/amp/references/add-watch.md +0 -56
  58. package/skills/graphify/skills/amp/references/exports.md +0 -71
  59. package/skills/graphify/skills/amp/references/extraction-spec.md +0 -68
  60. package/skills/graphify/skills/amp/references/github-and-merge.md +0 -46
  61. package/skills/graphify/skills/amp/references/hooks.md +0 -33
  62. package/skills/graphify/skills/amp/references/query.md +0 -249
  63. package/skills/graphify/skills/amp/references/transcribe.md +0 -48
  64. package/skills/graphify/skills/amp/references/update.md +0 -179
  65. package/skills/graphify/skills/claude/references/add-watch.md +0 -56
  66. package/skills/graphify/skills/claude/references/exports.md +0 -71
  67. package/skills/graphify/skills/claude/references/extraction-spec.md +0 -68
  68. package/skills/graphify/skills/claude/references/github-and-merge.md +0 -46
  69. package/skills/graphify/skills/claude/references/hooks.md +0 -33
  70. package/skills/graphify/skills/claude/references/query.md +0 -103
  71. package/skills/graphify/skills/claude/references/transcribe.md +0 -48
  72. package/skills/graphify/skills/claude/references/update.md +0 -179
  73. package/skills/graphify/skills/claw/references/add-watch.md +0 -56
  74. package/skills/graphify/skills/claw/references/exports.md +0 -71
  75. package/skills/graphify/skills/claw/references/extraction-spec.md +0 -29
  76. package/skills/graphify/skills/claw/references/github-and-merge.md +0 -46
  77. package/skills/graphify/skills/claw/references/hooks.md +0 -33
  78. package/skills/graphify/skills/claw/references/query.md +0 -249
  79. package/skills/graphify/skills/claw/references/transcribe.md +0 -48
  80. package/skills/graphify/skills/claw/references/update.md +0 -179
  81. package/skills/graphify/skills/codex/references/add-watch.md +0 -56
  82. package/skills/graphify/skills/codex/references/exports.md +0 -71
  83. package/skills/graphify/skills/codex/references/extraction-spec.md +0 -29
  84. package/skills/graphify/skills/codex/references/github-and-merge.md +0 -46
  85. package/skills/graphify/skills/codex/references/hooks.md +0 -33
  86. package/skills/graphify/skills/codex/references/query.md +0 -249
  87. package/skills/graphify/skills/codex/references/transcribe.md +0 -48
  88. package/skills/graphify/skills/codex/references/update.md +0 -179
  89. package/skills/graphify/skills/copilot/references/add-watch.md +0 -56
  90. package/skills/graphify/skills/copilot/references/exports.md +0 -71
  91. package/skills/graphify/skills/copilot/references/extraction-spec.md +0 -68
  92. package/skills/graphify/skills/copilot/references/github-and-merge.md +0 -46
  93. package/skills/graphify/skills/copilot/references/hooks.md +0 -33
  94. package/skills/graphify/skills/copilot/references/query.md +0 -249
  95. package/skills/graphify/skills/copilot/references/transcribe.md +0 -48
  96. package/skills/graphify/skills/copilot/references/update.md +0 -179
  97. package/skills/graphify/skills/droid/references/add-watch.md +0 -56
  98. package/skills/graphify/skills/droid/references/exports.md +0 -71
  99. package/skills/graphify/skills/droid/references/extraction-spec.md +0 -68
  100. package/skills/graphify/skills/droid/references/github-and-merge.md +0 -46
  101. package/skills/graphify/skills/droid/references/hooks.md +0 -33
  102. package/skills/graphify/skills/droid/references/query.md +0 -249
  103. package/skills/graphify/skills/droid/references/transcribe.md +0 -48
  104. package/skills/graphify/skills/droid/references/update.md +0 -179
  105. package/skills/graphify/skills/kilo/references/add-watch.md +0 -56
  106. package/skills/graphify/skills/kilo/references/exports.md +0 -71
  107. package/skills/graphify/skills/kilo/references/extraction-spec.md +0 -68
  108. package/skills/graphify/skills/kilo/references/github-and-merge.md +0 -46
  109. package/skills/graphify/skills/kilo/references/hooks.md +0 -33
  110. package/skills/graphify/skills/kilo/references/query.md +0 -249
  111. package/skills/graphify/skills/kilo/references/transcribe.md +0 -48
  112. package/skills/graphify/skills/kilo/references/update.md +0 -179
  113. package/skills/graphify/skills/kiro/references/add-watch.md +0 -56
  114. package/skills/graphify/skills/kiro/references/exports.md +0 -71
  115. package/skills/graphify/skills/kiro/references/extraction-spec.md +0 -29
  116. package/skills/graphify/skills/kiro/references/github-and-merge.md +0 -46
  117. package/skills/graphify/skills/kiro/references/hooks.md +0 -33
  118. package/skills/graphify/skills/kiro/references/query.md +0 -249
  119. package/skills/graphify/skills/kiro/references/transcribe.md +0 -48
  120. package/skills/graphify/skills/kiro/references/update.md +0 -179
  121. package/skills/graphify/skills/opencode/references/add-watch.md +0 -56
  122. package/skills/graphify/skills/opencode/references/exports.md +0 -71
  123. package/skills/graphify/skills/opencode/references/extraction-spec.md +0 -68
  124. package/skills/graphify/skills/opencode/references/github-and-merge.md +0 -46
  125. package/skills/graphify/skills/opencode/references/hooks.md +0 -33
  126. package/skills/graphify/skills/opencode/references/query.md +0 -249
  127. package/skills/graphify/skills/opencode/references/transcribe.md +0 -48
  128. package/skills/graphify/skills/opencode/references/update.md +0 -179
  129. package/skills/graphify/skills/pi/references/add-watch.md +0 -56
  130. package/skills/graphify/skills/pi/references/exports.md +0 -71
  131. package/skills/graphify/skills/pi/references/extraction-spec.md +0 -29
  132. package/skills/graphify/skills/pi/references/github-and-merge.md +0 -46
  133. package/skills/graphify/skills/pi/references/hooks.md +0 -33
  134. package/skills/graphify/skills/pi/references/query.md +0 -249
  135. package/skills/graphify/skills/pi/references/transcribe.md +0 -48
  136. package/skills/graphify/skills/pi/references/update.md +0 -179
  137. package/skills/graphify/skills/trae/references/add-watch.md +0 -56
  138. package/skills/graphify/skills/trae/references/exports.md +0 -71
  139. package/skills/graphify/skills/trae/references/extraction-spec.md +0 -68
  140. package/skills/graphify/skills/trae/references/github-and-merge.md +0 -46
  141. package/skills/graphify/skills/trae/references/hooks.md +0 -35
  142. package/skills/graphify/skills/trae/references/query.md +0 -249
  143. package/skills/graphify/skills/trae/references/transcribe.md +0 -48
  144. package/skills/graphify/skills/trae/references/update.md +0 -179
  145. package/skills/graphify/skills/vscode/references/add-watch.md +0 -56
  146. package/skills/graphify/skills/vscode/references/exports.md +0 -71
  147. package/skills/graphify/skills/vscode/references/extraction-spec.md +0 -68
  148. package/skills/graphify/skills/vscode/references/github-and-merge.md +0 -46
  149. package/skills/graphify/skills/vscode/references/hooks.md +0 -33
  150. package/skills/graphify/skills/vscode/references/query.md +0 -249
  151. package/skills/graphify/skills/vscode/references/transcribe.md +0 -48
  152. package/skills/graphify/skills/vscode/references/update.md +0 -179
  153. package/skills/graphify/skills/windows/references/add-watch.md +0 -56
  154. package/skills/graphify/skills/windows/references/exports.md +0 -71
  155. package/skills/graphify/skills/windows/references/extraction-spec.md +0 -68
  156. package/skills/graphify/skills/windows/references/github-and-merge.md +0 -46
  157. package/skills/graphify/skills/windows/references/hooks.md +0 -33
  158. package/skills/graphify/skills/windows/references/query.md +0 -249
  159. package/skills/graphify/skills/windows/references/transcribe.md +0 -48
  160. package/skills/graphify/skills/windows/references/update.md +0 -179
  161. package/skills/graphify/symbol_resolution.py +0 -538
  162. package/skills/graphify/transcribe.py +0 -184
  163. package/skills/graphify/tree_html.py +0 -582
  164. package/skills/graphify/validate.py +0 -72
  165. package/skills/graphify/watch.py +0 -898
  166. package/skills/graphify/wiki.py +0 -282
@@ -1,249 +0,0 @@
1
- # graphify reference: query, path, explain
2
-
3
- Load this when the user asks a question against an existing graph, or runs `/graphify path` or `/graphify explain`. The core's query stub points here for the full traversal flow. These flows use the `graphify query` CLI when it is available and fall back to an inline NetworkX traversal otherwise.
4
-
5
- Two traversal modes - choose based on the question:
6
-
7
- | Mode | Flag | Best for |
8
- |------|------|----------|
9
- | BFS (default) | _(none)_ | "What is X connected to?" - broad context, nearest neighbors first |
10
- | DFS | `--dfs` | "How does X reach Y?" - trace a specific chain or dependency path |
11
-
12
- First check the graph exists:
13
- ```bash
14
- $(cat graphify-out/.graphify_python) -c "
15
- from pathlib import Path
16
- if not Path('graphify-out/graph.json').exists():
17
- print('ERROR: No graph found. Run /graphify <path> first to build the graph.')
18
- raise SystemExit(1)
19
- "
20
- ```
21
- If it fails, stop and tell the user to run `/graphify <path>` first.
22
-
23
- Prefer the CLI when it is installed:
24
- ```bash
25
- graphify query "QUESTION"
26
- # or: graphify query "QUESTION" --dfs --budget 3000
27
- ```
28
-
29
- If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal inline:
30
-
31
- 1. Find the 1-3 nodes whose label best matches key terms in the question.
32
- 2. Run the appropriate traversal from each starting node.
33
- 3. Read the subgraph - node labels, edge relations, confidence tags, source locations.
34
- 4. Answer using **only** what the graph contains. Quote `source_location` when citing a specific fact.
35
- 5. If the graph lacks enough information, say so - do not hallucinate edges.
36
-
37
- ```bash
38
- $(cat graphify-out/.graphify_python) -c "
39
- import sys, json
40
- from networkx.readwrite import json_graph
41
- import networkx as nx
42
- from pathlib import Path
43
-
44
- data = json.loads(Path('graphify-out/graph.json').read_text())
45
- G = json_graph.node_link_graph(data, edges='links')
46
-
47
- question = 'QUESTION'
48
- mode = 'MODE' # 'bfs' or 'dfs'
49
- terms = [t.lower() for t in question.split() if len(t) > 3]
50
-
51
- # Find best-matching start nodes
52
- scored = []
53
- for nid, ndata in G.nodes(data=True):
54
- label = ndata.get('label', '').lower()
55
- score = sum(1 for t in terms if t in label)
56
- if score > 0:
57
- scored.append((score, nid))
58
- scored.sort(reverse=True)
59
- start_nodes = [nid for _, nid in scored[:3]]
60
-
61
- if not start_nodes:
62
- print('No matching nodes found for query terms:', terms)
63
- sys.exit(0)
64
-
65
- subgraph_nodes = set()
66
- subgraph_edges = []
67
-
68
- if mode == 'dfs':
69
- # DFS: follow one path as deep as possible before backtracking.
70
- # Depth-limited to 6 to avoid traversing the whole graph.
71
- visited = set()
72
- stack = [(n, 0) for n in reversed(start_nodes)]
73
- while stack:
74
- node, depth = stack.pop()
75
- if node in visited or depth > 6:
76
- continue
77
- visited.add(node)
78
- subgraph_nodes.add(node)
79
- for neighbor in G.neighbors(node):
80
- if neighbor not in visited:
81
- stack.append((neighbor, depth + 1))
82
- subgraph_edges.append((node, neighbor))
83
- else:
84
- # BFS: explore all neighbors layer by layer up to depth 3.
85
- frontier = set(start_nodes)
86
- subgraph_nodes = set(start_nodes)
87
- for _ in range(3):
88
- next_frontier = set()
89
- for n in frontier:
90
- for neighbor in G.neighbors(n):
91
- if neighbor not in subgraph_nodes:
92
- next_frontier.add(neighbor)
93
- subgraph_edges.append((n, neighbor))
94
- subgraph_nodes.update(next_frontier)
95
- frontier = next_frontier
96
-
97
- # Token-budget aware output: rank by relevance, cut at budget (~4 chars/token)
98
- token_budget = BUDGET # default 2000
99
- char_budget = token_budget * 4
100
-
101
- # Score each node by term overlap for ranked output
102
- def relevance(nid):
103
- label = G.nodes[nid].get('label', '').lower()
104
- return sum(1 for t in terms if t in label)
105
-
106
- ranked_nodes = sorted(subgraph_nodes, key=relevance, reverse=True)
107
-
108
- lines = [f'Traversal: {mode.upper()} | Start: {[G.nodes[n].get(\"label\",n) for n in start_nodes]} | {len(subgraph_nodes)} nodes']
109
- for nid in ranked_nodes:
110
- d = G.nodes[nid]
111
- lines.append(f' NODE {d.get(\"label\", nid)} [src={d.get(\"source_file\",\"\")} loc={d.get(\"source_location\",\"\")}]')
112
- for u, v in subgraph_edges:
113
- if u in subgraph_nodes and v in subgraph_nodes:
114
- _raw = G[u][v]; d = next(iter(_raw.values()), {}) if isinstance(G, nx.MultiGraph) else _raw
115
- lines.append(f' EDGE {G.nodes[u].get(\"label\",u)} --{d.get(\"relation\",\"\")} [{d.get(\"confidence\",\"\")}]--> {G.nodes[v].get(\"label\",v)}')
116
-
117
- output = '\n'.join(lines)
118
- if len(output) > char_budget:
119
- output = output[:char_budget] + f'\n... (truncated at ~{token_budget} token budget - use --budget N for more)'
120
- print(output)
121
- "
122
- ```
123
-
124
- Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, and `BUDGET` with the token budget (default `2000`, or whatever `--budget N` specifies). Then answer based on the subgraph output above.
125
-
126
- After writing the answer, save it back into the graph so it improves future queries:
127
-
128
- ```bash
129
- $(cat graphify-out/.graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2
130
- ```
131
-
132
- Replace `QUESTION` with the user's verbatim question, `ANSWER` with your full answer text, and the node list with the labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph.
133
-
134
- ---
135
-
136
- ## For /graphify path
137
-
138
- Find the shortest path between two named concepts in the graph.
139
-
140
- ```bash
141
- $(cat graphify-out/.graphify_python) -c "
142
- import json, sys
143
- import networkx as nx
144
- from networkx.readwrite import json_graph
145
- from pathlib import Path
146
-
147
- data = json.loads(Path('graphify-out/graph.json').read_text())
148
- G = json_graph.node_link_graph(data, edges='links')
149
-
150
- a_term = 'NODE_A'
151
- b_term = 'NODE_B'
152
-
153
- def find_node(term):
154
- term = term.lower()
155
- scored = sorted(
156
- [(sum(1 for w in term.split() if w in G.nodes[n].get('label','').lower()), n)
157
- for n in G.nodes()],
158
- reverse=True
159
- )
160
- return scored[0][1] if scored and scored[0][0] > 0 else None
161
-
162
- src = find_node(a_term)
163
- tgt = find_node(b_term)
164
-
165
- if not src or not tgt:
166
- print(f'Could not find nodes matching: {a_term!r} or {b_term!r}')
167
- sys.exit(0)
168
-
169
- try:
170
- path = nx.shortest_path(G, src, tgt)
171
- print(f'Shortest path ({len(path)-1} hops):')
172
- for i, nid in enumerate(path):
173
- label = G.nodes[nid].get('label', nid)
174
- if i < len(path) - 1:
175
- _raw = G[nid][path[i+1]]; edge = next(iter(_raw.values()), {}) if isinstance(G, nx.MultiGraph) else _raw
176
- rel = edge.get('relation', '')
177
- conf = edge.get('confidence', '')
178
- print(f' {label} --{rel}--> [{conf}]')
179
- else:
180
- print(f' {label}')
181
- except nx.NetworkXNoPath:
182
- print(f'No path found between {a_term!r} and {b_term!r}')
183
- except nx.NodeNotFound as e:
184
- print(f'Node not found: {e}')
185
- "
186
- ```
187
-
188
- Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then explain the path in plain language - what each hop means, why it's significant.
189
-
190
- After writing the explanation, save it back:
191
-
192
- ```bash
193
- $(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B
194
- ```
195
-
196
- ---
197
-
198
- ## For /graphify explain
199
-
200
- Give a plain-language explanation of a single node - everything connected to it.
201
-
202
- ```bash
203
- $(cat graphify-out/.graphify_python) -c "
204
- import json, sys
205
- import networkx as nx
206
- from networkx.readwrite import json_graph
207
- from pathlib import Path
208
-
209
- data = json.loads(Path('graphify-out/graph.json').read_text())
210
- G = json_graph.node_link_graph(data, edges='links')
211
-
212
- term = 'NODE_NAME'
213
- term_lower = term.lower()
214
-
215
- # Find best matching node
216
- scored = sorted(
217
- [(sum(1 for w in term_lower.split() if w in G.nodes[n].get('label','').lower()), n)
218
- for n in G.nodes()],
219
- reverse=True
220
- )
221
- if not scored or scored[0][0] == 0:
222
- print(f'No node matching {term!r}')
223
- sys.exit(0)
224
-
225
- nid = scored[0][1]
226
- data_n = G.nodes[nid]
227
- print(f'NODE: {data_n.get(\"label\", nid)}')
228
- print(f' source: {data_n.get(\"source_file\",\"unknown\")}')
229
- print(f' type: {data_n.get(\"file_type\",\"unknown\")}')
230
- print(f' degree: {G.degree(nid)}')
231
- print()
232
- print('CONNECTIONS:')
233
- for neighbor in G.neighbors(nid):
234
- _raw = G[nid][neighbor]; edge = next(iter(_raw.values()), {}) if isinstance(G, nx.MultiGraph) else _raw
235
- nlabel = G.nodes[neighbor].get('label', neighbor)
236
- rel = edge.get('relation', '')
237
- conf = edge.get('confidence', '')
238
- src_file = G.nodes[neighbor].get('source_file', '')
239
- print(f' --{rel}--> {nlabel} [{conf}] ({src_file})')
240
- "
241
- ```
242
-
243
- Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sentence explanation of what this node is, what it connects to, and why those connections are significant. Use the source locations as citations.
244
-
245
- After writing the explanation, save it back:
246
-
247
- ```bash
248
- $(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME
249
- ```
@@ -1,48 +0,0 @@
1
- # graphify reference: transcribe video and audio
2
-
3
- Load this only when `detect` reported one or more `video` files. A corpus with no video never reads this.
4
-
5
- ### Step 2.5 - Transcribe video / audio files (only if video files detected)
6
-
7
- Skip this step entirely if `detect` returned zero `video` files.
8
-
9
- Video and audio files cannot be read directly. Transcribe them to text first, then treat the transcripts as doc files in Step 3.
10
-
11
- **Strategy:** Read the god nodes from `graphify-out/.graphify_detect.json` (or the analysis file if it exists from a previous run). You are already a language model — write a one-sentence domain hint yourself from those labels. Then pass it to Whisper as the initial prompt. No separate API call needed.
12
-
13
- **However**, if the corpus has *only* video files and no other docs/code, use the generic fallback prompt: `"Use proper punctuation and paragraph breaks."`
14
-
15
- **Step 1 - Write the Whisper prompt yourself.**
16
-
17
- Read the top god node labels from detect output or analysis, then compose a short domain hint sentence, for example:
18
-
19
- - Labels: `transformer, attention, encoder, decoder` → `"Machine learning research on transformer architectures and attention mechanisms. Use proper punctuation and paragraph breaks."`
20
- - Labels: `kubernetes, deployment, pod, helm` → `"DevOps discussion about Kubernetes deployments and Helm charts. Use proper punctuation and paragraph breaks."`
21
-
22
- Set it as `WHISPER_PROMPT` to use in the next command.
23
-
24
- **Step 2 - Transcribe:**
25
-
26
- ```bash
27
- GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed
28
- $(cat graphify-out/.graphify_python) -c "
29
- import json, os
30
- from pathlib import Path
31
- from graphify.transcribe import transcribe_all
32
-
33
- detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text(encoding=\"utf-8\"))
34
- video_files = detect.get('files', {}).get('video', [])
35
- prompt = os.environ.get('GRAPHIFY_WHISPER_PROMPT', 'Use proper punctuation and paragraph breaks.')
36
-
37
- transcript_paths = transcribe_all(video_files, initial_prompt=prompt)
38
- print(json.dumps(transcript_paths, ensure_ascii=False))
39
- " > graphify-out/.graphify_transcripts.json
40
- ```
41
-
42
- After transcription:
43
- - Read the transcript paths from `graphify-out/.graphify_transcripts.json`
44
- - Add them to the docs list before dispatching semantic subagents in Step 3B
45
- - Print how many transcripts were created: `Transcribed N video file(s) -> treating as docs`
46
- - If transcription fails for a file, print a warning and continue with the rest
47
-
48
- **Whisper model:** Default is `base`. If the user passed `--whisper-model <name>`, set `GRAPHIFY_WHISPER_MODEL=<name>` in the environment before running the command above.
@@ -1,179 +0,0 @@
1
- # graphify reference: incremental update and cluster-only
2
-
3
- Load this only when the user passed `--update` or `--cluster-only`. A first-time full build never reads this file.
4
-
5
- ## For --update (incremental re-extraction)
6
-
7
- Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time.
8
-
9
- ```bash
10
- $(cat graphify-out/.graphify_python) -c "
11
- import sys, json
12
- from graphify.detect import detect_incremental, save_manifest
13
- from pathlib import Path
14
-
15
- result = detect_incremental(Path('INPUT_PATH'))
16
- new_total = result.get('new_total', 0)
17
- print(json.dumps(result, indent=2, ensure_ascii=False))
18
- Path('graphify-out/.graphify_incremental.json').write_text(json.dumps(result, ensure_ascii=False), encoding=\"utf-8\")
19
- deleted = list(result.get('deleted_files', []))
20
- if new_total == 0 and not deleted:
21
- print('No files changed since last run. Nothing to update.')
22
- raise SystemExit(0)
23
- if deleted:
24
- print(f'{len(deleted)} deleted file(s) to prune.')
25
- if new_total > 0:
26
- print(f'{new_total} new/changed file(s) to re-extract.')
27
- "
28
- ```
29
-
30
- Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context:
31
-
32
- ```bash
33
- $(cat graphify-out/.graphify_python) -c "
34
- import json
35
- from pathlib import Path
36
- r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
37
- Path('graphify-out/.graphify_detect.json').write_text(json.dumps({
38
- 'files': r.get('new_files', {}),
39
- 'all_files': r.get('files', {}),
40
- 'total_files': r.get('new_total', 0),
41
- 'total_words': r.get('total_words', 0),
42
- 'skipped_sensitive': r.get('skipped_sensitive', []),
43
- 'needs_graph': True,
44
- }, ensure_ascii=False), encoding=\"utf-8\")
45
- "
46
- ```
47
-
48
- If new files exist, first check whether all changed files are code files:
49
-
50
- ```bash
51
- $(cat graphify-out/.graphify_python) -c "
52
- import json
53
- from pathlib import Path
54
-
55
- result = json.loads(open('graphify-out/.graphify_incremental.json', encoding='utf-8').read()) if Path('graphify-out/.graphify_incremental.json').exists() else {}
56
- code_exts = {'.py','.ts','.js','.go','.rs','.java','.cpp','.c','.rb','.swift','.kt','.cs','.scala','.php','.cc','.cxx','.hpp','.h','.kts','.lua','.toc','.f','.F','.f90','.F90','.f95','.F95','.f03','.F03','.f08','.F08'}
57
- new_files = result.get('new_files', {})
58
- all_changed = [f for files in new_files.values() for f in files]
59
- code_only = all(Path(f).suffix.lower() in code_exts for f in all_changed)
60
- print('code_only:', code_only)
61
- "
62
- ```
63
-
64
- If `code_only` is True: print `[graphify update] Code-only changes detected - skipping semantic extraction (no LLM needed)`, run only Step 3A (AST) on the changed files, skip Step 3B entirely (no subagents), then go straight to merge and Steps 4–8.
65
-
66
- If `code_only` is False (any changed file is a doc/paper/image): run the full Steps 3A–3C pipeline as normal.
67
-
68
-
69
- If no new files exist (only deletions), create an empty extraction so the merge step can prune:
70
-
71
- ```bash
72
- if [ ! -f graphify-out/.graphify_extract.json ]; then
73
- echo '[graphify update] Only deletions -- creating empty extraction for merge.'
74
- $(cat graphify-out/.graphify_python) -c "
75
- import json
76
- from pathlib import Path
77
- Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8')
78
- "
79
- fi
80
- ```
81
-
82
-
83
- Then:
84
-
85
- ```bash
86
- $(cat graphify-out/.graphify_python) -c "
87
- import json
88
- from pathlib import Path
89
- from graphify.build import build_merge
90
- from graphify.detect import save_manifest
91
-
92
- # Load new extraction and incremental state
93
- new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
94
- incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
95
- deleted = list(incremental.get('deleted_files', []))
96
- # Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
97
- # Without this, build_merge's dedup pass tries to reconcile old and new versions of
98
- # the same file's nodes and can collapse same-named symbols across files (#1178).
99
- changed = [f for files in incremental.get('new_files', {}).values() for f in files]
100
- prune = list(dict.fromkeys(deleted + changed)) or None
101
-
102
- # Use build_merge() — reads graph.json directly without NetworkX round-trip
103
- # so edge direction (calls, implements, imports) is always preserved (#801).
104
- G = build_merge(
105
- [new_extraction],
106
- graph_path='graphify-out/graph.json',
107
- prune_sources=prune,
108
- )
109
- print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
110
-
111
- # Write merged result back to .graphify_extract.json so Step 4 sees the full graph
112
- merged_out = {
113
- 'nodes': [{'id': n, **d} for n, d in G.nodes(data=True)],
114
- 'edges': [
115
- # Explicit source/target last so they win over any stale attrs in d.
116
- {**{k: val for k, val in d.items() if k not in ('_src', '_tgt', 'source', 'target')},
117
- 'source': d.get('_src', u), 'target': d.get('_tgt', v)}
118
- for u, v, d in G.edges(data=True)
119
- ],
120
- # G.graph["hyperedges"] holds hyperedges from both existing graph.json
121
- # and new_extraction (build_merge combines them). Falling back to
122
- # new_extraction only would silently drop prior-run hyperedges (#801).
123
- 'hyperedges': list(G.graph.get('hyperedges', [])),
124
- 'input_tokens': new_extraction.get('input_tokens', 0),
125
- 'output_tokens': new_extraction.get('output_tokens', 0),
126
- }
127
- Path('graphify-out/.graphify_extract.json').write_text(json.dumps(merged_out, ensure_ascii=False), encoding=\"utf-8\")
128
- print(f'[graphify update] Merged extraction written ({len(merged_out[\"nodes\"])} nodes, {len(merged_out[\"edges\"])} edges)')
129
-
130
- # Save manifest so next --update diffs against today's state, not the
131
- # prior run's baseline (prevents ghost-node reports on subsequent updates).
132
- save_manifest(incremental['files'])
133
- print('[graphify update] Manifest saved.')
134
- "
135
- ```
136
-
137
- Then run Steps 4–8 on the merged graph as normal.
138
-
139
- After Step 4, show the graph diff:
140
-
141
- ```bash
142
- $(cat graphify-out/.graphify_python) -c "
143
- import json
144
- from graphify.analyze import graph_diff
145
- from graphify.build import build_from_json
146
- from networkx.readwrite import json_graph
147
- import networkx as nx
148
- from pathlib import Path
149
-
150
- # Load old graph (before update) from backup written before merge
151
- old_data = json.loads(Path('graphify-out/.graphify_old.json').read_text(encoding=\"utf-8\")) if Path('graphify-out/.graphify_old.json').exists() else None
152
- new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
153
- G_new = build_from_json(new_extract)
154
-
155
- if old_data:
156
- G_old = json_graph.node_link_graph(old_data, edges='links')
157
- diff = graph_diff(G_old, G_new)
158
- print(diff['summary'])
159
- if diff['new_nodes']:
160
- print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5]))
161
- if diff['new_edges']:
162
- print('New edges:', len(diff['new_edges']))
163
- "
164
- ```
165
-
166
- Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json`
167
- Clean up after: `rm -f graphify-out/.graphify_old.json`
168
-
169
- ---
170
-
171
- ## For --cluster-only
172
-
173
- Skip Steps 1–3. Re-run clustering on the existing graph:
174
-
175
- ```bash
176
- graphify cluster-only .
177
- ```
178
-
179
- Then run Steps 5–9 as normal (label communities, generate viz, benchmark, clean up, report).