@minhpnq1807/contextos 0.5.20 → 0.5.21

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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.21
4
+
5
+ - Makes prompt hooks fall back to direct scoring when the `ctx-mcp` bridge socket is missing, stale, or unavailable, avoiding empty `hook context` output.
6
+ - Prioritizes imperative and code-review-graph rules in injected critical context so `IMPORTANT` project rules appear before generic semantic matches.
7
+ - Improves workflow detection for CI, deployment, server, runtime, debugging, and issue-analysis prompts.
8
+
3
9
  ## 0.5.20
4
10
 
5
11
  - Refreshes stale `ctx-mcp` Ruler entries that point at temporary paths such as `/tmp/contextos/...`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minhpnq1807/contextos",
3
- "version": "0.5.20",
3
+ "version": "0.5.21",
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": {
@@ -259,7 +259,7 @@ export function scoreRules(rules, task, openFiles = []) {
259
259
 
260
260
  const lowerRule = rule.content.toLowerCase();
261
261
  if (IMPORTANT_WORDS.some((word) => lowerRule.includes(word))) {
262
- score += 0.4;
262
+ score += 0.5;
263
263
  reasons.push("imperative");
264
264
  }
265
265
 
@@ -2,6 +2,7 @@ import { scheduleContext } from "./scheduler.js";
2
2
  import { appendJsonLine, writeJsonFile } from "./fs-utils.js";
3
3
  import { callCtxScoreContext } from "./ctx-mcp-client.js";
4
4
  import { resolveHookCwd } from "./hook-io.js";
5
+ import { scoreContext as scoreContextDirect } from "./score-context.js";
5
6
  import path from "node:path";
6
7
 
7
8
  export async function handlePromptPayload(
@@ -21,15 +22,31 @@ export async function handlePromptPayload(
21
22
  const openFiles = payload.openFiles || payload.open_files || payload.files || [];
22
23
  const dataDir = dataPath ? path.dirname(dataPath) : undefined;
23
24
 
24
- const scored = await scoreContextClient({
25
- cwd,
26
- prompt,
27
- openFiles,
28
- maxFiles: 3
29
- }, {
30
- dataDir: mcpDataDir || dataDir,
31
- timeoutMs: Number(process.env.CONTEXTOS_MCP_BRIDGE_TIMEOUT_MS || 1000)
32
- });
25
+ let scored;
26
+ try {
27
+ scored = await scoreContextClient({
28
+ cwd,
29
+ prompt,
30
+ openFiles,
31
+ maxFiles: 3
32
+ }, {
33
+ dataDir: mcpDataDir || dataDir,
34
+ timeoutMs: Number(process.env.CONTEXTOS_MCP_BRIDGE_TIMEOUT_MS || 1000)
35
+ });
36
+ } catch (error) {
37
+ scored = await scoreContextDirect({
38
+ cwd,
39
+ prompt,
40
+ openFiles,
41
+ maxFiles: 3,
42
+ dataDir: mcpDataDir || dataDir
43
+ });
44
+ scored.telemetry = {
45
+ ...(scored.telemetry || {}),
46
+ bridgeStatus: "fallback",
47
+ bridgeError: error?.message || String(error)
48
+ };
49
+ }
33
50
 
34
51
  if (scored.error) throw new Error(scored.error);
35
52
  const scoredRules = scored.scoredRules || [];
@@ -1,9 +1,10 @@
1
1
  const MAX_CONTEXT_CHARS = 4000;
2
2
 
3
3
  export function scheduleContext({ rules = [], relevantFiles = [], suggestedSkills = [], suggestedWorkflows = [], maxChars = MAX_CONTEXT_CHARS } = {}) {
4
- const high = rules.filter((rule) => rule.score >= 0.5);
5
- const mid = rules.filter((rule) => rule.score >= 0.1 && rule.score < 0.5);
6
- const dropped = rules.filter((rule) => rule.score < 0.1);
4
+ const orderedRules = [...rules].sort(compareRulesForContext);
5
+ const high = orderedRules.filter((rule) => rule.score >= 0.5);
6
+ const mid = orderedRules.filter((rule) => rule.score >= 0.1 && rule.score < 0.5);
7
+ const dropped = orderedRules.filter((rule) => rule.score < 0.1);
7
8
 
8
9
  const sections = [];
9
10
  if (high.length) {
@@ -37,6 +38,20 @@ export function scheduleContext({ rules = [], relevantFiles = [], suggestedSkill
37
38
  };
38
39
  }
39
40
 
41
+ function compareRulesForContext(a, b) {
42
+ return rulePriority(b) - rulePriority(a)
43
+ || Number(b.score || 0) - Number(a.score || 0)
44
+ || Number(a.originalOrder || 0) - Number(b.originalOrder || 0);
45
+ }
46
+
47
+ function rulePriority(rule) {
48
+ const content = String(rule.content || "").toLowerCase();
49
+ let priority = 0;
50
+ if (/\b(important|always|must|required|mandatory|strictly|never)\b/.test(content)) priority += 10;
51
+ if (/\b(code-review-graph|query_graph|get_minimal_context|detect_changes|semantic_search_nodes)\b/.test(content)) priority += 4;
52
+ return priority;
53
+ }
54
+
40
55
  function section(title, lines) {
41
56
  if (!lines.length) return "";
42
57
  return `## ${title}\n${lines.join("\n")}`;
@@ -320,12 +320,12 @@ function scoreWorkflowsByKeyword({ prompt, workflows }) {
320
320
 
321
321
  function actionIntentBonus(normalizedPrompt, workflow) {
322
322
  const name = normalize(`${workflow.name} ${workflow.title} ${workflow.description}`);
323
- const implementationIntent = /\b(implement|feature|build|create|fix|debug|test|ci|failing)\b/.test(normalizedPrompt);
323
+ const implementationIntent = /\b(implement|feature|build|create|fix|debug|test|ci|cd|pipeline|failing|failure|error|issue|bug|analyze|analyse|solution|server|runtime|deploy|fly|flyio|loi|phan tich|giai phap)\b/.test(normalizedPrompt);
324
324
  const docsIntent = /\b(doc|docs|documentation|readme|changelog|roadmap)\b/.test(normalizedPrompt);
325
325
  const orchestrationIntent = /\b(parallel|sequential|chain|delegate|agent|subagent|orchestrat)\b/.test(normalizedPrompt);
326
- if (implementationIntent && /\b(primary|implementation|testing|debugging|quality)\b/.test(name)) return 0.35;
327
- if (docsIntent && /\b(documentation|docs|changelog|roadmap)\b/.test(name)) return 0.35;
328
- if (orchestrationIntent && /\b(orchestration|parallel|sequential|chaining)\b/.test(name)) return 0.35;
326
+ if (implementationIntent && /\b(primary|implementation|testing|debugging|quality)\b/.test(name)) return 0.42;
327
+ if (docsIntent && /\b(documentation|docs|changelog|roadmap)\b/.test(name)) return 0.42;
328
+ if (orchestrationIntent && /\b(orchestration|parallel|sequential|chaining)\b/.test(name)) return 0.42;
329
329
  return 0;
330
330
  }
331
331