@minhpnq1807/contextos 0.5.21 → 0.5.23
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 +10 -0
- package/LAUNCH.md +4 -2
- package/README.md +3 -2
- package/bin/ctx.js +13 -1
- package/package.json +1 -1
- package/plugins/ctx/lib/antigravity-hooks.js +2 -1
- package/plugins/ctx/lib/antigravity-mcp.js +2 -1
- package/plugins/ctx/lib/claude-hooks.js +2 -1
- package/plugins/ctx/lib/claude-mcp.js +2 -1
- package/plugins/ctx/lib/gitignore.js +69 -0
- package/plugins/ctx/lib/ruler-sync.js +23 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.23
|
|
4
|
+
|
|
5
|
+
- **Fix Windows install paths:** Replaces all `process.env.HOME || process.cwd()` fallbacks with `os.homedir()` across `ctx.js`, `claude-hooks.js`, `antigravity-hooks.js`, `claude-mcp.js`, `antigravity-mcp.js`, and `ruler-sync.js`. On Windows, `HOME` is not set, causing `.codex/`, `.claude/`, and `.gemini/` directories (with full `node_modules` and source code) to be created inside the project tree instead of the user's home directory.
|
|
6
|
+
- **Fix ephemeral MCP server path:** `ctx sync --rules` now resolves the MCP server path from stable install roots (`~/.codex/marketplaces/contextos/`, `~/.ctx/contextos/agents/`) instead of `rootDir`, which may point to a temporary npm extraction directory (e.g. `/tmp/contextos/`) that disappears after cleanup.
|
|
7
|
+
|
|
8
|
+
## 0.5.22
|
|
9
|
+
|
|
10
|
+
- Adds `.gitignore` management to `ctx install`: writes inner `.gitignore` (excludes `node_modules/`, `bin/`, `lib/`, `mcp/`) inside installed agent directories and ensures the project root `.gitignore` excludes `.codex/marketplaces/contextos/`, `.claude/settings.json`, and `.gemini/`.
|
|
11
|
+
- Splits the `npm install -g && ctx setup` one-liner into two separate commands in README and LAUNCH docs to avoid shell PATH resolution failures.
|
|
12
|
+
|
|
3
13
|
## 0.5.21
|
|
4
14
|
|
|
5
15
|
- Makes prompt hooks fall back to direct scoring when the `ctx-mcp` bridge socket is missing, stale, or unavailable, avoiding empty `hook context` output.
|
package/LAUNCH.md
CHANGED
|
@@ -37,7 +37,8 @@ It supports Codex, Claude Code, and Antigravity. It is local-first and uses loca
|
|
|
37
37
|
|
|
38
38
|
Install:
|
|
39
39
|
|
|
40
|
-
npm install -g @minhpnq1807/contextos
|
|
40
|
+
npm install -g @minhpnq1807/contextos
|
|
41
|
+
ctx setup
|
|
41
42
|
|
|
42
43
|
Repo: https://github.com/khovan123/contextOS
|
|
43
44
|
```
|
|
@@ -51,7 +52,8 @@ Codex can read AGENTS.md and still ignore the rule that matters.
|
|
|
51
52
|
|
|
52
53
|
ContextOS ranks rules per prompt, injects the important ones before work starts, then reports followed / ignored / unknown after the task.
|
|
53
54
|
|
|
54
|
-
npm install -g @minhpnq1807/contextos
|
|
55
|
+
npm install -g @minhpnq1807/contextos
|
|
56
|
+
ctx setup
|
|
55
57
|
|
|
56
58
|
https://github.com/khovan123/contextOS
|
|
57
59
|
```
|
package/README.md
CHANGED
|
@@ -49,10 +49,11 @@ Rule outcomes: 8 followed, 0 ignored, 0 unknown
|
|
|
49
49
|
Runtime telemetry: code-review-graph, code-review-graph.query_graph_tool
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
## Install
|
|
52
|
+
## Quick Install
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
npm install -g @minhpnq1807/contextos
|
|
55
|
+
npm install -g @minhpnq1807/contextos
|
|
56
|
+
ctx setup
|
|
56
57
|
```
|
|
57
58
|
|
|
58
59
|
No postinstall surprise: `npm install` only installs the CLI. Setup runs only when you call `ctx setup`.
|
package/bin/ctx.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import readline from "node:readline/promises";
|
|
5
6
|
import { stdin as input, stdout as output } from "node:process";
|
|
@@ -24,6 +25,7 @@ import { installClaudeMcp } from "../plugins/ctx/lib/claude-mcp.js";
|
|
|
24
25
|
import { installAntigravityHooks } from "../plugins/ctx/lib/antigravity-hooks.js";
|
|
25
26
|
import { installAntigravityMcp } from "../plugins/ctx/lib/antigravity-mcp.js";
|
|
26
27
|
import { syncRules } from "../plugins/ctx/lib/ruler-sync.js";
|
|
28
|
+
import { writeInnerGitignore, ensureRootGitignore } from "../plugins/ctx/lib/gitignore.js";
|
|
27
29
|
import { syncSkills } from "../plugins/ctx/lib/skillshare-sync.js";
|
|
28
30
|
import { scanSkills, warmSkillEmbeddings } from "../plugins/ctx/lib/skill-discoverer.js";
|
|
29
31
|
import { parsePassthroughArgs, runPassthrough } from "../plugins/ctx/lib/passthrough.js";
|
|
@@ -162,7 +164,7 @@ function packageVersion() {
|
|
|
162
164
|
}
|
|
163
165
|
|
|
164
166
|
function codexHome() {
|
|
165
|
-
return process.env.CODEX_HOME || path.join(
|
|
167
|
+
return process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
function copyInstall() {
|
|
@@ -194,6 +196,9 @@ async function install({ copy = false, inject = true, agent = "codex" } = {}) {
|
|
|
194
196
|
const hooksPath = installClaudeHooks({ installRoot, injectPromptContext: inject });
|
|
195
197
|
progress.step(40, "installing mcp");
|
|
196
198
|
const mcpConfigPath = installClaudeMcp({ installRoot });
|
|
199
|
+
progress.step(50, "configuring gitignore");
|
|
200
|
+
writeInnerGitignore(installRoot);
|
|
201
|
+
ensureRootGitignore(process.cwd());
|
|
197
202
|
progress.step(55, "warming embeddings");
|
|
198
203
|
const warmResult = await warmInstallEmbeddings();
|
|
199
204
|
progress.done("claude installed");
|
|
@@ -218,6 +223,9 @@ async function install({ copy = false, inject = true, agent = "codex" } = {}) {
|
|
|
218
223
|
const hooksPath = installAntigravityHooks({ installRoot, injectPromptContext: inject });
|
|
219
224
|
progress.step(40, "installing mcp");
|
|
220
225
|
const mcpConfigPaths = installAntigravityMcp({ installRoot });
|
|
226
|
+
progress.step(50, "configuring gitignore");
|
|
227
|
+
writeInnerGitignore(installRoot);
|
|
228
|
+
ensureRootGitignore(process.cwd());
|
|
221
229
|
progress.step(55, "warming embeddings");
|
|
222
230
|
const warmResult = await warmInstallEmbeddings();
|
|
223
231
|
progress.done("agy installed");
|
|
@@ -256,6 +264,10 @@ async function install({ copy = false, inject = true, agent = "codex" } = {}) {
|
|
|
256
264
|
progress.step(60, "installing hooks");
|
|
257
265
|
const hooksPath = installGlobalHooks({ codexHome: codexHome(), marketplaceRoot, injectPromptContext: inject });
|
|
258
266
|
|
|
267
|
+
progress.step(65, "configuring gitignore");
|
|
268
|
+
writeInnerGitignore(marketplaceRoot);
|
|
269
|
+
ensureRootGitignore(process.cwd());
|
|
270
|
+
|
|
259
271
|
progress.step(70, "warming embeddings");
|
|
260
272
|
const warmResult = await warmInstallEmbeddings();
|
|
261
273
|
progress.done("codex installed");
|
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
|
|
4
5
|
function shellQuote(value) {
|
|
@@ -19,7 +20,7 @@ function commandFor(installRoot, scriptName, { injectPromptContext = true } = {}
|
|
|
19
20
|
|
|
20
21
|
export function antigravityHooksPath() {
|
|
21
22
|
return process.env.ANTIGRAVITY_HOOKS_PATH
|
|
22
|
-
|| path.join(
|
|
23
|
+
|| path.join(os.homedir(), ".gemini", "config", "hooks.json");
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export function buildAntigravityHooksConfig(existingConfig, { installRoot, injectPromptContext = true } = {}) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
|
|
4
5
|
function readJsonFile(filePath, fallback) {
|
|
@@ -12,7 +13,7 @@ export function antigravityMcpConfigPaths() {
|
|
|
12
13
|
if (process.env.ANTIGRAVITY_MCP_CONFIG_PATH) {
|
|
13
14
|
return [process.env.ANTIGRAVITY_MCP_CONFIG_PATH];
|
|
14
15
|
}
|
|
15
|
-
const home =
|
|
16
|
+
const home = os.homedir();
|
|
16
17
|
return [
|
|
17
18
|
path.join(home, ".gemini", "antigravity", "mcp_config.json"),
|
|
18
19
|
path.join(home, ".gemini", "antigravity-cli", "mcp_config.json"),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
|
|
4
5
|
import { buildGlobalHooksConfig } from "./global-hooks.js";
|
|
@@ -11,7 +12,7 @@ function readJsonFile(filePath, fallback) {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export function claudeHome() {
|
|
14
|
-
return process.env.CLAUDE_HOME || path.join(
|
|
15
|
+
return process.env.CLAUDE_HOME || path.join(os.homedir(), ".claude");
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export function installClaudeHooks({ claudeHome: home = claudeHome(), installRoot, injectPromptContext = true } = {}) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
|
|
4
5
|
function readJsonFile(filePath, fallback) {
|
|
@@ -9,7 +10,7 @@ function readJsonFile(filePath, fallback) {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export function claudeConfigPath() {
|
|
12
|
-
return process.env.CLAUDE_CONFIG_PATH || path.join(
|
|
13
|
+
return process.env.CLAUDE_CONFIG_PATH || path.join(os.homedir(), ".claude.json");
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export function buildClaudeMcpConfig(existingConfig, { installRoot } = {}) {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Entries to exclude inside the installed contextos directory.
|
|
6
|
+
* Keeps node_modules, bin, lib, and mcp out of version control.
|
|
7
|
+
*/
|
|
8
|
+
const INNER_GITIGNORE_ENTRIES = [
|
|
9
|
+
"node_modules/",
|
|
10
|
+
"bin/",
|
|
11
|
+
"lib/",
|
|
12
|
+
"mcp/",
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Entries that ctx install should add to the project root .gitignore.
|
|
17
|
+
*
|
|
18
|
+
* .codex/marketplaces/contextos/ — Codex agent install dir
|
|
19
|
+
* .claude/settings.json — Claude hooks written by ctx install
|
|
20
|
+
* .gemini/ — Antigravity hooks/config
|
|
21
|
+
*/
|
|
22
|
+
const ROOT_GITIGNORE_ENTRIES = [
|
|
23
|
+
".codex/marketplaces/contextos/",
|
|
24
|
+
".claude/settings.json",
|
|
25
|
+
".gemini/",
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Write a .gitignore inside `dir` that excludes build/runtime artefacts.
|
|
30
|
+
* Creates the directory if it does not exist yet.
|
|
31
|
+
*/
|
|
32
|
+
export function writeInnerGitignore(dir) {
|
|
33
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
34
|
+
const gitignorePath = path.join(dir, ".gitignore");
|
|
35
|
+
const content = INNER_GITIGNORE_ENTRIES.join("\n") + "\n";
|
|
36
|
+
fs.writeFileSync(gitignorePath, content, "utf8");
|
|
37
|
+
return gitignorePath;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Ensure the project root .gitignore exists and contains the entries
|
|
42
|
+
* needed to keep ctx install artefacts out of version control.
|
|
43
|
+
*
|
|
44
|
+
* Only appends entries that are not already present.
|
|
45
|
+
* Creates the file if it does not exist.
|
|
46
|
+
*/
|
|
47
|
+
export function ensureRootGitignore(projectRoot) {
|
|
48
|
+
const gitignorePath = path.join(projectRoot, ".gitignore");
|
|
49
|
+
let existing = "";
|
|
50
|
+
if (fs.existsSync(gitignorePath)) {
|
|
51
|
+
existing = fs.readFileSync(gitignorePath, "utf8");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const lines = existing.split("\n");
|
|
55
|
+
const missing = ROOT_GITIGNORE_ENTRIES.filter(
|
|
56
|
+
(entry) => !lines.some((line) => line.trim() === entry)
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
if (missing.length === 0) return gitignorePath;
|
|
60
|
+
|
|
61
|
+
const block = [
|
|
62
|
+
"",
|
|
63
|
+
"# ContextOS install artefacts",
|
|
64
|
+
...missing,
|
|
65
|
+
].join("\n") + "\n";
|
|
66
|
+
|
|
67
|
+
fs.writeFileSync(gitignorePath, existing.trimEnd() + "\n" + block, "utf8");
|
|
68
|
+
return gitignorePath;
|
|
69
|
+
}
|
|
@@ -5,9 +5,12 @@ import readline from "node:readline/promises";
|
|
|
5
5
|
import { stdin as input, stdout as output } from "node:process";
|
|
6
6
|
import { execFileSync } from "node:child_process";
|
|
7
7
|
|
|
8
|
+
import { defaultDataRoot } from "./workspace-data.js";
|
|
9
|
+
|
|
8
10
|
const DEFAULT_AGENTS = ["codex", "claude", "antigravity"];
|
|
9
11
|
const CTX_MCP_NAME = "ctx-mcp";
|
|
10
12
|
const CONTEXTOS_PROXY_MARKER = "/contextos/plugins/ctx/mcp/proxy.js";
|
|
13
|
+
const MCP_SERVER_RELATIVE = path.join("plugins", "ctx", "mcp", "server.js");
|
|
11
14
|
const AGENT_ALIASES = new Map([
|
|
12
15
|
["agy", "antigravity"],
|
|
13
16
|
["antigravity", "antigravity"],
|
|
@@ -54,11 +57,11 @@ function displayAgentName(agent) {
|
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
function codexConfigPath() {
|
|
57
|
-
return path.join(process.env.CODEX_HOME || path.join(
|
|
60
|
+
return path.join(process.env.CODEX_HOME || path.join(os.homedir(), ".codex"), "config.toml");
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
function claudeUserConfigPath() {
|
|
61
|
-
return process.env.CLAUDE_CONFIG_PATH || path.join(
|
|
64
|
+
return process.env.CLAUDE_CONFIG_PATH || path.join(os.homedir(), ".claude.json");
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
export function rulerTomlPath(cwd = process.cwd()) {
|
|
@@ -273,7 +276,7 @@ function readRulerMcpServer({ tomlPath, name } = {}) {
|
|
|
273
276
|
}
|
|
274
277
|
|
|
275
278
|
function antigravityMcpConfigPaths() {
|
|
276
|
-
const home =
|
|
279
|
+
const home = os.homedir();
|
|
277
280
|
return [
|
|
278
281
|
path.join(home, ".gemini", "antigravity", "mcp_config.json"),
|
|
279
282
|
path.join(home, ".gemini", "antigravity-cli", "mcp_config.json"),
|
|
@@ -456,7 +459,7 @@ export function verifySync({ cwd = process.cwd(), agents = DEFAULT_AGENTS } = {}
|
|
|
456
459
|
const checks = [];
|
|
457
460
|
const definitions = {
|
|
458
461
|
codex: [path.join(cwd, ".codex", "config.toml")],
|
|
459
|
-
claude: [path.join(cwd, ".mcp.json"), path.join(cwd, ".claude", "settings.json"), path.join(
|
|
462
|
+
claude: [path.join(cwd, ".mcp.json"), path.join(cwd, ".claude", "settings.json"), path.join(os.homedir(), ".claude.json")],
|
|
460
463
|
antigravity: [
|
|
461
464
|
path.join(cwd, ".gemini", "settings.json"),
|
|
462
465
|
path.join(cwd, ".gemini", "mcp.json"),
|
|
@@ -473,6 +476,21 @@ export function verifySync({ cwd = process.cwd(), agents = DEFAULT_AGENTS } = {}
|
|
|
473
476
|
return checks;
|
|
474
477
|
}
|
|
475
478
|
|
|
479
|
+
function resolveStableMcpServerPath(rootDir) {
|
|
480
|
+
const codexRoot = path.join(process.env.CODEX_HOME || path.join(os.homedir(), ".codex"), "marketplaces", "contextos");
|
|
481
|
+
const dataRoot = defaultDataRoot();
|
|
482
|
+
const candidates = [
|
|
483
|
+
path.join(codexRoot, MCP_SERVER_RELATIVE),
|
|
484
|
+
path.join(dataRoot, "agents", "claude", "contextos", MCP_SERVER_RELATIVE),
|
|
485
|
+
path.join(dataRoot, "agents", "agy", "contextos", MCP_SERVER_RELATIVE),
|
|
486
|
+
path.join(rootDir, MCP_SERVER_RELATIVE)
|
|
487
|
+
];
|
|
488
|
+
for (const candidate of candidates) {
|
|
489
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
490
|
+
}
|
|
491
|
+
return path.join(rootDir, MCP_SERVER_RELATIVE);
|
|
492
|
+
}
|
|
493
|
+
|
|
476
494
|
export async function syncRules({
|
|
477
495
|
cwd = process.cwd(),
|
|
478
496
|
rootDir,
|
|
@@ -495,7 +513,7 @@ export async function syncRules({
|
|
|
495
513
|
const init = ensureRulerInit({ cwd, run, dryRun: options.dryRun });
|
|
496
514
|
logger(statusLine("Checking .ruler/ruler.toml...", init.created ? "✓ created" : "✓ found"));
|
|
497
515
|
|
|
498
|
-
const mcpServerPath =
|
|
516
|
+
const mcpServerPath = resolveStableMcpServerPath(rootDir);
|
|
499
517
|
const injected = injectCtxMcp({
|
|
500
518
|
tomlPath: init.tomlPath,
|
|
501
519
|
mcpServerPath,
|