@minhpnq1807/contextos 0.5.42 → 0.5.45

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,41 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.45
4
+
5
+ - **Project-aware MCP skill suggestions:** Skill ranking now reads `package.json` keywords and dependencies such as `@modelcontextprotocol/sdk`. MCP projects can recommend `mcp-builder`, `mcp-management`, `mcp-tool-developer`, and `agent-memory-mcp` for context retrieval, scorer, hook, and prompt-injection debugging tasks even when the prompt does not explicitly say `mcp`.
6
+ - **Domain-safe skill ranking:** Added common-language stopwords and bounded domain gates so generic prompt overlap no longer revives unrelated MCP, offensive-security, or platform-commerce skills. Purchase prompts prioritize payment, billing, frontend API integration, and backend skills without assuming Stripe, PayPal, WooCommerce, or another provider unless named.
7
+ - **Purchase-flow file retrieval:** File embedding and graph retrieval queries now expand purchase, wallet, checkout, content-access, library, and notification prompts with focused retrieval hints while keeping repository walking out of the prompt hot path.
8
+ - **Seven-item prompt summaries:** Increased suggested file and skill limits from three to seven in prompt hooks and `ctx debug`. Suggested files now render as a compact comma-separated inline summary while duplicate basenames remain disambiguated with relative paths.
9
+ - **Target-workspace prompt scoring:** Prompt hooks can score an explicitly named sibling workspace such as `../philo-mind`, allowing repo-specific manifest and skill recommendations when debugging another project from the current shell.
10
+ - **Monorepo manifest awareness:** Project skill hints and run/connect file suggestions now read bounded root and workspace `package.json` metadata, including workspace arrays, `{ packages: [...] }`, and one-level globs.
11
+ - **Fallback file retrieval budget:** Raised direct hook fallback file-vector timeout to 1000ms so indexed file suggestions remain available when the private MCP bridge is unavailable.
12
+
13
+ ## 0.5.44
14
+
15
+ - **Robust MCP TOML handling:** Added `smol-toml` parsing for Codex MCP config while preserving comments, ordering, multiline arrays, and nested tool approval sections during telemetry proxy rewrites.
16
+ - **Embedding-only file retrieval:** Removed filename heuristic fallback. File suggestions now flow through local file-path embeddings, relative import expansion, and optional `code-review-graph` retrieval.
17
+ - **Fast stale-socket fallback:** Added a separate 100ms `ctx-mcp` socket connect timeout while keeping a bounded 2s response timeout for active scoring requests.
18
+ - **Bridge disconnect resilience:** `ctx-mcp` now ignores per-client socket errors when a timed-out hook disconnects while scoring is still in progress, preventing an `EPIPE` from crashing the long-running MCP server.
19
+ - **Bridge revision fallback:** `ctx refresh` invalidates the private hook bridge socket after syncing an active marketplace update. Hook clients also reject stale `ctx-mcp` bridge responses and discard the same-inode socket, then fall back to direct scoring until Codex restarts the long-running MCP process.
20
+ - **Hook deadline fail-open:** `on-prompt.js` now has an 8.5s hard deadline, exits cleanly after writing JSON, and caps direct fallback scoring when the MCP bridge is unavailable. This prevents Codex's 10s hook timeout from killing the hook and causing broken-pipe noise.
21
+ - **Automatic empty-context recovery:** Prompt hooks no longer return an empty `hookSpecificOutput` block. When no rules/files/skills/workflows are available from enabled sections, ContextOS records `emptyContextReason` and starts a detached `autowarm` rebuild with cooldown so the next prompt can use fresh file, skill, workflow, import-graph, and graph-embedding indexes without making the current hook walk the repo.
22
+ - **PostToolUse stdin drain:** Existing `code-review-graph update --skip-flows` PostToolUse hooks are normalized to drain hook stdin before running, preventing Codex broken-pipe errors when the update command exits early.
23
+ - **Smooth skill installs:** `ctx skills` and the setup community installer now use a portable shell runner instead of hard-coded `sh`, report installer environment problems without crashing, repair unsafe skill symlinks before/after install, and automatically run `skillshare sync` after successful `ctx skills` installs.
24
+ - **Graph strategy detection:** `ctx install` now reports detected `code-review-graph` and `codegraph` backends. `codegraph` remains adapter-pending until its MCP contract is implemented.
25
+ - **Internal graph telemetry:** Direct `graph-retriever.js` calls now emit `InternalGraphRetrieval` events so compliance tracking observes graph usage even when retrieval bypasses the MCP proxy.
26
+ - **Automatic graph embedding refresh:** `ctx install` now refreshes local `code-review-graph` node embeddings after ContextOS warmup when the project already has a graph database. Missing graph runtimes remain fail-open.
27
+ - **Automatic active marketplace refresh:** Added `ctx refresh`, and made `ctx embeddings warm` sync the current package into the active Codex marketplace before rebuilding indexes. This removes the manual `rsync` step during local updates.
28
+ - **Consistent standard installs:** Every non-legacy `ctx install` agent path, including installs invoked by `ctx setup`, now syncs the active Codex marketplace before rebuilding file/import indexes and refreshing available code-review-graph embeddings.
29
+ - **Indexed file retrieval hot path:** Prompt scoring now queries persisted file vectors from `embeddings.db` and persisted one-hop import adjacency directly. Repository walking is limited to install and explicit embedding warmup rebuilds.
30
+ - **File retrieval timeout:** Raised the indexed file-vector lookup timeout from 80ms to 1000ms so warm local SQLite searches can return Suggested files instead of silently falling back to an empty list on larger project indexes.
31
+ - **Parallel context retrieval:** Rules, file suggestions, skills, and workflows now score concurrently through `Promise.all()`.
32
+ - **Interactive prompt section config:** Added `ctx --config`, a multi-select panel for toggling injected critical rules, suggested files, suggested skills, and suggested workflows. Interactive `ctx setup` now includes the same section picker; `ctx setup --yes` preserves the current saved config for automation. Choices persist globally in `~/.ctx/contextos/output-config.json`, and saved summaries remain inside the `│` panel.
33
+ - **Compact prompt summaries:** Prompt injection now shows file basenames without full paths, emits skills as a deduplicated comma-separated inline list without descriptions, and keeps workflows to names plus chains.
34
+ - **Skill suggestion precision:** Skill keyword ranking now ignores generic setup/runtime tokens such as `node`, `package`, `setup`, `sync`, and `graph`, and deduplicates repeated skill names found across agent roots.
35
+ - **Project-aware skill hints:** Skill ranking now reads bounded root/workspace manifest hints and known mobile config files such as `app.json`, `app.config.*`, and `eas.json`. URL tokens are stripped before scoring, and EAS domain eligibility prevents semantic fallback from reviving unrelated mobile skills, so specialized Expo/EAS skills outrank unrelated GitHub-linked descriptions.
36
+ - **Silent Stop hooks:** Stop hooks now persist compliance reports without printing them after every task. Run `ctx report` or `ctx evidence` for the detailed output.
37
+ - **Plugin version guard:** Plugin validation now requires the Codex plugin manifest version to match `package.json`.
38
+
3
39
  ## 0.5.42
