@minhpnq1807/contextos 0.5.38 → 0.5.39

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,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.39
4
+
5
+ - **Report layout fix:** Replaced ASCII table formatting with clean markdown output. Reports now render correctly in all agent UIs (Antigravity, Claude Code, Codex) without truncation or line-wrapping issues.
6
+ - **Skills & workflows in report:** `Suggested Skills` and `Suggested Workflows` sections now appear in the compliance report when available. Data is passed through from `stop-hook.js` → `buildReport()` → `formatReport()`.
7
+ - **No more truncation:** All rules now display in the report — removed the artificial item limits that caused `... N more` messages.
8
+ - **Emoji status indicators:** Rule outcomes use ✅/❌/❓/⚠️ prefixes for quick scanning.
9
+
10
+
3
11
  ## 0.5.38
4
12
 
5
13
  - **Unified agent branding:** All user-facing text now shows `antigravity` instead of `agy`. Internal value remains `agy` for backward compatibility. Interactive prompts display "Antigravity" without the parenthetical alias.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minhpnq1807/contextos",
3
- "version": "0.5.38",
3
+ "version": "0.5.39",
4
4
  "description": "Task-aware AGENTS.md context injection and compliance reporting for Codex, Claude Code, and Antigravity.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,6 @@
1
1
  import { isSystemUserRule } from "./analyzer.js";
2
- import { section, table, truncateCell } from "./terminal-ui.js";
3
2
 
