@minhpnq1807/contextos 0.6.4 → 0.6.7
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 +14 -0
- package/README.md +7 -6
- package/package.json +1 -1
- package/plugins/ctx/.codex-plugin/plugin.json +1 -1
- package/plugins/ctx/lib/certification.js +49 -17
- package/plugins/ctx/lib/project-context-generator.js +10 -3
- package/plugins/ctx/lib/skill-discoverer.js +42 -8
- package/plugins/ctx/lib/workflow-discoverer.js +2 -0
- package/plugins/ctx/mcp/proxy.js +31 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.7
|
|
4
|
+
|
|
5
|
+
- **MCP proxy test stability:** Fixed the MCP proxy telemetry smoke test so it waits for the telemetry file before reading it and uses a stable stdin/stdout echo child. This removes the CI race where `telemetry.jsonl` could be read before it existed.
|
|
6
|
+
|
|
7
|
+
## 0.6.6
|
|
8
|
+
|
|
9
|
+
- **Global-first skill coverage:** `ctx doctor` now treats global and community skills as valid skill coverage instead of requiring project-local skill packs. Project skills are reported separately as optional project overrides, so repositories with synced global skills no longer show `Skills: 0` or `Not Ready` just because `.codex/skills` is absent.
|
|
10
|
+
- **Evidence-gated skill routing:** Updated Skill Router scoring so global skills are first-class candidates, community skills get a small source boost, and project skills get an override boost without penalizing global catalogs. Prompt+semantic matches without project evidence now remain medium-confidence candidates instead of disappearing.
|
|
11
|
+
- **Shared project context:** `ctx doctor --fix` and `ctx setup --generate-project-context` now scaffold shared project context under `.agents/skills/` and `.agents/workflows/` instead of Codex-only `.codex/` paths. Workflow discovery and certification now read `.agents/workflows` so the same generated context can be synced to Codex, Claude Code, Gemini, and Antigravity.
|
|
12
|
+
|
|
13
|
+
## 0.6.5
|
|
14
|
+
|
|
15
|
+
- **Generated skill frontmatter:** Fixed `ctx doctor --fix` starter `SKILL.md` output so generated project skills include YAML frontmatter with `name` and `description`. This prevents invalid-skill warnings after generated skills are synced through skillshare.
|
|
16
|
+
|
|
3
17
|
## 0.6.4
|
|
4
18
|
|
|
5
19
|
- **Project context generator:** Added `ctx doctor --fix` and `ctx setup --generate-project-context` to explicitly scaffold starter project skills and a primary workflow when a repository has rules but is missing ContextOS-ready skills/workflows. Generation is repo-scoped, does not run from `npm install`, and does not overwrite existing files unless `--force` is passed to `ctx doctor --fix`.
|
package/README.md
CHANGED
|
@@ -246,14 +246,15 @@ ctx doctor
|
|
|
246
246
|
Repository Score
|
|
247
247
|
|
|
248
248
|
Rules: 92
|
|
249
|
-
|
|
249
|
+
Skill Coverage: 88
|
|
250
|
+
Project Skill Overrides: 0
|
|
250
251
|
Workflows: 84
|
|
251
252
|
|
|
252
253
|
Overall:
|
|
253
|
-
ContextOS Ready
|
|
254
|
+
ContextOS Ready Silver
|
|
254
255
|
```
|
|
255
256
|
|
|
256
|
-
The score checks project `AGENTS.md` rules,
|
|
257
|
+
The score checks project `AGENTS.md` rules, global/community skill coverage, optional project skill overrides, and project workflows. Shared project context should live under `.agents/skills/` and `.agents/workflows/`; ContextOS can sync it to Codex, Claude Code, Gemini, and Antigravity agent roots. Use the badge only after `ctx doctor` reports Bronze, Silver, or Gold.
|
|
257
258
|
|
|
258
259
|
## Quick Commands
|
|
259
260
|
|
|
@@ -584,14 +585,14 @@ This warning comes from a transitive dependency in the local embedding/WASM stac
|
|
|
584
585
|
| `ctx install --copy` | Copies only the plugin payload to `$CODEX_HOME/plugins/ctx`. | Legacy local development or manual plugin experiments. | Does not sync the active marketplace, rebuild indexes, register MCP, or install global hooks. Prefer `ctx refresh` for active local updates. |
|
|
585
586
|
| `ctx setup` | Runs the first-run setup wizard. | You want the recommended onboarding flow after `npm install -g @minhpnq1807/contextos`. | Installs selected agents, optionally syncs Ruler rules/MCP and skillshare skills, asks which prompt sections to show, then prints next steps. |
|
|
586
587
|
| `ctx setup --yes` | Runs setup with defaults non-interactively. | You want scriptable Codex setup. | Uses `codex`, enables injection, syncs rules, syncs skills, skips interactive community-skill installation when no TTY is available, and passes `--yes` to dependency setup prompts. Use `--agents codex,claude,agy` for multi-agent setup. |
|
|
587
|
-
| `ctx setup --generate-project-context` | Generates starter project skills and workflow during setup. | Your repo has rules but `ctx doctor` reports missing skills/workflows. | Creates `.
|
|
588
|
+
| `ctx setup --generate-project-context` | Generates starter shared project skills and workflow during setup. | Your repo has rules but `ctx doctor` reports missing skills/workflows. | Creates `.agents/skills/<detected-skill>/SKILL.md`, matching `skill.yaml`, and `.agents/workflows/primary.md` without overwriting existing files. Run `ctx sync --skills` and `ctx sync --workflows` to push them to selected agents. |
|
|
588
589
|
| `ctx setup --agents <list>` | Runs setup for selected agents. | You want only part of the default set. | Accepts comma-separated `codex`, `claude`, `agy`, or `antigravity`. |
|
|
589
590
|
| `ctx setup --no-rules` | Skips Ruler sync during setup. | You only want hooks/MCP install and maybe skill sync. | Does not run `ctx sync --rules`. |
|
|
590
591
|
| `ctx setup --no-skills` | Skips skillshare sync during setup. | You do not want shared skills configured. | Does not run `ctx sync --skills`. |
|
|
591
592
|
| `ctx setup --quiet` | Runs setup in measurement-only mode. | You want reports/stats without visible injected prompt context. | Installs hooks with prompt context injection disabled. |
|
|
592
593
|
| `ctx debug -- "task"` | Runs the scheduler locally for a fake prompt. | You want to see which AGENTS.md rules and files ContextOS would inject before using Codex. | Prints rule scores, scoring reasons, suggested files, and final `additionalContext`. |
|
|
593
594
|
| `ctx doctor` | Scores repository ContextOS readiness. | You want to add or verify a `ContextOS Ready` badge. | Prints Rules, Skills, Workflows, Overall tier, evidence, and next recommendations. |
|
|
594
|
-
| `ctx doctor --fix` | Generates starter ContextOS project context. | `ctx doctor` says skills/workflows are missing and you want explicit local scaffolding. | Detects package/config evidence, creates up to three
|
|
595
|
+
| `ctx doctor --fix` | Generates starter ContextOS project context. | `ctx doctor` says skills/workflows are missing and you want explicit local scaffolding. | Detects package/config evidence, creates up to three shared project skills plus `.agents/workflows/primary.md`, then prints the updated readiness score. |
|
|
595
596
|
| `ctx report` | Shows the last Stop-hook compliance report for the current workspace. | An agent task has finished and you want the summary again. | Prints sectioned tables for summary, rule outcomes, suggested files, and runtime telemetry from `~/.ctx/contextos/workspaces/<workspace-id>/last-report.json`. |
|
|
596
597
|
| `ctx evidence` | Shows detailed evidence behind the last report for the current workspace. | You want to inspect why a rule was marked `followed`, `ignored`, `unknown`, or `unmeasurable`. | Prints a compact evidence table plus per-rule detail tables. |
|
|
597
598
|
| `ctx stats` | Shows aggregate runtime metrics for the current workspace. | You want to know whether ContextOS is active and useful over time. | Prints sectioned tables for prompt/report counts, injection rate, efficiency, rule outcomes, hook events, last prompt, and last report. |
|
|
@@ -611,7 +612,7 @@ This warning comes from a transitive dependency in the local embedding/WASM stac
|
|
|
611
612
|
| `ctx sync --skills --no-collect` | Skips collecting existing agent skills into skillshare. | You already manage `~/.config/skillshare/skills` and only want to push it out. | Initializes/syncs skillshare without running `skillshare backup` or `skillshare collect --all`. |
|
|
612
613
|
| `ctx sync --skills --no-embeddings` | Skips ContextOS skill embedding rebuild after skillshare sync. | You have a very large skill catalog and want sync to finish quickly. | Runs skillshare sync, then leaves embeddings to a later `ctx embeddings warm -- "task"` run. |
|
|
613
614
|
| `ctx sync --skills --verbose` | Shows native skillshare token budget warnings during sync. | You are diagnosing skillshare path overlap or always-loaded context size. | Omits ContextOS' default `skillshare sync --quiet` behavior. |
|
|
614
|
-
| `ctx sync --workflows` | Syncs and indexes agent workflow markdown files for prompt-time workflow suggestions. | You use `.claude/workflows/`, `.codex/workflows/`, or Antigravity workflow folders and want every agent to see the same deduped workflow set. | Scans project/global workflow folders, dedupes by workflow name, copies unique workflows to selected global agent roots, warms workflow embeddings, and makes `ctx debug`/prompt hooks show relevant workflow hints. |
|
|
615
|
+
| `ctx sync --workflows` | Syncs and indexes agent workflow markdown files for prompt-time workflow suggestions. | You use `.agents/workflows/`, `.claude/workflows/`, `.codex/workflows/`, or Gemini/Antigravity workflow folders and want every agent to see the same deduped workflow set. | Scans project/global workflow folders, dedupes by workflow name, copies unique workflows to selected global agent roots, warms workflow embeddings, and makes `ctx debug`/prompt hooks show relevant workflow hints. |
|
|
615
616
|
| `ctx sync --workflows --agents <list>` | Syncs workflows only for selected agents. | You want a subset such as `codex,claude` or `codex,claude,agy`. | Accepts comma-separated `codex`, `claude`, `agy`, or `antigravity`; `agy` writes the Gemini/Antigravity workflow roots. |
|
|
616
617
|
| `ctx sync --workflows --dry-run` | Previews workflow sync without writing files. | You want to inspect source workflows and target roots first. | Prints planned sync/index output and skips copying target files. |
|
|
617
618
|
| `ctx skills` | Installs community skill libraries. | You want curated skills without running the full setup wizard. | Opens the community installer, uses a portable shell on Windows/Linux/macOS, repairs unsafe skill symlinks, and syncs installed skills to selected agents. |
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
|
|
5
5
|
import { filterActionableRules, parseRules } from "./analyzer.js";
|
|
6
6
|
import { readAgentsChain } from "./reader.js";
|
|
7
|
-
import { scanSkills } from "./skill-discoverer.js";
|
|
7
|
+
import { scanSkills, skillSearchRoots } from "./skill-discoverer.js";
|
|
8
8
|
import { scanWorkflows } from "./workflow-discoverer.js";
|
|
9
9
|
|
|
10
10
|
const PROJECT_SKILL_ROOTS = [
|
|
@@ -17,6 +17,7 @@ const PROJECT_SKILL_ROOTS = [
|
|
|
17
17
|
];
|
|
18
18
|
|
|
19
19
|
const PROJECT_WORKFLOW_ROOTS = [
|
|
20
|
+
[".agents", "workflows"],
|
|
20
21
|
[".claude", "workflows"],
|
|
21
22
|
[".codex", "workflows"],
|
|
22
23
|
[".gemini", "workflows"],
|
|
@@ -27,7 +28,7 @@ const PROJECT_WORKFLOW_ROOTS = [
|
|
|
27
28
|
export function inspectContextOSReady({ cwd = process.cwd(), home = os.homedir() } = {}) {
|
|
28
29
|
const root = findProjectRoot(cwd);
|
|
29
30
|
const rules = inspectRules({ cwd, root, home });
|
|
30
|
-
const skills = inspectSkills({ root });
|
|
31
|
+
const skills = inspectSkills({ root, home });
|
|
31
32
|
const workflows = inspectWorkflows({ root });
|
|
32
33
|
const overall = Math.round((rules.score + skills.score + workflows.score) / 3);
|
|
33
34
|
const tier = readinessTier(overall, { rules, skills, workflows });
|
|
@@ -48,7 +49,8 @@ export function formatContextOSReady(result) {
|
|
|
48
49
|
"Repository Score",
|
|
49
50
|
"",
|
|
50
51
|
`Rules: ${result.rules.score}`,
|
|
51
|
-
`
|
|
52
|
+
`Skill Coverage: ${result.skills.score}`,
|
|
53
|
+
`Project Skill Overrides: ${result.skills.projectOverrideScore}`,
|
|
52
54
|
`Workflows: ${result.workflows.score}`,
|
|
53
55
|
"",
|
|
54
56
|
"Overall:",
|
|
@@ -56,7 +58,8 @@ export function formatContextOSReady(result) {
|
|
|
56
58
|
"",
|
|
57
59
|
"Evidence:",
|
|
58
60
|
`- Rules: ${result.rules.summary}`,
|
|
59
|
-
`-
|
|
61
|
+
`- Skill Coverage: ${result.skills.summary}`,
|
|
62
|
+
`- Project Skill Overrides: ${result.skills.projectSummary}`,
|
|
60
63
|
`- Workflows: ${result.workflows.summary}`
|
|
61
64
|
];
|
|
62
65
|
|
|
@@ -108,10 +111,15 @@ function inspectRules({ cwd, root, home }) {
|
|
|
108
111
|
};
|
|
109
112
|
}
|
|
110
113
|
|
|
111
|
-
function inspectSkills({ root }) {
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
const
|
|
114
|
+
function inspectSkills({ root, home }) {
|
|
115
|
+
const projectRoots = PROJECT_SKILL_ROOTS.map((parts) => path.join(root, ...parts));
|
|
116
|
+
const roots = skillSearchRoots({ cwd: root, home });
|
|
117
|
+
const skills = scanSkills({ cwd: root, roots, maxSkills: 5000 });
|
|
118
|
+
const projectSkills = skills.filter((skill) => skill.scope === "project");
|
|
119
|
+
const sharedSkills = skills.filter((skill) => skill.scope !== "project");
|
|
120
|
+
const communitySkills = skills.filter((skill) => isCommunitySkillPath(skill.path));
|
|
121
|
+
const globalSkills = sharedSkills.filter((skill) => !isCommunitySkillPath(skill.path));
|
|
122
|
+
const metadataFiles = findFiles(projectRoots, (filePath) => /skill\.ya?ml$/i.test(path.basename(filePath)));
|
|
115
123
|
const richMetadata = metadataFiles.filter((filePath) => {
|
|
116
124
|
const content = safeRead(filePath);
|
|
117
125
|
return /^positive_triggers:/m.test(content)
|
|
@@ -123,29 +131,52 @@ function inspectSkills({ root }) {
|
|
|
123
131
|
const recommendations = [];
|
|
124
132
|
|
|
125
133
|
if (skills.length) score += 50;
|
|
126
|
-
else recommendations.push("
|
|
134
|
+
else recommendations.push("Sync or install global skills with `ctx setup` or `ctx sync --skills`.");
|
|
127
135
|
|
|
128
|
-
if (
|
|
129
|
-
else recommendations.push("Add skill.yaml metadata beside important SKILL.md files.");
|
|
136
|
+
if (sharedSkills.length || projectSkills.length >= 3) score += 25;
|
|
130
137
|
|
|
131
|
-
if (
|
|
132
|
-
else recommendations.push("Include positive_triggers, negative_triggers, evidence, and workflow in skill.yaml.");
|
|
138
|
+
if (projectSkills.length) score += 10;
|
|
133
139
|
|
|
134
|
-
if (
|
|
135
|
-
|
|
140
|
+
if (metadataFiles.length) score += 5;
|
|
141
|
+
if (richMetadata.length) score += 10;
|
|
142
|
+
if (projectSkills.length && !metadataFiles.length) {
|
|
143
|
+
recommendations.push("Add skill.yaml metadata beside project-specific SKILL.md files.");
|
|
144
|
+
}
|
|
145
|
+
if (projectSkills.length && !richMetadata.length) {
|
|
146
|
+
recommendations.push("Include positive_triggers, negative_triggers, evidence, and workflow in project skill.yaml files.");
|
|
147
|
+
}
|
|
136
148
|
|
|
137
149
|
return {
|
|
138
150
|
score: Math.min(100, score),
|
|
139
151
|
count: skills.length,
|
|
152
|
+
globalCount: globalSkills.length,
|
|
153
|
+
communityCount: communitySkills.length,
|
|
154
|
+
sharedCount: sharedSkills.length,
|
|
155
|
+
projectCount: projectSkills.length,
|
|
156
|
+
projectOverrideScore: projectSkillOverrideScore(projectSkills),
|
|
140
157
|
metadataCount: metadataFiles.length,
|
|
141
158
|
richMetadataCount: richMetadata.length,
|
|
142
159
|
summary: skills.length
|
|
143
|
-
? `${skills.length} skill(s), ${
|
|
144
|
-
: "missing project skill
|
|
160
|
+
? `${skills.length} skill(s): ${globalSkills.length} global, ${communitySkills.length} community/shared, ${projectSkills.length} project override(s)`
|
|
161
|
+
: "missing global/community/project skill catalog",
|
|
162
|
+
projectSummary: projectSkills.length
|
|
163
|
+
? `${projectSkills.length} project override skill(s), ${metadataFiles.length} metadata file(s)`
|
|
164
|
+
: "0 project override skill(s); global/community skills remain valid",
|
|
145
165
|
recommendations
|
|
146
166
|
};
|
|
147
167
|
}
|
|
148
168
|
|
|
169
|
+
function projectSkillOverrideScore(projectSkills = []) {
|
|
170
|
+
if (projectSkills.length >= 3) return 100;
|
|
171
|
+
if (projectSkills.length === 2) return 70;
|
|
172
|
+
if (projectSkills.length === 1) return 40;
|
|
173
|
+
return 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function isCommunitySkillPath(filePath = "") {
|
|
177
|
+
return String(filePath || "").includes(`${path.sep}.config${path.sep}skillshare${path.sep}skills${path.sep}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
149
180
|
function inspectWorkflows({ root }) {
|
|
150
181
|
const roots = PROJECT_WORKFLOW_ROOTS.map((parts) => path.join(root, ...parts));
|
|
151
182
|
const workflows = scanWorkflows({ cwd: root, roots });
|
|
@@ -175,6 +206,7 @@ function inspectWorkflows({ root }) {
|
|
|
175
206
|
|
|
176
207
|
function readinessTier(overall, { rules, skills, workflows }) {
|
|
177
208
|
if (rules.score < 50 || skills.score < 50 || workflows.score < 50) return "Not Ready";
|
|
209
|
+
if (!skills.projectCount && overall >= 85) return "Silver";
|
|
178
210
|
if (overall >= 85) return "Gold";
|
|
179
211
|
if (overall >= 70) return "Silver";
|
|
180
212
|
if (overall >= 50) return "Bronze";
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { clearSkillScanCache } from "./skill-discoverer.js";
|
|
5
5
|
|
|
6
6
|
const STARTER_SKILL_LIMIT = 3;
|
|
7
|
+
const SHARED_PROJECT_CONTEXT_DIR = ".agents";
|
|
7
8
|
|
|
8
9
|
export function generateProjectContext({ cwd = process.cwd(), force = false } = {}) {
|
|
9
10
|
const root = findProjectRoot(cwd);
|
|
@@ -13,7 +14,7 @@ export function generateProjectContext({ cwd = process.cwd(), force = false } =
|
|
|
13
14
|
const skipped = [];
|
|
14
15
|
|
|
15
16
|
for (const skill of skills) {
|
|
16
|
-
const dir = path.join(root,
|
|
17
|
+
const dir = path.join(root, SHARED_PROJECT_CONTEXT_DIR, "skills", skill.id);
|
|
17
18
|
const skillPath = path.join(dir, "SKILL.md");
|
|
18
19
|
const yamlPath = path.join(dir, "skill.yaml");
|
|
19
20
|
fs.mkdirSync(dir, { recursive: true });
|
|
@@ -21,7 +22,7 @@ export function generateProjectContext({ cwd = process.cwd(), force = false } =
|
|
|
21
22
|
writeFile({ filePath: yamlPath, content: renderSkillYaml(skill), force, created, skipped });
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
const workflowPath = path.join(root,
|
|
25
|
+
const workflowPath = path.join(root, SHARED_PROJECT_CONTEXT_DIR, "workflows", "primary.md");
|
|
25
26
|
fs.mkdirSync(path.dirname(workflowPath), { recursive: true });
|
|
26
27
|
writeFile({
|
|
27
28
|
filePath: workflowPath,
|
|
@@ -61,7 +62,8 @@ export function formatProjectContextGeneration(result) {
|
|
|
61
62
|
for (const filePath of result.skipped) lines.push(`- ${path.relative(result.root, filePath)}`);
|
|
62
63
|
}
|
|
63
64
|
lines.push("", "Next:");
|
|
64
|
-
lines.push("- Review generated skills/workflow and edit project-specific wording.");
|
|
65
|
+
lines.push("- Review generated shared skills/workflow and edit project-specific wording.");
|
|
66
|
+
lines.push("- Run: ctx sync --skills && ctx sync --workflows");
|
|
65
67
|
lines.push("- Run: ctx doctor");
|
|
66
68
|
lines.push("- Run: ctx debug -- \"your task\"");
|
|
67
69
|
return lines.join("\n");
|
|
@@ -254,6 +256,11 @@ function skill({ id, name, description, prompts, files, dependencies, negatives
|
|
|
254
256
|
|
|
255
257
|
function renderSkillMarkdown(skill) {
|
|
256
258
|
return [
|
|
259
|
+
"---",
|
|
260
|
+
`name: ${skill.id}`,
|
|
261
|
+
`description: ${skill.description}`,
|
|
262
|
+
"---",
|
|
263
|
+
"",
|
|
257
264
|
`# ${skill.name}`,
|
|
258
265
|
"",
|
|
259
266
|
skill.description,
|
|
@@ -551,7 +551,16 @@ function inferSkillMetadata(skill = {}) {
|
|
|
551
551
|
}
|
|
552
552
|
if (/\bnext|app router\b/.test(text)) {
|
|
553
553
|
metadata.dependencies.push("next", "react");
|
|
554
|
-
metadata.positivePrompts.push("frontend", "ui", "role", "dashboard", "app router");
|
|
554
|
+
metadata.positivePrompts.push("frontend", "ui", "role", "dashboard", "app router", "page", "webapp");
|
|
555
|
+
}
|
|
556
|
+
if (/\b(frontend|react|ui|component|layout|design)\b/.test(text)) {
|
|
557
|
+
metadata.dependencies.push("react");
|
|
558
|
+
metadata.positivePrompts.push("frontend", "ui", "component", "page", "layout", "button", "modal");
|
|
559
|
+
}
|
|
560
|
+
if (/\b(forum|topic|community|chat|message|realtime|websocket|socket|conversation)\b/.test(text)) {
|
|
561
|
+
metadata.positivePrompts.push("forum", "topic", "new topic", "trending", "chat", "chatting", "message", "realtime", "websocket");
|
|
562
|
+
metadata.files.push("package.json", "webapp/package.json", "services/*/package.json");
|
|
563
|
+
metadata.dependencies.push("next", "react", "socket.io", "ws", "@nestjs/websockets");
|
|
555
564
|
}
|
|
556
565
|
return metadata;
|
|
557
566
|
}
|
|
@@ -570,16 +579,18 @@ function hybridSkillScore(skill, { prompt, projectEvidence }) {
|
|
|
570
579
|
const projectEvidenceScore = dependencyEvidence.score;
|
|
571
580
|
const fileConfigScore = fileEvidence.score;
|
|
572
581
|
const importGraphScore = 0;
|
|
582
|
+
const sourceBoostScore = skillSourceBoostScore(skill);
|
|
573
583
|
const externalGraphScore = 0;
|
|
574
584
|
const memoryScore = 0;
|
|
575
585
|
const hybridScore = Math.max(0, Math.min(1,
|
|
576
|
-
semanticScore * 0.
|
|
586
|
+
semanticScore * 0.25
|
|
577
587
|
+ promptMatch.score * 0.20
|
|
578
|
-
+ projectEvidenceScore * 0.
|
|
588
|
+
+ projectEvidenceScore * 0.25
|
|
579
589
|
+ fileConfigScore * 0.10
|
|
580
590
|
+ importGraphScore * 0.10
|
|
581
|
-
+
|
|
582
|
-
+
|
|
591
|
+
+ sourceBoostScore * 0.05
|
|
592
|
+
+ externalGraphScore * 0.03
|
|
593
|
+
+ memoryScore * 0.02
|
|
583
594
|
- negativePenalty * 0.20
|
|
584
595
|
));
|
|
585
596
|
const explicit = (skill.reasons || []).includes("explicit-skill");
|
|
@@ -590,13 +601,15 @@ function hybridSkillScore(skill, { prompt, projectEvidence }) {
|
|
|
590
601
|
dependencyEvidence,
|
|
591
602
|
fileEvidence,
|
|
592
603
|
negativePenalty,
|
|
593
|
-
explicit
|
|
604
|
+
explicit,
|
|
605
|
+
semanticScore
|
|
594
606
|
});
|
|
595
607
|
const evidence = [...new Set([
|
|
596
608
|
...(skill.reasons || []),
|
|
597
609
|
...promptMatch.matches.map((item) => `prompt:${item}`),
|
|
598
610
|
...dependencyEvidence.matches.map((item) => `dependency:${item}`),
|
|
599
|
-
...fileEvidence.matches.map((item) => `file:${item}`)
|
|
611
|
+
...fileEvidence.matches.map((item) => `file:${item}`),
|
|
612
|
+
...(sourceBoostScore ? [`source:${skillSourceLabel(skill)}`] : [])
|
|
600
613
|
])];
|
|
601
614
|
const negativeEvidence = [
|
|
602
615
|
...negativeDependencies.matches.map((item) => `dependency:${item}`),
|
|
@@ -618,6 +631,7 @@ function hybridSkillScore(skill, { prompt, projectEvidence }) {
|
|
|
618
631
|
projectEvidenceScore,
|
|
619
632
|
fileConfigScore,
|
|
620
633
|
importGraphScore,
|
|
634
|
+
sourceBoostScore,
|
|
621
635
|
externalGraphScore,
|
|
622
636
|
memoryScore,
|
|
623
637
|
graphScore: externalGraphScore,
|
|
@@ -636,7 +650,8 @@ function calibrateSkillConfidence(score, {
|
|
|
636
650
|
dependencyEvidence,
|
|
637
651
|
fileEvidence,
|
|
638
652
|
negativePenalty = 0,
|
|
639
|
-
explicit = false
|
|
653
|
+
explicit = false,
|
|
654
|
+
semanticScore = 0
|
|
640
655
|
} = {}) {
|
|
641
656
|
let confidence = Math.max(0, Math.min(1, Number(score || 0)));
|
|
642
657
|
const hasDependencyEvidence = Boolean(dependencyEvidence?.matches?.length);
|
|
@@ -647,6 +662,9 @@ function calibrateSkillConfidence(score, {
|
|
|
647
662
|
if (!hasProjectEvidence && !explicit) {
|
|
648
663
|
confidence = Math.min(confidence, 0.62);
|
|
649
664
|
}
|
|
665
|
+
if (!hasProjectEvidence && hasPromptEvidence && Number(semanticScore || 0) >= 0.75 && !explicit) {
|
|
666
|
+
confidence = Math.max(confidence, 0.56);
|
|
667
|
+
}
|
|
650
668
|
if (isAmbiguousPrompt(prompt) && !(hasDependencyEvidence && hasFileEvidence) && !explicit) {
|
|
651
669
|
confidence = Math.min(confidence, 0.64);
|
|
652
670
|
}
|
|
@@ -662,6 +680,22 @@ function calibrateSkillConfidence(score, {
|
|
|
662
680
|
return Math.max(0, Math.min(1, confidence));
|
|
663
681
|
}
|
|
664
682
|
|
|
683
|
+
function skillSourceBoostScore(skill = {}) {
|
|
684
|
+
if (skill.scope === "project") return 1;
|
|
685
|
+
if (isCommunitySkill(skill)) return 0.4;
|
|
686
|
+
return 0;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
function skillSourceLabel(skill = {}) {
|
|
690
|
+
if (skill.scope === "project") return "project";
|
|
691
|
+
if (isCommunitySkill(skill)) return "community";
|
|
692
|
+
return "global";
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
function isCommunitySkill(skill = {}) {
|
|
696
|
+
return String(skill.path || "").includes(`${path.sep}.config${path.sep}skillshare${path.sep}skills${path.sep}`);
|
|
697
|
+
}
|
|
698
|
+
|
|
665
699
|
function confidenceBand(confidence) {
|
|
666
700
|
const value = Number(confidence || 0);
|
|
667
701
|
if (value >= 0.85) return "high";
|
|
@@ -30,11 +30,13 @@ const KNOWN_AGENT_NAMES = new Set([
|
|
|
30
30
|
|
|
31
31
|
export function workflowSearchRoots({ cwd = process.cwd(), home = os.homedir() } = {}) {
|
|
32
32
|
return [
|
|
33
|
+
path.join(cwd, ".agents", "workflows"),
|
|
33
34
|
path.join(cwd, ".claude", "workflows"),
|
|
34
35
|
path.join(cwd, ".codex", "workflows"),
|
|
35
36
|
path.join(cwd, ".gemini", "workflows"),
|
|
36
37
|
path.join(cwd, ".gemini", "antigravity", "workflows"),
|
|
37
38
|
path.join(cwd, ".gemini", "antigravity-cli", "workflows"),
|
|
39
|
+
path.join(home, ".agents", "workflows"),
|
|
38
40
|
path.join(home, ".claude", "workflows"),
|
|
39
41
|
path.join(home, ".codex", "workflows"),
|
|
40
42
|
path.join(home, ".gemini", "workflows"),
|
package/plugins/ctx/mcp/proxy.js
CHANGED
|
@@ -9,6 +9,9 @@ const { serverName, command, args } = parseArgs(process.argv.slice(2));
|
|
|
9
9
|
const cwd = process.cwd();
|
|
10
10
|
const telemetryPath = path.join(workspaceDataDir({ cwd }), "telemetry.jsonl");
|
|
11
11
|
let inspectBuffer = "";
|
|
12
|
+
let childExit = null;
|
|
13
|
+
let pendingStdinWrites = 0;
|
|
14
|
+
let stdinEnded = false;
|
|
12
15
|
|
|
13
16
|
const child = spawn(command, args, {
|
|
14
17
|
cwd,
|
|
@@ -18,20 +21,32 @@ const child = spawn(command, args, {
|
|
|
18
21
|
|
|
19
22
|
process.stdin.on("data", (chunk) => {
|
|
20
23
|
inspectClientChunk(chunk);
|
|
21
|
-
|
|
24
|
+
pendingStdinWrites += 1;
|
|
25
|
+
if (!child.stdin.write(chunk, onChildStdinWrite)) process.stdin.pause();
|
|
22
26
|
});
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
child.stdin.on("drain", () => {
|
|
29
|
+
process.stdin.resume();
|
|
26
30
|
});
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
process.stdin.on("end", () => {
|
|
33
|
+
stdinEnded = true;
|
|
34
|
+
maybeEndChildStdin();
|
|
30
35
|
});
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
function onChildStdinWrite() {
|
|
38
|
+
pendingStdinWrites -= 1;
|
|
39
|
+
maybeEndChildStdin();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function maybeEndChildStdin() {
|
|
43
|
+
if (stdinEnded && pendingStdinWrites === 0 && !child.stdin.destroyed) {
|
|
44
|
+
child.stdin.end();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
child.stdout.pipe(process.stdout);
|
|
49
|
+
child.stderr.pipe(process.stderr);
|
|
35
50
|
|
|
36
51
|
child.on("error", (error) => {
|
|
37
52
|
process.stderr.write(`contextos mcp proxy failed to start ${serverName}: ${error?.message || String(error)}\n`);
|
|
@@ -39,10 +54,16 @@ child.on("error", (error) => {
|
|
|
39
54
|
});
|
|
40
55
|
|
|
41
56
|
child.on("exit", (code, signal) => {
|
|
42
|
-
|
|
43
|
-
|
|
57
|
+
childExit = { code, signal };
|
|
58
|
+
maybeFinish();
|
|
44
59
|
});
|
|
45
60
|
|
|
61
|
+
function maybeFinish() {
|
|
62
|
+
if (!childExit) return;
|
|
63
|
+
if (childExit.signal) process.kill(process.pid, childExit.signal);
|
|
64
|
+
else process.exitCode = childExit.code ?? 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
46
67
|
function inspectClientChunk(chunk) {
|
|
47
68
|
inspectBuffer += chunk.toString("utf8");
|
|
48
69
|
const lines = inspectBuffer.split(/\r?\n/);
|