4
40
 
5
41
  - **Setup fallback when no skills found:** During `ctx setup`, if `syncSkills` completes but `detectExistingSkills` finds zero skills on the machine, the CLI now automatically offers the community skill library installer. After successful install, `syncSkills` re-runs to distribute the newly installed skills to all selected agents.
package/README.md CHANGED
@@ -102,7 +102,7 @@ The problem is not that agents cannot read `AGENTS.md`. The problem is that larg
102
102
  | Injection | Critical rules are placed with primacy + recency, not buried in the middle. |
103
103
  | Discovery | Relevant files, skills, and workflows are suggested before work starts. |
104
104
  | Sync | Rules/MCP via Ruler, skills via skillshare, workflows via ContextOS. |
105
- | Evidence | Stop hooks report `followed`, `ignored`, `unknown`, and runtime telemetry. |
105
+ | Evidence | Stop hooks persist `followed`, `ignored`, `unknown`, and runtime telemetry for explicit reports. |
106
106
 
107
107
  ## Quick Commands
108
108
 
@@ -194,6 +194,8 @@ ctx install --agent agy
194
194
  4. Warms `~/.ctx/contextos/embeddings.db` for AGENTS rules and project file paths.
195
195
  5. Registers the `ctx-mcp` MCP server and merges ContextOS global hooks into `$CODEX_HOME/hooks.json`.
196
196
  6. Wraps configured local MCP servers, except ContextOS' own `ctx-mcp`, with a transparent telemetry proxy so `tools/call` events can be measured. The original MCP command is preserved after the proxy separator and executed unchanged.
197
+ 7. Detects available project graph backends and prints the selected strategy. `code-review-graph` is active today; detected `codegraph` backends are reported as adapter-pending until the integration contract is implemented.
198
+ 8. Refreshes local `code-review-graph` node embeddings when the project already has `.code-review-graph/graph.db`. This is best-effort: install still succeeds when the graph runtime is unavailable.
197
199
 
198
200
  Restart Codex after installing.
199
201
 
@@ -407,15 +409,15 @@ This warning comes from a transitive dependency in the local embedding/WASM stac
407
409
 
408
410
  | Command | Meaning | Use when | Output / side effect |
409
411
  | --- | --- | --- | --- |
410
- | `ctx install` | Installs ContextOS into Codex with prompt context injection enabled. | Normal Codex setup after installing the npm package. | Same as `ctx install codex`. |
412
+ | `ctx install` | Installs ContextOS into Codex with prompt context injection enabled. | Normal Codex setup after installing the npm package. | Same as `ctx install codex`. Standard installs sync the active Codex marketplace, rebuild file/import indexes, and refresh code-review-graph embeddings when available. |
411
413
  | `ctx install codex` | Installs ContextOS into Codex. | You use the `codex` CLI. | Copies the plugin into `$CODEX_HOME/marketplaces/contextos`, registers `ctx@contextos`, registers `ctx-mcp`, installs global hooks, downloads the embedding model, and warms caches. |
412
414
  | `ctx install claude` | Installs ContextOS into Claude Code. | You use the `claude` CLI. | Copies a stable package root to `~/.ctx/contextos/agents/claude/contextos`, merges hooks into `~/.claude/settings.json`, and registers `ctx-mcp` in `~/.claude.json`. |
413
415
  | `ctx install agy` | Installs ContextOS into Antigravity. | You use the `agy` CLI or Antigravity app/editor. | Copies a stable package root to `~/.ctx/contextos/agents/agy/contextos`, writes hooks to `~/.gemini/config/hooks.json`, and registers `ctx-mcp` in Antigravity app, CLI, and legacy editor MCP config paths. |
414
416
  | `ctx install --agent <name>` | Installs for a named agent. | You prefer explicit scripts. | Accepts `codex`, `claude`, or `agy`. |
415
417
  | `ctx install --quiet` | Installs ContextOS in measurement-only mode. | You want reports and stats but do not want visible injected context. | Installs the same hooks, but prompt hooks return empty context. |
416
418
  | `ctx install --inject` | Installs ContextOS with explicit injection mode. | You want to be explicit in scripts or docs. | Same runtime behavior as the default install mode; if combined with `--quiet`, `--inject` wins. |
417
- | `ctx install --copy` | Copies only the plugin payload to `$CODEX_HOME/plugins/ctx`. | Local development or manual plugin experiments. | Does not register marketplace, MCP, or global hooks. |
418
- | `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, then prints next steps. |
419
+ | `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. |
420
+ | `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. |
419
421
  | `ctx setup --yes` | Runs setup with defaults non-interactively. | You want scriptable all-agent setup. | Uses `codex,claude,agy`, enables injection, syncs rules, syncs skills, and passes `--yes` to dependency setup prompts. |
420
422
  | `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`. |
421
423
  | `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`. |
@@ -440,7 +442,10 @@ This warning comes from a transitive dependency in the local embedding/WASM stac
440
442
  | `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. |