4
- export function buildReport({ cwd, prompt, relevantFiles, scheduled, gitSnapshot, compliance, runtimeEvidence }) {
3
+ export function buildReport({ cwd, prompt, relevantFiles, suggestedSkills, suggestedWorkflows, scheduled, gitSnapshot, compliance, runtimeEvidence }) {
5
4
  const actionableCompliance = compliance.filter((item) => !isSystemUserRule(item.rule));
6
5
  const followed = actionableCompliance.filter((item) => item.status === "followed");
7
6
  const ignored = actionableCompliance.filter((item) => item.status === "ignored");
@@ -16,6 +15,8 @@ export function buildReport({ cwd, prompt, relevantFiles, scheduled, gitSnapshot
16
15
  prompt,
17
16
  injectedRuleCount: (scheduled?.highRules?.length || 0) + (scheduled?.midRules?.length || 0),
18
17
  relevantFiles,
18
+ suggestedSkills: suggestedSkills || [],
19
+ suggestedWorkflows: suggestedWorkflows || [],
19
20
  changedFiles: gitSnapshot.changedFiles,
20
21
  warnings: gitSnapshot.warnings || [],
21
22
  runtimeEvidence: summarizeRuntimeEvidence(runtimeEvidence),
@@ -33,47 +34,77 @@ export function buildReport({ cwd, prompt, relevantFiles, scheduled, gitSnapshot
33
34
  export function formatReport(report) {
34
35
  report = sanitizeReport(report);
35
36
  const lines = [];
36
- lines.push("ContextOS report");
37
- lines.push(section("Summary"));
38
- lines.push(table(["Metric", "Value"], [
39
- ["Efficiency", report.efficiencyScore == null ? "unknown" : `${report.efficiencyScore}%`],
40
- ["Injected rules", report.injectedRuleCount || 0],
41
- ["Measured rules", report.measuredRuleCount ?? ((report.followed?.length || 0) + (report.ignored?.length || 0))],
42
- ["Changed files", report.changedFiles?.length ? report.changedFiles.length : "none detected"]
43
- ]));
44
-
45
- lines.push(section("Rule Outcomes"));
46
- lines.push(table(["Status", "Count"], [
47
- ["followed", report.followed?.length || 0],
48
- ["ignored", report.ignored?.length || 0],
49
- ["unknown", report.unknown?.length || 0],
50
- ["unmeasurable", report.unmeasurable?.length || 0]
51
- ]));
52
-
37
+ lines.push("# ContextOS Report\n");
38
+
39
+ // Summary
40
+ lines.push("## Summary");
41
+ lines.push(`- **Efficiency:** ${report.efficiencyScore == null ? "unknown" : `${report.efficiencyScore}%`}`);
42
+ lines.push(`- **Injected rules:** ${report.injectedRuleCount || 0}`);
43
+ lines.push(`- **Measured rules:** ${report.measuredRuleCount ?? ((report.followed?.length || 0) + (report.ignored?.length || 0))}`);
44
+ lines.push(`- **Changed files:** ${report.changedFiles?.length ? report.changedFiles.length : "none detected"}`);
45
+ lines.push("");
46
+
47
+ // Rule Outcomes
48
+ lines.push("## Rule Outcomes");
49
+ lines.push(`- ✅ Followed: ${report.followed?.length || 0}`);
50
+ lines.push(`- ❌ Ignored: ${report.ignored?.length || 0}`);
51
+ lines.push(`- ❓ Unknown: ${report.unknown?.length || 0}`);
52
+ lines.push(`- ⚠️ Unmeasurable: ${report.unmeasurable?.length || 0}`);
53
+ lines.push("");
54
+
55
+ // Suggested Files
53
56
  if (report.relevantFiles?.length) {
54
- lines.push(section("Suggested Files"));
55
- lines.push(table(["#", "Path", "Score"], report.relevantFiles.slice(0, 10).map((file, index) => [
56
- index + 1,
57
- truncateCell(file.path, 90),
58
- typeof file.score === "number" ? file.score.toFixed(2) : ""
59
- ])));
57
+ lines.push("## Suggested Files");
58
+ for (const [index, file] of report.relevantFiles.entries()) {
59
+ const score = typeof file.score === "number" ? ` (${file.score.toFixed(2)})` : "";
60
+ lines.push(`${index + 1}. ${file.path}${score}`);
61
+ }
62
+ lines.push("");
63
+ }
64
+
65
+ // Suggested Skills
66
+ if (report.suggestedSkills?.length) {
67
+ lines.push("## Suggested Skills");
68
+ for (const skill of report.suggestedSkills) {
69
+ const desc = skill.description ? `: ${truncate(skill.description, 80)}` : "";
70
+ lines.push(`- **${skill.name}**${desc}`);
71
+ }
72
+ lines.push("");
73
+ }
74
+
75
+ // Suggested Workflows
76
+ if (report.suggestedWorkflows?.length) {
77
+ lines.push("## Suggested Workflows");
78
+ for (const workflow of report.suggestedWorkflows) {
79
+ const name = workflow.title || workflow.name;
80
+ const chain = workflow.chain?.length ? ` → ${workflow.chain.join(" → ")}` : "";
81
+ lines.push(`- **${name}**${chain}`);
82
+ }
83
+ lines.push("");
60
84
  }
85
+
86
+ // Runtime Telemetry
61
87
  if (report.runtimeEvidence?.signals?.length) {
62
- lines.push(section("Runtime Telemetry"));
63
- lines.push(table(["#", "Signal"], report.runtimeEvidence.signals.map((signal, index) => [index + 1, signal])));
88
+ lines.push("## Runtime Telemetry");
89
+ for (const signal of report.runtimeEvidence.signals) {
90
+ lines.push(`- ${signal}`);
91
+ }
92
+ lines.push("");
64
93
  }
65
94
 
66
- for (const warning of report.warnings || []) lines.push(`Warning: ${warning}`);
95
+ // Warnings
96
+ for (const warning of report.warnings || []) lines.push(`> ⚠️ ${warning}\n`);
67
97
 
98
+ // Rule details
68
99
  appendBucket(lines, "Followed", report.followed);
69
100
  appendBucket(lines, "Ignored", report.ignored);
70
101
  appendBucket(lines, "Unknown", report.unknown);
71
102
  appendBucket(lines, "Unmeasurable", report.unmeasurable);
72
103
 
73
104
  if (report.ignored?.length) {
74
- lines.push(`Suggestion: fix ignored rule evidence first: ${truncate(report.ignored[0].rule?.content || "", 70)}`);
105
+ lines.push(`> **Suggestion:** Fix ignored rule evidence first: ${truncate(report.ignored[0].rule?.content || "", 70)}`);
75
106
  } else if (report.unknown?.length && !(report.followed?.length || report.ignored?.length)) {
76
- lines.push("Suggestion: these rules need runtime evidence or more concrete keywords before ContextOS can score them from git diff.");
107
+ lines.push("> **Suggestion:** These rules need runtime evidence or more concrete keywords before ContextOS can score them from git diff.");
77
108
  }
78
109
 
79
110
  return lines.join("\n");
@@ -82,15 +113,15 @@ export function formatReport(report) {
82
113
  export function formatEvidence(report) {
83
114
  report = sanitizeReport(report);
84
115
  const lines = [];
85
- lines.push("ContextOS evidence");
86
- lines.push(section("Summary"));
87
- lines.push(table(["Field", "Value"], [
88
- ["Prompt", truncateCell(report.prompt || "(empty)", 100)],
89
- ["Efficiency", report.efficiencyScore == null ? "unknown" : `${report.efficiencyScore}%`],
90
- ["Changed files", report.changedFiles?.length ? report.changedFiles.join(", ") : "none detected"]
91
- ]));
116
+ lines.push("# ContextOS Evidence\n");
117
+
118
+ lines.push("## Summary");
119
+ lines.push(`- **Prompt:** ${truncate(report.prompt || "(empty)", 100)}`);
120
+ lines.push(`- **Efficiency:** ${report.efficiencyScore == null ? "unknown" : `${report.efficiencyScore}%`}`);
121
+ lines.push(`- **Changed files:** ${report.changedFiles?.length ? report.changedFiles.join(", ") : "none detected"}`);
122
+ lines.push("");
92
123
 
93
- for (const warning of report.warnings || []) lines.push(`Warning: ${warning}`);
124
+ for (const warning of report.warnings || []) lines.push(`> ⚠️ ${warning}\n`);
94
125
 
95
126
  const items = [
96
127
  ...(report.followed || []).map((item) => ({ ...item, status: "followed" })),
@@ -105,43 +136,34 @@ export function formatEvidence(report) {
105
136
  return lines.join("\n");
106
137
  }
107
138
 
108
- lines.push(section("Evidence Table"));
109
- lines.push(table(["#", "Status", "Score", "Kind", "Rule", "Evidence"], items.map((item, index) => [
110
- index + 1,
111
- item.status.toUpperCase(),
112
- typeof item.rule?.score === "number" ? item.rule.score.toFixed(2) : "",
113
- item.kind || "",
114
- truncateCell(item.rule?.content || "(missing rule)", 46),
115
- truncateCell(item.evidence || "(none)", 58)
116
- ])));
117
-
118
- items.forEach((item, index) => {
119
- lines.push(section(`${index + 1}. ${item.status.toUpperCase()}`));
120
- lines.push(table(["Field", "Value"], [
121
- ["Rule", truncateCell(item.rule?.content || "(missing rule)", 120)],
122
- ["Source", item.rule?.sourcePath || ""],
123
- ["Score", typeof item.rule?.score === "number" ? item.rule.score.toFixed(2) : ""],
124
- ["Kind", item.kind || ""],
125
- ["Keywords", item.keywords?.length ? truncateCell(item.keywords.join(", "), 120) : ""],
126
- ["Evidence", truncateCell(item.evidence || "(none)", 120)]
127
- ].filter(([, value]) => value !== "")));
139
+ lines.push("## Evidence Details\n");
140
+ for (const [index, item] of items.entries()) {
141
+ const statusIcon = { followed: "✅", ignored: "❌", unknown: "❓", unmeasurable: "⚠️" }[item.status] || "";
142
+ lines.push(`### ${index + 1}. ${statusIcon} ${item.status.toUpperCase()}`);
143
+ lines.push(`- **Rule:** ${truncate(item.rule?.content || "(missing rule)", 120)}`);
144
+ if (item.rule?.sourcePath) lines.push(`- **Source:** ${item.rule.sourcePath}`);
145
+ if (typeof item.rule?.score === "number") lines.push(`- **Score:** ${item.rule.score.toFixed(2)}`);
146
+ if (item.kind) lines.push(`- **Kind:** ${item.kind}`);
147
+ lines.push(`- **Evidence:** ${truncate(item.evidence || "(none)", 120)}`);
128
148
  for (const line of item.matchedLines || []) {
129
149
  const where = line.file ? `${line.file}${typeof line.line === "number" ? `:${line.line}` : ""}` : "diff";
130
- lines.push(`Matched line: ${where} ${truncate(line.content || "", 140)}`);
150
+ lines.push(` - Match: \`${where}\` ${truncate(line.content || "", 100)}`);
131
151
  }
132
- });
152
+ lines.push("");
153
+ }
133
154
 
134
155
  return lines.join("\n");
135
156
  }
136
157
 
137
158
  function appendBucket(lines, label, items = []) {
138
159
  if (!items.length) return;
139
- lines.push(`${label}:`);
140
- for (const item of items.slice(0, 5)) {
141
- lines.push(`- Rule: ${truncate(item.rule.content, 68)}`);
142
- lines.push(` Evidence: ${truncate(item.evidence, 64)}`);
160
+ const icon = { Followed: "✅", Ignored: "❌", Unknown: "❓", Unmeasurable: "⚠️" }[label] || "";
161
+ lines.push(`### ${icon} ${label}`);
162
+ for (const item of items) {
163
+ lines.push(`- **Rule:** ${truncate(item.rule.content, 100)}`);
164
+ lines.push(` - Evidence: ${truncate(item.evidence, 100)}`);
143
165
  }
144
- if (items.length > 5) lines.push(`- ... ${items.length - 5} more`);
166
+ lines.push("");
145
167
  }
146
168
 
147
169
  function truncate(value, max) {
@@ -42,6 +42,8 @@ export function handleStopPayload(payload, { contextPath, reportPath, historyPat
42
42
  cwd,
43
43
  prompt: promptContext?.prompt || "",
44
44
  relevantFiles: promptContext?.relevantFiles || [],
45
+ suggestedSkills: promptContext?.suggestedSkills || [],
46
+ suggestedWorkflows: promptContext?.suggestedWorkflows || [],
45
47
  scheduled,
46
48
  gitSnapshot,
47
49
  compliance,