opencode-codegraph 0.1.6 → 0.1.8

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.8 - 2026-03-20
4
+
5
+ - add normalized workflow states (`refresh_needed`, `trace_pending`, `review_required`, `ready_to_continue`) across dogfooding status and review trace flows
6
+ - surface a recommended command alongside next-action guidance in session-start, status, and post-commit summaries
7
+ - align `/review`, `/audit`, and `/update` around the same status-derived command guidance
8
+
9
+ ## 0.1.7 - 2026-03-20
10
+
11
+ - add command-oriented next-step guidance (`/status`, `/update`, `/review`) to review-trace and dogfooding status flows
12
+ - unify `/review`, `/audit`, and `/update` around the shared `dogfood status --json` backend
13
+ - keep session-start and post-commit guidance aligned on the same recommended command semantics
14
+
3
15
  ## 0.1.6 - 2026-03-20
4
16
 
5
17
  - add explicit pending post-commit summary when durable review trace is not yet available
package/README.md CHANGED
@@ -39,9 +39,14 @@ Plugin injects:
39
39
 
40
40
  If the message also suggests an edit intent (`refactor`, `fix`, `modify`, `update`, etc.), the plugin appends a pre-edit warning block with complexity, fan-out, dead-code, and security hints for the referenced file.
41
41
 
42
- ### System Prompt
43
-
44
- Every conversation includes a project summary with file count, top complexity hotspots, and open security findings.
42
+ ### System Prompt
43
+
44
+ Every conversation includes:
45
+
46
+ - a project summary with file count, top complexity hotspots, and open security findings;
47
+ - a lightweight dogfooding status block when available, including freshness, current `HEAD`, review-trace state, and recommended next action.
48
+ - a recommended command (`/status`, `/update`, or `/review`) when the workflow can point to a deterministic next step.
49
+ - a normalized workflow state so the session can distinguish `refresh_needed`, `trace_pending`, `review_required`, and `ready_to_continue`.
45
50
 
46
51
  ### Post-Commit Updates
47
52
 
@@ -51,6 +56,8 @@ After `git commit`, the plugin triggers incremental CPG re-parsing via GoCPG and
51
56
  - why it matters
52
57
  - top recommendations
53
58
  - one clear next action
59
+ - one suggested command to run next
60
+ - one normalized workflow state
54
61
 
55
62
  If the durable review trace is not available yet, the plugin still appends a pending summary telling the developer to check `/status` instead of leaving the post-commit state ambiguous.
56
63
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-codegraph",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "OpenCode plugin for CodeGraph CPG-powered code analysis",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/index.ts CHANGED
@@ -17,13 +17,16 @@ import { CodeGraphAPI } from "./api"
17
17
  import {
18
18
  extractFileRefs,
19
19
  fileNeedsRegistrationCheck,
20
+ formatDogfoodStatusSummary,
20
21
  formatPendingReviewTraceSummary,
21
22
  formatReviewTraceSummary,
22
23
  getHeadCommit,
23
24
  isGitCommit,
24
25
  messageSuggestsEditing,
26
+ recommendedCommandFromReviewTrace,
25
27
  recommendedNextActionFromReviewTrace,
26
28
  readReviewTraceSnapshot,
29
+ workflowStateFromReviewTrace,
27
30
  whatChangedFromReviewTrace,
28
31
  whyItMattersFromReviewTrace,
29
32
  } from "./util"