441
443
  | `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. |
442
444
  | `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. |
445
+ | `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. |
443
446
  | `ctx embeddings warm -- "task"` | Prepares local semantic embedding caches. | First install, CI smoke checks, or after changing AGENTS.md/project files/skills/workflows. | Loads/downloads `Xenova/all-MiniLM-L6-v2` and writes rule, file-path, skill, and workflow vectors to `~/.ctx/contextos/embeddings.db`. |
447
+ | `ctx --config` | Opens an interactive multi-select panel for prompt sections. | You want to reduce ContextOS prompt output noise. | Toggles critical rules, suggested files, suggested skills, and suggested workflows globally under `~/.ctx/contextos/output-config.json`. |
448
+ | `ctx refresh` | Refreshes the active Codex marketplace plugin and rebuilds local indexes. | Local development updates or a stale file retrieval index. | Copies the current package to `$CODEX_HOME/marketplaces/contextos`, rebuilds file-path embeddings and import adjacency, and refreshes code-review-graph embeddings when available. |
444
449
  | `ctx ruler -- <args>` | Forwards args to the installed `ruler` CLI. | You need native Ruler commands such as `init`, `apply`, or `revert`. | Preserves Ruler stdout/stderr and exit status. |
445
450
  | `ctx skillshare -- <args>` | Forwards args to the installed `skillshare` CLI. | You need native skillshare commands such as `status`, `target list`, `doctor`, `push`, or `pull`. | Preserves skillshare stdout/stderr and exit status. |
446
451
  | `ctx --version` | Prints the installed ContextOS CLI version. | You want to confirm which npm version is being executed. | Prints the version from package metadata. |
@@ -495,16 +500,31 @@ For file suggestions, ContextOS now runs a local RAG-style retrieval pass:
495
500
  prompt
496
501
  -> UserPromptSubmit hook calls ctx-mcp bridge
497
502
  -> ctx-mcp reads AGENTS.md and scores rules with local MiniLM
498
- -> run file-path embedding search against embeddings.db for semantic file candidates
499
- -> scan filenames for initial seed candidates
503
+ -> query the persisted file-vector index in embeddings.db for semantic file candidates
500
504
  -> expand candidates through relative import graph links
501
505
  -> query code-review-graph semantic_search_nodes with seed entity names
502
- -> merge graph matches with heuristic matches
506
+ -> merge and deduplicate semantic, import-graph, and code-review-graph matches
503
507
  -> inject top suggested files with graph evidence reasons
504
508
  ```
505
509
 
506
510
  This keeps the hook fast and local while still using graph semantics when available. The graph search path is visible in runtime data through file reasons such as `graph:content-moderation.service`.
507
511
 
512
+ Prompt scoring does not walk the repository for file candidates or import expansion. `ctx install` and `ctx embeddings warm` rebuild the persisted file-vector index and one-hop import adjacency index by walking source paths once; prompt hooks query those indexes directly. Rules, files, skills, and workflows are scored concurrently with `Promise.all()`.
513
+
514
+ `ctx embeddings warm` automatically refreshes the active Codex marketplace payload before rebuilding indexes. Use `ctx refresh` when you want the same marketplace sync plus install-style file/import index and code-review-graph embedding refresh in one command.
515
+
516
+ If a prompt has no usable context candidates, the hook fails open without emitting an empty `hook context` block, records `emptyContextReason` in the workspace runtime file, and starts a detached `autowarm` rebuild with a cooldown. That background rebuild refreshes file vectors, skill/workflow vectors, import adjacency, and available code-review-graph node embeddings for the next prompt while keeping repository walking out of the current prompt hot path.
517
+
518
+ Use `ctx --config` to choose which prompt sections ContextOS injects. Interactive `ctx setup` now includes the same multi-select step, while `ctx setup --yes` keeps the current saved config for automation. The panel supports multiple selection with `Space` and persists the global choice in `~/.ctx/contextos/output-config.json`. Disabling rules hides both critical and additional relevant rule sections; compliance metadata remains available for reports.
519
+
520
+ Injected prompt sections are intentionally compact: rules show only detected rule text, files show basenames without paths, skills show unique names as a comma-separated inline list without descriptions, and workflows show names with their agent chain. Stop hooks persist reports silently; run `ctx report` or `ctx evidence` when you want the detailed compliance output.
521
+
522
+ Codex may flatten newlines in its `UserPromptSubmit hook (completed)` preview. The injected `additionalContext` payload remains multiline; this is a Codex preview display limitation.
523
+
524
+ Skill ranking uses bounded project hints from root/workspace `package.json` files and known mobile config files such as `app.json`, `app.config.*`, and `eas.json`. This lets Expo/EAS tasks activate specialized skills without walking the source tree on every prompt.
525
+
526
+ After `ctx refresh`, ContextOS invalidates the private hook bridge socket so prompts fall back to direct scoring until Codex restarts the long-running `ctx-mcp` process. Hook clients also discard a same-inode socket if an older bridge revision is detected.
527
+
508
528
  Configuration:
509
529
 
510
530
  ```text
@@ -512,10 +532,15 @@ CONTEXTOS_GRAPH_RETRIEVAL=0 disable graph-backed file retrieval
512
532
  CONTEXTOS_GRAPH_TIMEOUT_MS=80 graph lookup timeout
513
533
  CONTEXTOS_CRG_PYTHON=/path/python Python with code_review_graph installed
514
534
  CONTEXTOS_EMBEDDINGS=0 disable embedding rule scoring
515
- CONTEXTOS_MCP_BRIDGE_TIMEOUT_MS=1000 ctx-mcp hook bridge timeout
535
+ CONTEXTOS_MCP_CONNECT_TIMEOUT_MS=100 stale ctx-mcp socket connect timeout
536
+ CONTEXTOS_MCP_BRIDGE_TIMEOUT_MS=2000 ctx-mcp hook bridge timeout
537
+ CONTEXTOS_HOOK_DEADLINE_MS=8500 hard fail-open deadline for prompt hooks
538
+ CONTEXTOS_DIRECT_FALLBACK_TIMEOUT_MS=6000 direct scoring timeout when the bridge is unavailable
539
+ CONTEXTOS_HOOK_EMBEDDING_TIMEOUT_MS=500 rule embedding timeout during hook direct fallback
516
540
  CONTEXTOS_EMBEDDING_TIMEOUT_MS=800 embedding scoring timeout inside ctx-mcp/debug
517
541
  CONTEXTOS_FILE_EMBEDDINGS=0 disable file-path embedding retrieval
518
- CONTEXTOS_FILE_EMBEDDING_TIMEOUT_MS=80 file embedding lookup timeout
542
+ CONTEXTOS_HOOK_FILE_EMBEDDING_TIMEOUT_MS=500 file retrieval timeout during hook direct fallback
543
+ CONTEXTOS_FILE_EMBEDDING_TIMEOUT_MS=1000 file-path embedding retrieval timeout
519
544
  ```
520
545
 
521
546
  ## Hook Flow
@@ -545,10 +570,14 @@ unknown = the rule was relevant, but the diff does not prove either way
545
570
  unmeasurable = ContextOS lacks the required evidence source, such as git diff lines or runtime telemetry