@@ -42,16 +45,26 @@ const codegraphPlugin: Plugin = async (input) => {
42
45
  // -----------------------------------------------------------------
43
46
  // 1. System prompt: inject CPG project summary
44
47
  // -----------------------------------------------------------------
45
- "experimental.chat.system.transform": async (_inp, output) => {
46
- try {
47
- const summary = await api.getProjectSummary(projectId)
48
- if (summary) {
49
- output.system.push(summary)
50
- }
51
- } catch {
52
- // CodeGraph API not available — skip silently
53
- }
54
- },
48
+ "experimental.chat.system.transform": async (_inp, output) => {
49
+ try {
50
+ const rawStatus = await $`python -m src.cli.import_commands dogfood status --json`.quiet().text()
51
+ const statusSummary = formatDogfoodStatusSummary(JSON.parse(rawStatus))
52
+ if (statusSummary) {
53
+ output.system.push(statusSummary)
54
+ }
55
+ } catch {
56
+ // Dogfooding status unavailable — keep session startup lightweight
57
+ }
58
+
59
+ try {
60
+ const summary = await api.getProjectSummary(projectId)
61
+ if (summary) {
62
+ output.system.push(summary)
63
+ }
64
+ } catch {
65
+ // CodeGraph API not available — skip silently
66
+ }
67
+ },
55
68
 
56
69
  // -----------------------------------------------------------------
57
70
  // 2. Chat message: auto-enrich with CPG context for mentioned files
@@ -112,11 +125,15 @@ const codegraphPlugin: Plugin = async (input) => {
112
125
  output.metadata = {
113
126
  ...output.metadata,
114
127
  codegraph_review_trace_status: traceSnapshot.status || "unknown",
128
+ codegraph_review_trace_workflow_state:
129
+ traceSnapshot.workflow_state || workflowStateFromReviewTrace(traceSnapshot),
115
130
  codegraph_review_trace_phase: traceSnapshot.phase || "unknown",
116
131
  codegraph_review_trace_findings: traceSnapshot.review_findings_count ?? null,
117
132
  codegraph_review_trace_recommendations:
118
133
  traceSnapshot.review_recommendations?.slice(0, 3) || [],
119
134
  codegraph_review_trace_next_action: recommendedNextActionFromReviewTrace(traceSnapshot),
135
+ codegraph_review_trace_recommended_command:
136
+ traceSnapshot.recommended_command || recommendedCommandFromReviewTrace(traceSnapshot),
120
137
  codegraph_review_trace_what_changed: whatChangedFromReviewTrace(traceSnapshot),
121
138
  codegraph_review_trace_why_it_matters: whyItMattersFromReviewTrace(traceSnapshot),
122
139
  }
@@ -125,11 +142,13 @@ const codegraphPlugin: Plugin = async (input) => {
125
142
  output.metadata = {
126
143
  ...output.metadata,
127
144
  codegraph_review_trace_status: "pending_or_missing",
145
+ codegraph_review_trace_workflow_state: "trace_pending",
128
146
  codegraph_review_trace_phase: "awaiting_trace",
129
147
  codegraph_review_trace_findings: null,
130
148
  codegraph_review_trace_recommendations: [],
131
149
  codegraph_review_trace_next_action:
132
150
  "Wait briefly for review trace completion, then run /status to check the latest result.",
151
+ codegraph_review_trace_recommended_command: "/status",
133
152
  codegraph_review_trace_what_changed: [
134
153
  `Incremental CPG update was triggered for ${commit.slice(0, 12)}.`,
135
154
  "Durable review trace is not available yet or has not been written.",
package/src/util.ts CHANGED
@@ -14,6 +14,22 @@ export type ReviewTraceSnapshot = {
14
14
  review_severity_counts?: Record<string, number>
15
15
  review_recommendations?: string[]
16
16
  error?: string | null
17
+ workflow_state?: string
18
+ recommended_command?: string
19
+ }
20
+
21
+ export type DogfoodStatusSnapshot = {
22
+ cpg_status?: {
23
+ is_fresh?: boolean
24
+ freshness_reason?: string
25
+ commits_behind?: number
26
+ db_exists?: boolean
27
+ }
28
+ head_commit?: string
29
+ review_trace?: ReviewTraceSnapshot | null
30
+ workflow_state?: string
31
+ recommended_next_action?: string
32
+ recommended_command?: string
17
33
  }
18
34
 
19
35
  /**
@@ -146,6 +162,8 @@ export function formatPendingReviewTraceSummary(commit: string | null): string {
146
162
  "### What to do now",
147
163
  "",
148
164
  "- Wait briefly for review trace completion, then run `/status` to check the latest result.",
165
+ "- Suggested command: `/status`",
166
+ "- Workflow state: `trace_pending`",
149
167
  ].join("\n")
150
168
  }
151
169
 
@@ -156,6 +174,8 @@ export function formatReviewTraceSummary(snapshot: ReviewTraceSnapshot): string
156
174
  const whatChanged = whatChangedFromReviewTrace(snapshot)
157
175
  const whyItMatters = whyItMattersFromReviewTrace(snapshot)
158
176
  const nextAction = recommendedNextActionFromReviewTrace(snapshot)
177
+ const nextCommand = recommendedCommandFromReviewTrace(snapshot)
178
+ const workflowState = workflowStateFromReviewTrace(snapshot)
159
179
 
160
180
  const lines = ["## CodeGraph Post-Commit Summary", ""]
161
181
 
@@ -176,6 +196,8 @@ export function formatReviewTraceSummary(snapshot: ReviewTraceSnapshot): string
176
196
  }
177
197
 
178
198
  lines.push("### What to do now", "", `- ${nextAction}`)
199
+ lines.push(`- Suggested command: \`${nextCommand}\``)
200
+ lines.push(`- Workflow state: \`${workflowState}\``)
179
201
 
180
202
  return lines.join("\n")
181
203
  }
@@ -236,12 +258,12 @@ export function recommendedNextActionFromReviewTrace(snapshot: ReviewTraceSnapsh
236
258
  ? snapshot.review_recommendations.filter(Boolean)
237
259
  : []
238
260
 
261
+ if (workflowStateFromReviewTrace(snapshot) === "trace_pending") {
262
+ return "Wait for review trace completion, then inspect findings and recommendations."
263
+ }
239
264
  if (snapshot.error) {
240
265
  return "Investigate the review-trace error, then run /review once the pipeline is healthy."
241
266
  }
242
- if (status === "running") {
243
- return "Wait for review trace completion, then inspect findings and recommendations."
244
- }
245
267
  if (status && status !== "completed") {
246
268
  return "Check the latest review trace status again and rerun /review if the result is incomplete."
247
269
  }
@@ -254,6 +276,83 @@ export function recommendedNextActionFromReviewTrace(snapshot: ReviewTraceSnapsh
254
276
  return "No review findings recorded; continue with /review or push once the rest of your checks are green."
255
277
  }
256
278
 
279
+ export function recommendedCommandFromReviewTrace(snapshot: ReviewTraceSnapshot): string {
280
+ const status = (snapshot.status || "").toLowerCase()
281
+ const findingsCount = snapshot.review_findings_count
282
+ const workflowState = workflowStateFromReviewTrace(snapshot)
283
+
284
+ if (workflowState === "trace_pending") {
285
+ return "/status"
286
+ }
287
+ if (snapshot.error) {
288
+ return "/review"
289
+ }
290
+ if (status && status !== "completed") {
291
+ return "/review"
292
+ }
293
+ if (typeof findingsCount === "number" && findingsCount > 0) {
294
+ return "/review"
295
+ }
296
+ return "/review"
297
+ }
298
+
299
+ export function workflowStateFromReviewTrace(snapshot: ReviewTraceSnapshot): string {
300
+ const status = (snapshot.status || "").toLowerCase()
301
+ const findingsCount = snapshot.review_findings_count
302
+
303
+ if (snapshot.error) {
304
+ return "review_required"
305
+ }
306
+ if (status === "running" || status === "pending_or_missing") {
307
+ return "trace_pending"
308
+ }
309
+ if (status && status !== "completed") {
310
+ return "review_required"
311
+ }
312
+ if (typeof findingsCount === "number" && findingsCount > 0) {
313
+ return "review_required"
314
+ }
315
+ return "ready_to_continue"
316
+ }
317
+
318
+ export function formatDogfoodStatusSummary(snapshot: DogfoodStatusSnapshot): string | null {
319
+ const cpg = snapshot.cpg_status || {}
320
+ const isFresh = cpg.is_fresh
321
+ const freshnessReason = cpg.freshness_reason || "unknown"
322
+ const commitsBehind = cpg.commits_behind
323
+ const headCommit = snapshot.head_commit ? snapshot.head_commit.slice(0, 12) : null
324
+ const reviewTrace = snapshot.review_trace || null
325
+ const traceStatus = reviewTrace?.status || "missing"
326
+ const workflowState = snapshot.workflow_state
327
+ const nextAction = snapshot.recommended_next_action
328
+ const nextCommand = (snapshot as { recommended_command?: string }).recommended_command
329
+
330
+ if (typeof isFresh === "undefined" && !headCommit && !nextAction) {
331
+ return null
332
+ }
333
+
334
+ const lines = ["## CodeGraph Dogfooding Status", ""]
335
+ if (typeof isFresh !== "undefined") {
336
+ const freshness = isFresh ? "fresh" : "stale"
337
+ const behind = typeof commitsBehind === "number" ? `, commits behind: ${commitsBehind}` : ""
338
+ lines.push(`- CPG freshness: ${freshness} (reason: ${freshnessReason}${behind})`)
339
+ }
340
+ if (headCommit) {
341
+ lines.push(`- HEAD: ${headCommit}`)
342
+ }
343
+ lines.push(`- Review trace: ${traceStatus}`)
344
+ if (workflowState) {
345
+ lines.push(`- Workflow state: ${workflowState}`)
346
+ }
347
+ if (nextAction) {
348
+ lines.push(`- Next action: ${nextAction}`)
349
+ }
350
+ if (nextCommand) {
351
+ lines.push(`- Suggested command: ${nextCommand}`)
352
+ }
353
+ return lines.join("\n")
354
+ }
355
+
257
356
  // File extensions recognized as source code
258
357
  const SOURCE_EXTENSIONS = new Set([
259
358
  "py",