546
571
  ```
547
572
 
548
- For runtime-only rules, ContextOS also checks `telemetry.jsonl` for hook-visible tool names, MCP server names, and command metadata. A rule like "use code-review-graph before reading files" can be marked `followed` when telemetry contains a matching `code-review-graph` signal.
573
+ For runtime-only rules, ContextOS also checks `telemetry.jsonl` for hook-visible tool names, MCP server names, command metadata, and ContextOS' own internal graph retrieval events. A rule like "use code-review-graph before reading files" can be marked `followed` when telemetry contains a matching `code-review-graph` signal, whether retrieval traveled through the MCP proxy or the local graph bridge.
549
574
 
550
575
  `ctx install` wraps configured stdio MCP servers with a transparent proxy. Codex will show `node .../proxy.js` as the launched command because that is how stdio can be intercepted, but the original MCP command is kept after `--` and executed unchanged, including RTK-managed commands. The proxy forwards MCP JSON-RPC unchanged and records `tools/call` requests such as `code-review-graph.detect_changes_tool` to workspace telemetry.
551
576
 
577
+ The local graph bridge calls `code-review-graph.semantic_search_nodes` directly for hook latency, so it bypasses the stdio proxy. ContextOS records these calls separately as `InternalGraphRetrieval` telemetry with `source=graph-retriever`. `codegraph` detection is already active, but the hybrid adapter remains pending until its MCP response schema is stable enough to merge symbol lookup context with `code-review-graph` blast-radius results.
578
+
579
+ Codex MCP config is parsed with `smol-toml`. ContextOS rewrites only the selected MCP server fields so comments, ordering, multiline arrays, and tool approval subsections are preserved.
580
+
552
581
  Host/session setup rules such as "run shell commands as user X", `sudo su - user`, `sudo -i -u user`, and `sudo -u user` are filtered before scoring. They are not injected and do not count toward `unknown` outcomes because they describe the agent runtime environment rather than project behavior.
553
582
 
554
583
  ## Development
@@ -623,6 +652,8 @@ contextos-plan.jsx implementation plan/reference
623
652
  ## Limitations
624
653
 
625
654
  - Codex and Claude Code get prompt context through `additionalContext`; Antigravity gets prompt context through `PreInvocation` `ephemeralMessage`.
655
+ - File suggestions require local file-path embeddings or graph matches. ContextOS no longer falls back to filename heuristics when embedding caches are unavailable.
656
+ - `codegraph` detection is diagnostic only until the `codegraph_context` adapter contract is implemented.
626
657
  - Antigravity Stop hooks store reports locally, but they do not display the full report inline unless Antigravity adds a non-continuing Stop message surface.
627
658
  - Local marketplace plugin hooks may not fire reliably in current Codex builds, so `ctx install` also installs global hooks.
628
659
  - Injection mode may show a visible hook context block in some agents.
package/bin/ctx.js CHANGED
@@ -5,7 +5,7 @@ import path from "node:path";
5
5
  import readline from "node:readline/promises";
6
6
  import { stdin as input, stdout as output } from "node:process";
7
7
  import { fileURLToPath } from "node:url";
8
- import { execFileSync, execSync, spawn } from "node:child_process";
8
+ import { execFileSync, execSync } from "node:child_process";
9
9
 
10
10
  import { readAgentsChain } from "../plugins/ctx/lib/reader.js";
11
11
  import { filterActionableRules, parseRules, scoreRules } from "../plugins/ctx/lib/analyzer.js";
@@ -19,23 +19,27 @@ import { scoreContext } from "../plugins/ctx/lib/score-context.js";
19
19
  import { defaultDataRoot, workspaceDataDir, workspaceMarkerPath } from "../plugins/ctx/lib/workspace-data.js";
20
20
  import { installMcpTelemetryProxies } from "../plugins/ctx/lib/mcp-proxy-install.js";
21
21
  import { benchmarkWorkspace, formatBenchmark } from "../plugins/ctx/lib/benchmark.js";
22
- import { copyDir, copyPackageRoot } from "../plugins/ctx/lib/package-install.js";
22
+ import { copyDir, copyPackageRoot, syncPackageRoot } from "../plugins/ctx/lib/package-install.js";
23
23
  import { installClaudeHooks } from "../plugins/ctx/lib/claude-hooks.js";
24
24
  import { installClaudeMcp } from "../plugins/ctx/lib/claude-mcp.js";
25
25
  import { installAntigravityHooks } from "../plugins/ctx/lib/antigravity-hooks.js";
26
26
  import { installAntigravityMcp } from "../plugins/ctx/lib/antigravity-mcp.js";
27
27
  import { installCopilotHooks } from "../plugins/ctx/lib/copilot-hooks.js";
28
28
  import { installCopilotMcp } from "../plugins/ctx/lib/copilot-mcp.js";
29
- import { syncRules } from "../plugins/ctx/lib/ruler-sync.js";
29
+ import { readCodexMcpServers, syncRules } from "../plugins/ctx/lib/ruler-sync.js";
30
+ import { detectGraphStrategy, embedCodeReviewGraph, formatCodeReviewGraphEmbedding, formatGraphStrategy } from "../plugins/ctx/lib/graph-strategy.js";
30
31
  import { writeInnerGitignore, ensureRootGitignore } from "../plugins/ctx/lib/gitignore.js";
31
- import { syncSkills, detectExistingSkills } from "../plugins/ctx/lib/skillshare-sync.js";
32
+ import { repairSkillSymlinks, syncSkills, detectExistingSkills } from "../plugins/ctx/lib/skillshare-sync.js";
32
33
  import { scanSkills, warmSkillEmbeddings } from "../plugins/ctx/lib/skill-discoverer.js";
33
34
  import { parsePassthroughArgs, runPassthrough } from "../plugins/ctx/lib/passthrough.js";
34
35
  import { parseAgentList, parseSetupArgs, setupSummaryLines } from "../plugins/ctx/lib/setup-wizard.js";
35
36
  import { multiSelect } from "../plugins/ctx/lib/multi-select.js";
37
+ import { configureOutputSections, enabledOutputSectionsLabel, loadOutputConfig } from "../plugins/ctx/lib/output-config.js";
36
38
  import { syncWorkflows, warmWorkflowEmbeddings } from "../plugins/ctx/lib/workflow-discoverer.js";
37
39
  import { checkForUpdate } from "../plugins/ctx/lib/update-notifier.js";
38
40
  import { fetchSkillsForAgents, printSkillRecommendations, getAllLibraries, getInstallCommands } from "../plugins/ctx/lib/skill-library.js";
41
+ import { invalidateCtxMcpSocket } from "../plugins/ctx/lib/ctx-mcp-client.js";
42
+ import { runPrefixedCommand } from "../plugins/ctx/lib/shell-runner.js";
39
43
 
40
44
  /**
41
45
  * Run a shell command with all output lines prefixed by │
@@ -43,28 +47,7 @@ import { fetchSkillsForAgents, printSkillRecommendations, getAllLibraries, getIn
43
47
  * stdin is inherited so interactive prompts (e.g. npx "Ok to proceed?") still work.
44
48
  */
45
49
  function runPrefixed(cmd) {
46
- const DIM = "\x1B[2m";
47
- const RST = "\x1B[0m";
48
- const pfx = `${DIM}│${RST} `;
49
- return new Promise((resolve, reject) => {
50
- const child = spawn("sh", ["-c", cmd], { stdio: ["inherit", "pipe", "pipe"] });
51
- function pipe(stream, target) {
52
- let needPrefix = true;
53
- stream.on("data", (buf) => {
54
- const str = buf.toString();
55
- let out = "";
56
- for (const ch of str) {
57
- if (needPrefix) { out += pfx; needPrefix = false; }
58
- out += ch;
59
- if (ch === "\n") needPrefix = true;
60
- }
61
- target.write(out);
62
- });
63
- }
64
- pipe(child.stdout, process.stdout);
65
- pipe(child.stderr, process.stderr);
66
- child.on("close", (code) => code === 0 ? resolve() : reject(new Error(`exit code ${code}`)));
67
- });
50
+ return runPrefixedCommand(cmd);
68
51
  }
69
52
 
70
53
  /**
@@ -151,7 +134,15 @@ async function runCommunitySkillInstaller(agents = []) {
151
134
  console.log(`${DIM}│${RESET}`);
152
135
 
153
136
  try {
137
+ const beforeRepair = repairSkillSymlinks({ cwd: process.cwd(), home: os.homedir() });
138
+ if (beforeRepair.repaired.length || beforeRepair.removedBroken.length) {
139
+ console.log(`${DIM}│${RESET} Repaired ${beforeRepair.repaired.length} skill links before install.`);
140
+ }
154
141
  await runPrefixed(installCmd);
142
+ const afterRepair = repairSkillSymlinks({ cwd: process.cwd(), home: os.homedir() });
143
+ if (afterRepair.repaired.length || afterRepair.removedBroken.length) {
144
+ console.log(`${DIM}│${RESET} Repaired ${afterRepair.repaired.length} skill links after install.`);
145
+ }
155
146
  successCount++;
156
147
 
157
148
  if (installInfo.verify) {
@@ -160,9 +151,9 @@ async function runCommunitySkillInstaller(agents = []) {
160
151
  console.log(`${DIM}│${RESET}`);
161
152
  console.log(`${GREEN}✔${RESET} ${lib.name} installed successfully.`);
162
153
  } catch (err) {
163
- console.error(`${YELLOW}⚠${RESET} Install failed for ${lib.name}. Try manually:`);
164
- console.error(` ${installCmd}`);
165
- console.error(` ${DIM}${err.message}${RESET}`);
154
+ console.error(`${YELLOW}⚠${RESET} Install failed for ${lib.name}.`);
155
+ console.error(`${DIM}│${RESET} ${DIM}${err.message}${RESET}`);
156
+ console.error(`${DIM}│${RESET} ContextOS will continue setup; rerun \`ctx skills\` after fixing the environment.`);
166
157
  }
167
158
  }
168
159
  }
@@ -214,6 +205,8 @@ Usage:
214
205
  ctx skills Browse community skill libraries
215
206
  ctx skills --agents <names> Filter skills for specific agents
216
207
  ctx skills --refresh Force refresh skill library cache
208
+ ctx --config Choose prompt context sections to show
209
+ ctx refresh Sync active Codex marketplace and rebuild indexes
217
210
  ctx embeddings warm -- "task" Pre-warm embedding caches for a task
218
211
  ctx ruler -- <ruler args> Passthrough to ruler CLI
219
212
  ctx skillshare -- <skillshare args> Passthrough to skillshare CLI
@@ -366,8 +359,12 @@ async function install({ copy = false, agent = "codex" } = {}) {
366
359
  }
367
360
  const progress = createInstallProgress({ quiet: false });
368
361
  progress.start(`installing ${agent || "codex"}`);
362
+ const graphStrategy = graphStrategyForInstall();
369
363
 
370
364
  try {
365
+ progress.step(5, "syncing active marketplace");
366
+ syncActiveCodexMarketplace();
367
+
371
368
  if (agent === "claude") {
372
369
  progress.step(10, "copying package");
373
370
  const installRoot = copyPackageRoot({ rootDir, targetRoot: agentInstallRoot("claude") });
@@ -383,7 +380,9 @@ async function install({ copy = false, agent = "codex" } = {}) {
383
380
  progress.done("claude ✓");
384
381
  console.log(`Hooks → ${hooksPath}`);
385
382
  console.log(`MCP → ${mcpConfigPath}`);
383
+ console.log(`Graph → ${graphStrategy}`);
386
384
  console.log(`Embeddings: ${warmResult.fileCount || 0} files, ${warmResult.skillCount || 0} skills`);
385
+ console.log(`Graph embeddings: ${formatCodeReviewGraphEmbedding(warmResult.graphEmbedding)}`);
387
386
  console.log("Restart Claude Code to activate ContextOS.");
388
387
  return;
389
388
  }
@@ -403,7 +402,9 @@ async function install({ copy = false, agent = "codex" } = {}) {
403
402
  progress.done("antigravity ✓");
404
403
  console.log(`Hooks → ${hooksPath}`);
405
404
  console.log(`MCP → ${mcpConfigPaths.join(", ")}`);
405
+ console.log(`Graph → ${graphStrategy}`);
406
406
  console.log(`Embeddings: ${warmResult.fileCount || 0} files, ${warmResult.skillCount || 0} skills`);
407
+ console.log(`Graph embeddings: ${formatCodeReviewGraphEmbedding(warmResult.graphEmbedding)}`);
407
408
  console.log("Restart Antigravity to activate ContextOS.");
408
409
  return;
409
410
  }
@@ -423,7 +424,9 @@ async function install({ copy = false, agent = "codex" } = {}) {
423
424
  progress.done("copilot ✓");
424
425
  console.log(`Instructions → ${hooksPath}`);
425
426
  console.log(`MCP → ${mcpConfigPath}`);
427
+ console.log(`Graph → ${graphStrategy}`);
426
428
  console.log(`Embeddings: ${warmResult.fileCount || 0} files, ${warmResult.skillCount || 0} skills`);
429
+ console.log(`Graph embeddings: ${formatCodeReviewGraphEmbedding(warmResult.graphEmbedding)}`);
427
430
  console.log("Restart VS Code to activate ContextOS.");
428
431
  return;
429
432
  }
@@ -433,8 +436,7 @@ async function install({ copy = false, agent = "codex" } = {}) {
433
436
  }
434
437
 
435
438
  progress.step(10, "copying marketplace");
436
- const marketplaceRoot = path.join(codexHome(), "marketplaces", "contextos");
437
- copyPackageRoot({ rootDir, targetRoot: marketplaceRoot });
439
+ const marketplaceRoot = activeCodexMarketplaceRoot();
438
440
 
439
441
  progress.step(25, "refreshing codex plugin");
440
442
  tryRunCodex(["plugin", "remove", "ctx@contextos"]);
@@ -459,7 +461,9 @@ async function install({ copy = false, agent = "codex" } = {}) {
459
461
  console.log(`Hooks → ${hooksPath}`);
460
462
  console.log(`MCP → ctx-mcp installed`);
461
463
  console.log(`Proxies → ${proxyResult.wrapped.length ? proxyResult.wrapped.map((item) => item.name).join(", ") : "none changed"}`);
464
+ console.log(`Graph → ${graphStrategy}`);
462
465
  console.log(`Embeddings: ${warmResult.fileCount || 0} files, ${warmResult.skillCount || 0} skills`);
466
+ console.log(`Graph embeddings: ${formatCodeReviewGraphEmbedding(warmResult.graphEmbedding)}`);
463
467
  console.log("Restart Codex to activate ContextOS.");
464
468
  } catch (error) {
465
469
  progress.fail("install failed");
@@ -467,6 +471,19 @@ async function install({ copy = false, agent = "codex" } = {}) {
467
471
  }
468
472
  }
469
473
 
474
+ function graphStrategyForInstall() {
475
+ let mcpServerNames = [];
476
+ try {
477
+ mcpServerNames = readCodexMcpServers().map((server) => server.name);
478
+ } catch {
479
+ // Graph detection is diagnostic and must not block installation.
480
+ }
481
+ return formatGraphStrategy(detectGraphStrategy({
482
+ cwd: process.cwd(),
483
+ mcpServerNames
484
+ }));
485
+ }
486
+
470
487
  async function warmInstallEmbeddings() {
471
488
  const dataDir = contextOSDataDir();
472
489
  const modelReady = isModelCacheReady(dataDir);
@@ -501,7 +518,21 @@ async function warmInstallEmbeddings() {
501
518
  allowRemote: !modelReady
502
519
  })
503
520
  : { count: 0 };
504
- return { ...result, modelAlreadyCached: modelReady, fileCount: fileResult.count, skillCount: skillResult.count, workflowCount: workflowResult.count };
521
+ const graphEmbedding = embedCodeReviewGraph({ cwd: process.cwd() });
522
+ return { ...result, modelAlreadyCached: modelReady, fileCount: fileResult.count, skillCount: skillResult.count, workflowCount: workflowResult.count, graphEmbedding };
523
+ }
524
+
525
+ function activeCodexMarketplaceRoot() {
526
+ return path.join(codexHome(), "marketplaces", "contextos");
527
+ }
528
+
529
+ function syncActiveCodexMarketplace() {
530
+ const result = syncPackageRoot({
531
+ rootDir,
532
+ targetRoot: activeCodexMarketplaceRoot()
533
+ });
534
+ writeInnerGitignore(result.targetRoot);
535
+ return result;
505
536
  }
506
537
 
507
538
  function tryRunCodex(args) {
@@ -559,12 +590,13 @@ async function debug(task) {
559
590
  cwd,
560
591
  prompt: task,
561
592
  dataDir: contextOSDataDir(),
562
- maxFiles: 3,
593
+ maxFiles: 7,
594
+ maxSkills: 7,
563
595
  embeddingTimeoutMs: Number(process.env.CONTEXTOS_EMBEDDING_DEBUG_TIMEOUT_MS || 5000)
564
596
  });
565
597
  const rules = scored.scoredRules;
566
- const relevantFiles = scored.suggestedFiles.slice(0, 3);
567
- const suggestedSkills = (scored.suggestedSkills || []).slice(0, 3);
598
+ const relevantFiles = scored.suggestedFiles.slice(0, 7);
599
+ const suggestedSkills = (scored.suggestedSkills || []).slice(0, 7);
568
600
  const suggestedWorkflows = (scored.suggestedWorkflows || []).slice(0, 2);
569
601
  const scheduled = scheduleContext({ rules, relevantFiles, suggestedSkills, suggestedWorkflows });
570
602
 
@@ -611,7 +643,23 @@ async function debug(task) {
611
643
  console.log(scheduled.additionalContext || "(empty)");
612
644
  }
613
645
 
614
- async function warmEmbeddings(task) {
646
+ async function warmEmbeddings(task, { syncMarketplace = true, quiet = false } = {}) {
647
+ const warmResult = await warmWorkspaceIndexes({ task });
648
+ const marketplaceSync = syncMarketplace ? syncActiveCodexMarketplace() : null;
649
+ if (quiet) return { ...warmResult, marketplaceSync };
650
+ console.log(`Warmed ${warmResult.ruleCount} embeddings`);
651
+ console.log(`Warmed ${warmResult.fileCount} file path embeddings`);
652
+ console.log(`Warmed ${warmResult.skillCount} skill embeddings`);
653
+ console.log(`Warmed ${warmResult.workflowCount} workflow embeddings`);
654
+ console.log(`Cache: ${warmResult.cachePath}`);
655
+ console.log(`Graph embeddings: ${formatCodeReviewGraphEmbedding(warmResult.graphEmbedding)}`);
656
+ if (marketplaceSync) {
657
+ console.log(`Marketplace: ${marketplaceSync.synced ? "synced" : "already active"} (${marketplaceSync.targetRoot})`);
658
+ }
659
+ return { ...warmResult, marketplaceSync };
660
+ }
661
+
662
+ async function warmWorkspaceIndexes({ task = "project context" } = {}) {
615
663
  const cwd = process.cwd();
616
664
  const merged = readAgentsChain({ cwd });
617
665
  const rules = scoreRules(filterActionableRules(parseRules(merged.content)), task, []);
@@ -637,11 +685,26 @@ async function warmEmbeddings(task) {
637
685
  dataDir: contextOSDataDir(),
638
686
  allowRemote: true
639
687
  });
640
- console.log(`Warmed ${result.count} embeddings`);
641
- console.log(`Warmed ${fileResult.count} file path embeddings`);
642
- console.log(`Warmed ${skillResult.count} skill embeddings`);
643
- console.log(`Warmed ${workflowResult.count} workflow embeddings`);
644
- console.log(`Cache: ${result.cachePath}`);
688
+ const graphEmbedding = embedCodeReviewGraph({ cwd });
689
+ return {
690
+ ruleCount: result.count,
691
+ fileCount: fileResult.count,
692
+ skillCount: skillResult.count,
693
+ workflowCount: workflowResult.count,
694
+ cachePath: result.cachePath,
695
+ graphEmbedding
696
+ };
697
+ }
698
+
699
+ async function refresh() {
700
+ const marketplaceSync = syncActiveCodexMarketplace();
701
+ const invalidatedBridge = invalidateCtxMcpSocket(contextOSDataDir());
702
+ const warmResult = await warmInstallEmbeddings();
703
+ console.log(`Marketplace: ${marketplaceSync.synced ? "synced" : "already active"} (${marketplaceSync.targetRoot})`);
704
+ console.log(`Indexes: ${warmResult.fileCount || 0} file paths rebuilt`);
705
+ console.log(`Graph embeddings: ${formatCodeReviewGraphEmbedding(warmResult.graphEmbedding)}`);
706
+ if (invalidatedBridge) console.log("Bridge: stale private socket invalidated");
707
+ console.log("Restart Codex if ctx-mcp was already running.");
645
708
  }
646
709
 
647
710
  function printSetupBanner() {
@@ -668,6 +731,7 @@ async function askSetupYesNo(rl, question, defaultValue = true) {
668
731
  async function setup({ args = [], cwd = process.cwd() } = {}) {
669
732
  const options = parseSetupArgs(args);
670
733
  const interactive = !options.yes && process.stdin.isTTY;
734
+ let outputConfig = loadOutputConfig({ dataRoot: contextOSDataDir() });
671
735
 
672
736
  printSetupBanner();
673
737
  console.log(`◇ Installation directory:\n│ ${cwd}`);
@@ -708,11 +772,22 @@ async function setup({ args = [], cwd = process.cwd() } = {}) {
708
772
  rl.close();
709
773
  }
710
774
  }
775
+
776
+ console.log("");
777
+ console.log("◇ Configure prompt output:");
778
+ outputConfig = await configureOutputSections({
779
+ dataRoot: contextOSDataDir(),
780
+ select: multiSelect
781
+ });
711
782
  }
712
783
 
713
784
  console.log("");
714
785
  console.log("◇ Ready to setup:");
715
- for (const line of setupSummaryLines({ cwd, ...options })) console.log(`│ ${line}`);
786
+ for (const line of setupSummaryLines({
787
+ cwd,
788
+ ...options,
789
+ promptSections: enabledOutputSectionsLabel(outputConfig)
790
+ })) console.log(`│ ${line}`);
716
791
  console.log("");
717
792
 
718
793
  if (!options.agents.length) throw new Error("No agents selected. Use --agents codex,claude,antigravity,copilot.");
@@ -793,6 +868,11 @@ try {
793
868
  console.log(usage());
794
869
  } else if (command === "--version" || command === "-v") {
795
870
  console.log(packageVersion());
871
+ } else if (command === "--config" || command === "config") {
872
+ await configureOutputSections({
873
+ dataRoot: contextOSDataDir(),
874
+ select: multiSelect
875
+ });
796
876
  } else if (command === "install") {
797
877
  const copy = args.includes("--copy");
798
878
  const explicitAgents = installAgentsFromArgs(args);
@@ -834,6 +914,12 @@ try {
834
914
  const task = marker >= 0 ? args.slice(marker + 1).join(" ") : args.slice(1).join(" ");
835
915
  if (!task.trim()) throw new Error('Usage: ctx debug -- "task"');
836
916
  await debug(task);
917
+ } else if (command === "refresh") {
918
+ await refresh();
919
+ } else if (command === "autowarm") {
920
+ const marker = args.indexOf("--");
921
+ const task = marker >= 0 ? args.slice(marker + 1).join(" ") : args.slice(1).join(" ");
922
+ await warmEmbeddings(task || "project context", { syncMarketplace: false, quiet: true });
837
923
  } else if (command === "embeddings") {
838
924
  if (args[1] === "warm") {
839
925
  const marker = args.indexOf("--");
@@ -874,6 +960,18 @@ try {
874
960
  const installed = await runCommunitySkillInstaller(agents);
875
961
  if (installed === 0) {
876
962
  console.log(`\n${DIM}No installations were completed.${RESET}`);
963
+ } else {
964
+ console.log(`${CYAN}◇${RESET} ${BOLD}Syncing installed skills${RESET}`);
965
+ await streamSetupOutput(() => syncSkills({
966
+ cwd: process.cwd(),
967
+ args: ["--skills", "--agents", agents.map((agent) => agent === "agy" ? "antigravity" : agent).join(","), "--yes"],
968
+ rebuildSkillEmbeddings: async ({ cwd, sourceDir }) => warmSkillEmbeddings({
969
+ cwd,
970
+ dataDir: contextOSDataDir(),
971
+ allowRemote: !isModelCacheReady(contextOSDataDir()),
972
+ skills: scanSkills({ cwd, roots: [sourceDir] })
973
+ })
974
+ }));
877
975
  }
878
976
  console.log("");
879
977
  } else if (command === "sync") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minhpnq1807/contextos",
3
- "version": "0.5.42",
3
+ "version": "0.5.45",
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": {
@@ -52,6 +52,7 @@
52
52
  "dependencies": {
53
53
  "@modelcontextprotocol/sdk": "^1.29.0",
54
54
  "@xenova/transformers": "^2.17.2",
55
+ "smol-toml": "^1.6.1",
55
56
  "sql.js": "^1.14.1",
56
57
  "zod": "^4.4.3"
57
58
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ctx",
3
- "version": "0.5.41",
3
+ "version": "0.5.45",
4
4
  "description": "Inject task-relevant AGENTS.md rules into Codex through plugin hooks.",
5
5
  "author": {
6
6
  "name": "ContextOS"
@@ -1,12 +1,18 @@
1
1
  #!/usr/bin/env node
2
- import { readStdinJson, writeJson, failOpen, logDebug, pluginRuntimeFile, pluginDataRoot, resolveHookCwd } from "../lib/hook-io.js";
2
+ import { armHookDeadline, exitAfterStdout, readStdinJson, writeJson, failOpen, logDebug, pluginRuntimeFile, pluginDataRoot, resolveHookCwd } from "../lib/hook-io.js";
3
3
  import { handlePromptPayload } from "../lib/prompt-hook.js";
4
4
  import { appendTelemetry } from "../lib/telemetry.js";
5
5
 
6
6
  const started = Date.now();
7
+ const fallback = {
8
+ continue: true,
9
+ suppressOutput: true
10
+ };
11
+ let deadline;
7
12
 
8
13
  try {
9
14
  const payload = await readStdinJson();
15
+ deadline = armHookDeadline("UserPromptSubmit", fallback);
10
16
  const cwd = resolveHookCwd(payload);
11
17
  const normalized = { ...payload, cwd };
12
18
 
@@ -18,13 +24,10 @@ try {
18
24
  mcpDataDir: pluginDataRoot(),
19
25
  started
20
26
  }));
27
+ deadline.clear();
28
+ exitAfterStdout(0);
21
29
  } catch (error) {
22
- failOpen("UserPromptSubmit", error, {
23
- continue: true,
24
- suppressOutput: true,
25
- hookSpecificOutput: {
26
- hookEventName: "UserPromptSubmit",
27
- additionalContext: ""
28
- }
29
- });
30
+ deadline?.clear();
31
+ failOpen("UserPromptSubmit", error, fallback);
32
+ exitAfterStdout(0);
30
33
  }