@minhpnq1807/contextos 0.5.45 → 0.5.46
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 +8 -0
- package/README.md +4 -4
- package/bin/ctx.js +29 -9
- package/package.json +1 -1
- package/plugins/ctx/.codex-plugin/plugin.json +1 -1
- package/plugins/ctx/lib/output-config.js +37 -2
- package/plugins/ctx/lib/prompt-hook.js +12 -15
- package/plugins/ctx/lib/setup-wizard.js +3 -1
- package/plugins/ctx/lib/skill-discoverer.js +59 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.46
|
|
4
|
+
|
|
5
|
+
- **Configurable prompt suggestion limits:** `ctx --config` and interactive `ctx setup` now let users choose how many suggested files, skills, and workflows appear in prompt context. Defaults are five each, with caps of 20 files, 10 skills, and 5 workflows.
|
|
6
|
+
- **Limit-aware prompt hooks and debug:** `UserPromptSubmit` hooks, direct fallback scoring, the private `ctx-mcp` bridge request, and `ctx debug` now all honor the saved suggestion limits instead of using hard-coded counts.
|
|
7
|
+
- **Document authoring skill intent:** Prompts that create, edit, update, or maintain documents, workspace docs, README files, wiki pages, manuals, guides, specs, or ADRs now prioritize documentation skills such as `doc-coauthoring`, `documentation`, `docs-architect`, `readme`, and `wiki-page-writer`.
|
|
8
|
+
- **Safer document skill gating:** Document-processing and workspace-automation skills such as Azure Document Intelligence, DocuSign, Asana, Slack, Google Docs, and Notion no longer win generic document-writing prompts unless the provider or processing task is explicitly named.
|
|
9
|
+
- **Setup summary clarity:** The setup wizard summary now reports the saved prompt suggestion limits alongside the enabled prompt sections so users can review output volume immediately.
|
|
10
|
+
|
|
3
11
|
## 0.5.45
|
|
4
12
|
|
|
5
13
|
- **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`.
|
package/README.md
CHANGED
|
@@ -444,7 +444,7 @@ This warning comes from a transitive dependency in the local embedding/WASM stac
|
|
|
444
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
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. |
|
|
446
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
|
|
447
|
+
| `ctx --config` | Opens an interactive panel for prompt sections and suggestion limits. | 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`, then lets you set suggestion counts for files, skills, and workflows. |
|
|
448
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. |
|
|
449
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. |
|
|
450
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. |
|
|
@@ -515,13 +515,13 @@ Prompt scoring does not walk the repository for file candidates or import expans
|
|
|
515
515
|
|
|
516
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
517
|
|
|
518
|
-
Use `ctx --config` to choose which prompt sections ContextOS injects. Interactive `ctx setup`
|
|
518
|
+
Use `ctx --config` to choose which prompt sections ContextOS injects and how many suggestions each section may show. Interactive `ctx setup` includes the same section picker and limit prompts, 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`. Defaults are five suggested files, five skills, and five workflows; caps are 20 files, 10 skills, and 5 workflows. Disabling rules hides both critical and additional relevant rule sections; compliance metadata remains available for reports.
|
|
519
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.
|
|
520
|
+
Injected prompt sections are intentionally compact: rules show only detected rule text, files show a comma-separated inline list of 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
521
|
|
|
522
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
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.
|
|
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 and MCP tasks activate specialized skills without walking the source tree on every prompt. Document-authoring prompts also get explicit intent handling for README, wiki, workspace documentation, guides, specs, and ADR work, while document-processing or workspace-automation providers only rank highly when the prompt actually names that provider or processing task.
|
|
525
525
|
|
|
526
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
527
|
|
package/bin/ctx.js
CHANGED
|
@@ -34,7 +34,7 @@ import { scanSkills, warmSkillEmbeddings } from "../plugins/ctx/lib/skill-discov
|
|
|
34
34
|
import { parsePassthroughArgs, runPassthrough } from "../plugins/ctx/lib/passthrough.js";
|
|
35
35
|
import { parseAgentList, parseSetupArgs, setupSummaryLines } from "../plugins/ctx/lib/setup-wizard.js";
|
|
36
36
|
import { multiSelect } from "../plugins/ctx/lib/multi-select.js";
|
|
37
|
-
import { configureOutputSections, enabledOutputSectionsLabel, loadOutputConfig } from "../plugins/ctx/lib/output-config.js";
|
|
37
|
+
import { configureOutputSections, enabledOutputSectionsLabel, loadOutputConfig, outputConfigLimits, outputConfigLimitsLabel } from "../plugins/ctx/lib/output-config.js";
|
|
38
38
|
import { syncWorkflows, warmWorkflowEmbeddings } from "../plugins/ctx/lib/workflow-discoverer.js";
|
|
39
39
|
import { checkForUpdate } from "../plugins/ctx/lib/update-notifier.js";
|
|
40
40
|
import { fetchSkillsForAgents, printSkillRecommendations, getAllLibraries, getInstallCommands } from "../plugins/ctx/lib/skill-library.js";
|
|
@@ -586,18 +586,20 @@ function contextOSWorkspaceDataDir(cwd = process.cwd()) {
|
|
|
586
586
|
|
|
587
587
|
async function debug(task) {
|
|
588
588
|
const cwd = process.cwd();
|
|
589
|
+
const limits = outputConfigLimits(loadOutputConfig({ dataRoot: contextOSDataDir() }));
|
|
589
590
|
const scored = await scoreContext({
|
|
590
591
|
cwd,
|
|
591
592
|
prompt: task,
|
|
592
593
|
dataDir: contextOSDataDir(),
|
|
593
|
-
maxFiles:
|
|
594
|
-
maxSkills:
|
|
594
|
+
maxFiles: limits.files,
|
|
595
|
+
maxSkills: limits.skills,
|
|
596
|
+
maxWorkflows: limits.workflows,
|
|
595
597
|
embeddingTimeoutMs: Number(process.env.CONTEXTOS_EMBEDDING_DEBUG_TIMEOUT_MS || 5000)
|
|
596
598
|
});
|
|
597
599
|
const rules = scored.scoredRules;
|
|
598
|
-
const relevantFiles = scored.suggestedFiles.slice(0,
|
|
599
|
-
const suggestedSkills = (scored.suggestedSkills || []).slice(0,
|
|
600
|
-
const suggestedWorkflows = (scored.suggestedWorkflows || []).slice(0,
|
|
600
|
+
const relevantFiles = scored.suggestedFiles.slice(0, limits.files);
|
|
601
|
+
const suggestedSkills = (scored.suggestedSkills || []).slice(0, limits.skills);
|
|
602
|
+
const suggestedWorkflows = (scored.suggestedWorkflows || []).slice(0, limits.workflows);
|
|
601
603
|
const scheduled = scheduleContext({ rules, relevantFiles, suggestedSkills, suggestedWorkflows });
|
|
602
604
|
|
|
603
605
|
console.log("ContextOS debug");
|
|
@@ -728,6 +730,21 @@ async function askSetupYesNo(rl, question, defaultValue = true) {
|
|
|
728
730
|
return !/^n(o)?$/i.test(answer.trim());
|
|
729
731
|
}
|
|
730
732
|
|
|
733
|
+
async function askOutputLimit({ option, currentValue }) {
|
|
734
|
+
if (!process.stdin.isTTY) return currentValue;
|
|
735
|
+
const rl = readline.createInterface({ input, output });
|
|
736
|
+
try {
|
|
737
|
+
const answer = await rl.question(`◇ ${option.label} limit (0-${option.max}, current ${currentValue}): `);
|
|
738
|
+
const trimmed = answer.trim();
|
|
739
|
+
if (!trimmed) return currentValue;
|
|
740
|
+
const value = Number(trimmed);
|
|
741
|
+
if (!Number.isFinite(value)) return currentValue;
|
|
742
|
+
return Math.max(0, Math.min(option.max, Math.trunc(value)));
|
|
743
|
+
} finally {
|
|
744
|
+
rl.close();
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
731
748
|
async function setup({ args = [], cwd = process.cwd() } = {}) {
|
|
732
749
|
const options = parseSetupArgs(args);
|
|
733
750
|
const interactive = !options.yes && process.stdin.isTTY;
|
|
@@ -777,7 +794,8 @@ async function setup({ args = [], cwd = process.cwd() } = {}) {
|
|
|
777
794
|
console.log("◇ Configure prompt output:");
|
|
778
795
|
outputConfig = await configureOutputSections({
|
|
779
796
|
dataRoot: contextOSDataDir(),
|
|
780
|
-
select: multiSelect
|
|
797
|
+
select: multiSelect,
|
|
798
|
+
askLimit: askOutputLimit
|
|
781
799
|
});
|
|
782
800
|
}
|
|
783
801
|
|
|
@@ -786,7 +804,8 @@ async function setup({ args = [], cwd = process.cwd() } = {}) {
|
|
|
786
804
|
for (const line of setupSummaryLines({
|
|
787
805
|
cwd,
|
|
788
806
|
...options,
|
|
789
|
-
promptSections: enabledOutputSectionsLabel(outputConfig)
|
|
807
|
+
promptSections: enabledOutputSectionsLabel(outputConfig),
|
|
808
|
+
promptLimits: outputConfigLimitsLabel(outputConfig)
|
|
790
809
|
})) console.log(`│ ${line}`);
|
|
791
810
|
console.log("");
|
|
792
811
|
|
|
@@ -871,7 +890,8 @@ try {
|
|
|
871
890
|
} else if (command === "--config" || command === "config") {
|
|
872
891
|
await configureOutputSections({
|
|
873
892
|
dataRoot: contextOSDataDir(),
|
|
874
|
-
select: multiSelect
|
|
893
|
+
select: multiSelect,
|
|
894
|
+
askLimit: askOutputLimit
|
|
875
895
|
});
|
|
876
896
|
} else if (command === "install") {
|
|
877
897
|
const copy = args.includes("--copy");
|
package/package.json
CHANGED
|
@@ -13,9 +13,16 @@ export const OUTPUT_SECTION_OPTIONS = [
|
|
|
13
13
|
{ value: "workflows", label: "Suggested workflow for this task", hint: "Include matching workflow recommendations." }
|
|
14
14
|
];
|
|
15
15
|
|
|
16
|
+
export const OUTPUT_LIMIT_OPTIONS = [
|
|
17
|
+
{ value: "files", label: "Suggested files", defaultValue: 5, max: 20 },
|
|
18
|
+
{ value: "skills", label: "Suggested skills", defaultValue: 5, max: 10 },
|
|
19
|
+
{ value: "workflows", label: "Suggested workflows", defaultValue: 5, max: 5 }
|
|
20
|
+
];
|
|
21
|
+
|
|
16
22
|
export function defaultOutputConfig() {
|
|
17
23
|
return {
|
|
18
|
-
sections: Object.fromEntries(OUTPUT_SECTION_OPTIONS.map((option) => [option.value, true]))
|
|
24
|
+
sections: Object.fromEntries(OUTPUT_SECTION_OPTIONS.map((option) => [option.value, true])),
|
|
25
|
+
limits: Object.fromEntries(OUTPUT_LIMIT_OPTIONS.map((option) => [option.value, option.defaultValue]))
|
|
19
26
|
};
|
|
20
27
|
}
|
|
21
28
|
|
|
@@ -49,9 +56,19 @@ export function enabledOutputSectionsLabel(config = loadOutputConfig()) {
|
|
|
49
56
|
return enabled.length ? enabled.join(", ") : "(none)";
|
|
50
57
|
}
|
|
51
58
|
|
|
59
|
+
export function outputConfigLimits(config = loadOutputConfig()) {
|
|
60
|
+
return normalizeOutputConfig(config).limits;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function outputConfigLimitsLabel(config = loadOutputConfig()) {
|
|
64
|
+
const limits = outputConfigLimits(config);
|
|
65
|
+
return OUTPUT_LIMIT_OPTIONS.map((option) => `${option.value}: ${limits[option.value]}`).join(", ");
|
|
66
|
+
}
|
|
67
|
+
|
|
52
68
|
export async function configureOutputSections({
|
|
53
69
|
dataRoot = defaultDataRoot(),
|
|
54
70
|
select,
|
|
71
|
+
askLimit,
|
|
55
72
|
logger = console.log
|
|
56
73
|
} = {}) {
|
|
57
74
|
if (typeof select !== "function") throw new Error("configureOutputSections requires a multi-select function");
|
|
@@ -64,11 +81,19 @@ export async function configureOutputSections({
|
|
|
64
81
|
}))
|
|
65
82
|
});
|
|
66
83
|
const selectedSet = new Set(selected);
|
|
84
|
+
const limits = {};
|
|
85
|
+
for (const option of OUTPUT_LIMIT_OPTIONS) {
|
|
86
|
+
limits[option.value] = typeof askLimit === "function"
|
|
87
|
+
? await askLimit({ option, currentValue: current.limits[option.value] })
|
|
88
|
+
: current.limits[option.value];
|
|
89
|
+
}
|
|
67
90
|
const saved = saveOutputConfig({
|
|
68
|
-
sections: Object.fromEntries(OUTPUT_SECTION_OPTIONS.map((option) => [option.value, selectedSet.has(option.value)]))
|
|
91
|
+
sections: Object.fromEntries(OUTPUT_SECTION_OPTIONS.map((option) => [option.value, selectedSet.has(option.value)])),
|
|
92
|
+
limits
|
|
69
93
|
}, { dataRoot });
|
|
70
94
|
logger(`│ Saved ContextOS prompt section config: ${outputConfigPath(dataRoot)}`);
|
|
71
95
|
logger(`│ Enabled sections: ${enabledOutputSectionsLabel(saved)}`);
|
|
96
|
+
logger(`│ Suggest limits: ${outputConfigLimitsLabel(saved)}`);
|
|
72
97
|
return saved;
|
|
73
98
|
}
|
|
74
99
|
|
|
@@ -80,6 +105,16 @@ function normalizeOutputConfig(config = {}) {
|
|
|
80
105
|
typeof config.sections?.[option.value] === "boolean"
|
|
81
106
|
? config.sections[option.value]
|
|
82
107
|
: defaults.sections[option.value]
|
|
108
|
+
])),
|
|
109
|
+
limits: Object.fromEntries(OUTPUT_LIMIT_OPTIONS.map((option) => [
|
|
110
|
+
option.value,
|
|
111
|
+
normalizeLimit(config.limits?.[option.value], option)
|
|
83
112
|
]))
|
|
84
113
|
};
|
|
85
114
|
}
|
|
115
|
+
|
|
116
|
+
function normalizeLimit(value, option) {
|
|
117
|
+
const number = Number(value);
|
|
118
|
+
if (!Number.isFinite(number)) return option.defaultValue;
|
|
119
|
+
return Math.max(0, Math.min(option.max, Math.trunc(number)));
|
|
120
|
+
}
|
|
@@ -3,15 +3,11 @@ import { appendJsonLine, writeJsonFile } from "./fs-utils.js";
|
|
|
3
3
|
import { maybeAutoWarmWorkspace } from "./auto-warm.js";
|
|
4
4
|
import { callCtxScoreContext } from "./ctx-mcp-client.js";
|
|
5
5
|
import { resolveHookCwd } from "./hook-io.js";
|
|
6
|
-
import { loadOutputConfig } from "./output-config.js";
|
|
6
|
+
import { loadOutputConfig, outputConfigLimits } from "./output-config.js";
|
|
7
7
|
import { scoreContext as scoreContextDirect } from "./score-context.js";
|
|
8
8
|
import fs from "node:fs";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
|
|
11
|
-
const PROMPT_FILE_LIMIT = 7;
|
|
12
|
-
const PROMPT_SKILL_LIMIT = 7;
|
|
13
|
-
const PROMPT_WORKFLOW_LIMIT = 2;
|
|
14
|
-
|
|
15
11
|
export async function handlePromptPayload(
|
|
16
12
|
payload,
|
|
17
13
|
{
|
|
@@ -33,6 +29,8 @@ export async function handlePromptPayload(
|
|
|
33
29
|
const cwd = resolvePromptTargetCwd({ cwd: hookCwd, prompt });
|
|
34
30
|
const openFiles = payload.openFiles || payload.open_files || payload.files || [];
|
|
35
31
|
const dataDir = dataPath ? path.dirname(dataPath) : undefined;
|
|
32
|
+
const effectiveOutputConfig = outputConfig || loadOutputConfig();
|
|
33
|
+
const promptLimits = outputConfigLimits(effectiveOutputConfig);
|
|
36
34
|
|
|
37
35
|
let scored;
|
|
38
36
|
try {
|
|
@@ -40,9 +38,9 @@ export async function handlePromptPayload(
|
|
|
40
38
|
cwd,
|
|
41
39
|
prompt,
|
|
42
40
|
openFiles,
|
|
43
|
-
maxFiles:
|
|
44
|
-
maxSkills:
|
|
45
|
-
maxWorkflows:
|
|
41
|
+
maxFiles: promptLimits.files,
|
|
42
|
+
maxSkills: promptLimits.skills,
|
|
43
|
+
maxWorkflows: promptLimits.workflows
|
|
46
44
|
}, {
|
|
47
45
|
dataDir: mcpDataDir || dataDir,
|
|
48
46
|
timeoutMs: Number(process.env.CONTEXTOS_MCP_BRIDGE_TIMEOUT_MS || 2000)
|
|
@@ -53,9 +51,9 @@ export async function handlePromptPayload(
|
|
|
53
51
|
cwd,
|
|
54
52
|
prompt,
|
|
55
53
|
openFiles,
|
|
56
|
-
maxFiles:
|
|
57
|
-
maxSkills:
|
|
58
|
-
maxWorkflows:
|
|
54
|
+
maxFiles: promptLimits.files,
|
|
55
|
+
maxSkills: promptLimits.skills,
|
|
56
|
+
maxWorkflows: promptLimits.workflows,
|
|
59
57
|
dataDir: mcpDataDir || dataDir,
|
|
60
58
|
embeddingTimeoutMs: Number(process.env.CONTEXTOS_HOOK_EMBEDDING_TIMEOUT_MS || 500),
|
|
61
59
|
fileEmbeddingTimeoutMs: Number(process.env.CONTEXTOS_HOOK_FILE_EMBEDDING_TIMEOUT_MS || 1000)
|
|
@@ -76,10 +74,9 @@ export async function handlePromptPayload(
|
|
|
76
74
|
|
|
77
75
|
if (scored.error) throw new Error(scored.error);
|
|
78
76
|
const scoredRules = scored.scoredRules || [];
|
|
79
|
-
const relevantFiles = (scored.suggestedFiles || []).slice(0,
|
|
80
|
-
const suggestedSkills = (scored.suggestedSkills || []).slice(0,
|
|
81
|
-
const suggestedWorkflows = (scored.suggestedWorkflows || []).slice(0,
|
|
82
|
-
const effectiveOutputConfig = outputConfig || loadOutputConfig();
|
|
77
|
+
const relevantFiles = (scored.suggestedFiles || []).slice(0, promptLimits.files);
|
|
78
|
+
const suggestedSkills = (scored.suggestedSkills || []).slice(0, promptLimits.skills);
|
|
79
|
+
const suggestedWorkflows = (scored.suggestedWorkflows || []).slice(0, promptLimits.workflows);
|
|
83
80
|
const scheduled = scheduleContext({ rules: scoredRules, relevantFiles, suggestedSkills, suggestedWorkflows, outputConfig: effectiveOutputConfig });
|
|
84
81
|
const contextEmptyReason = emptyContextReason({ scheduled, outputConfig: effectiveOutputConfig, injectContext });
|
|
85
82
|
const autoWarm = autoWarmWorkspace({
|
|
@@ -37,7 +37,8 @@ export function setupSummaryLines({
|
|
|
37
37
|
agents = DEFAULT_AGENTS,
|
|
38
38
|
syncRules = true,
|
|
39
39
|
syncSkills = true,
|
|
40
|
-
promptSections = null
|
|
40
|
+
promptSections = null,
|
|
41
|
+
promptLimits = null
|
|
41
42
|
} = {}) {
|
|
42
43
|
const lines = [
|
|
43
44
|
`Installation directory: ${cwd}`,
|
|
@@ -47,5 +48,6 @@ export function setupSummaryLines({
|
|
|
47
48
|
`skillshare skill sync: ${syncSkills ? "enabled" : "skipped"}`
|
|
48
49
|
];
|
|
49
50
|
if (promptSections !== null) lines.push(`Prompt sections shown: ${promptSections}`);
|
|
51
|
+
if (promptLimits !== null) lines.push(`Prompt suggest limits: ${promptLimits}`);
|
|
50
52
|
return lines;
|
|
51
53
|
}
|
|
@@ -20,9 +20,10 @@ const GENERIC_SKILL_TOKENS = new Set([
|
|
|
20
20
|
"users", "when", "where", "whether", "with"
|
|
21
21
|
]);
|
|
22
22
|
const SPECIALIZED_SKILL_TOKENS = new Set([
|
|
23
|
-
"android", "
|
|
24
|
-
"
|
|
25
|
-
"
|
|
23
|
+
"android", "architecture", "authorization", "cicd", "documentation", "docs", "document",
|
|
24
|
+
"eas", "expo", "frontend", "ios", "next", "nextjs", "mcp", "modelcontextprotocol",
|
|
25
|
+
"postgres", "postgresql", "react", "react-native", "readme", "tailwind", "typescript",
|
|
26
|
+
"ui", "wiki", "writer"
|
|
26
27
|
]);
|
|
27
28
|
|
|
28
29
|
const scanCache = new Map();
|
|
@@ -312,6 +313,8 @@ function isSkillDomainEligible(normalizedPrompt, enriched, projectTokens = new S
|
|
|
312
313
|
if (isMcpSkill(skillText) && !isMcpRelevantTask(normalizedPrompt, projectTokens)) return false;
|
|
313
314
|
if (isOffensiveSecuritySkill(skillText) && !isSecurityTask(normalizedPrompt)) return false;
|
|
314
315
|
if (isPlatformCommerceSkill(skillText) && !isPlatformCommerceTask(normalizedPrompt, skillText)) return false;
|
|
316
|
+
if (isDocumentProcessingSkill(skillText) && !isDocumentProcessingTask(normalizedPrompt, skillText)) return false;
|
|
317
|
+
if (isWorkspaceAutomationSkill(skillText) && !isWorkspaceAutomationTask(normalizedPrompt, skillText)) return false;
|
|
315
318
|
if (!/\beas\b/.test(normalizedPrompt)) return true;
|
|
316
319
|
if (!/\b(android|ios)\b/.test(skillText)) return true;
|
|
317
320
|
return /\b(eas|expo|cicd)\b/.test(skillText);
|
|
@@ -319,6 +322,10 @@ function isSkillDomainEligible(normalizedPrompt, enriched, projectTokens = new S
|
|
|
319
322
|
|
|
320
323
|
function skillIntentBonus(normalizedPrompt, enriched, projectTokens = new Set()) {
|
|
321
324
|
const skillText = normalize(`${enriched.name} ${enriched.description}`);
|
|
325
|
+
if (isDocumentAuthoringTask(normalizedPrompt)
|
|
326
|
+
&& /\b(documentation|document|docs|doc|readme|wiki|writer|writing|coauthor|technical documentation|architecture documentation|onboarding|office productivity)\b/.test(skillText)) {
|
|
327
|
+
return 0.48;
|
|
328
|
+
}
|
|
322
329
|
if (isMcpRelevantTask(normalizedPrompt, projectTokens)
|
|
323
330
|
&& /\b(mcp|model context protocol|modelcontextprotocol|agent memory|tool developer|tool builder)\b/.test(skillText)) {
|
|
324
331
|
return 0.48;
|
|
@@ -368,6 +375,20 @@ function skillRelevancePriority(normalizedPrompt, enriched, projectTokens = new
|
|
|
368
375
|
const skillText = normalize(`${enriched.name} ${enriched.description}`);
|
|
369
376
|
const skillName = normalize(enriched.name);
|
|
370
377
|
let priority = 0;
|
|
378
|
+
if (isDocumentAuthoringTask(normalizedPrompt)) {
|
|
379
|
+
if (skillName === "doc coauthoring") priority += 1300;
|
|
380
|
+
if (skillName === "documentation") priority += 720;
|
|
381
|
+
if (skillName === "docs architect") priority += 700;
|
|
382
|
+
if (skillName === "readme") priority += 660;
|
|
383
|
+
if (skillName === "wiki page writer") priority += 640;
|
|
384
|
+
if (skillName === "wiki architect") priority += 620;
|
|
385
|
+
if (skillName === "wiki onboarding") priority += 600;
|
|
386
|
+
if (skillName === "writer" || skillName === "docx" || skillName === "office productivity") priority += 560;
|
|
387
|
+
if (skillName === "agents md") priority += 420;
|
|
388
|
+
if (/\b(code documentation doc generate|documentation generation doc generate|api documentation|api documenter|reference builder|architecture)\b/.test(skillText)) priority += 320;
|
|
389
|
+
if (/\b(documentation|document|docs|doc|readme|wiki|writer|writing|coauthor|technical documentation)\b/.test(skillText)) priority += 130;
|
|
390
|
+
if (/\b(mcp|model context protocol|metasploit|penetration|exploit)\b/.test(skillText)) priority -= 220;
|
|
391
|
+
}
|
|
371
392
|
if (isMcpRelevantTask(normalizedPrompt, projectTokens)) {
|
|
372
393
|
if (skillName === "mcp builder") priority += 760;
|
|
373
394
|
if (skillName === "mcp management") priority += 740;
|
|
@@ -448,6 +469,11 @@ function isFrontendCheckoutTask(normalizedPrompt) {
|
|
|
448
469
|
return /\b(modal|display|show|checkout|library|frontend|webapp|page|button)\b/.test(normalizedPrompt);
|
|
449
470
|
}
|
|
450
471
|
|
|
472
|
+
function isDocumentAuthoringTask(normalizedPrompt) {
|
|
473
|
+
return /\b(create|write|edit|update|draft|generate|author|maintain|work on|produce)\b.*\b(document|documents|documentation|docs|doc|readme|wiki|workspace|workspaces|manual|guide|onboarding|spec|adr)\b/.test(normalizedPrompt)
|
|
474
|
+
|| /\b(document|documents|documentation|docs|doc|readme|wiki|workspace|workspaces|manual|guide|onboarding|spec|adr)\b.*\b(create|write|edit|update|draft|generate|author|maintain|work on|produce)\b/.test(normalizedPrompt);
|
|
475
|
+
}
|
|
476
|
+
|
|
451
477
|
function isMcpTask(normalizedPrompt) {
|
|
452
478
|
return /\b(mcp|model context protocol|tool server|tools server|server tool|bridge|proxy)\b/.test(normalizedPrompt);
|
|
453
479
|
}
|
|
@@ -489,6 +515,36 @@ function isPlatformCommerceTask(normalizedPrompt, skillText) {
|
|
|
489
515
|
return true;
|
|
490
516
|
}
|
|
491
517
|
|
|
518
|
+
function isDocumentProcessingSkill(skillText) {
|
|
519
|
+
return /\b(azure ai document|document intelligence|formrecognizer|document translation|cosmos db|azure cosmos|search documents|docusign)\b/.test(skillText);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function isDocumentProcessingTask(normalizedPrompt, skillText) {
|
|
523
|
+
if (/\bdocusign\b/.test(skillText)) return /\bdocusign|signature|envelope|sign\b/.test(normalizedPrompt);
|
|
524
|
+
if (/\bcosmos db|azure cosmos\b/.test(skillText)) return /\bcosmos|database|nosql|query|container\b/.test(normalizedPrompt);
|
|
525
|
+
if (/\bsearch documents\b/.test(skillText)) return /\bazure search|vector search|semantic search|index\b/.test(normalizedPrompt);
|
|
526
|
+
return /\bextract|ocr|analyze|translate|translation|form recognizer|document intelligence|azure\b/.test(normalizedPrompt);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function isWorkspaceAutomationSkill(skillText) {
|
|
530
|
+
return /\b(asana|bitbucket|slack|coda|google docs|google drive|google sheets|google slides|notion|telegram)\b/.test(skillText)
|
|
531
|
+
&& /\b(automation|automate|workspace|workspaces|manage docs|documents)\b/.test(skillText);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function isWorkspaceAutomationTask(normalizedPrompt, skillText) {
|
|
535
|
+
if (/\basana\b/.test(skillText)) return /\basana\b/.test(normalizedPrompt);
|
|
536
|
+
if (/\bbitbucket\b/.test(skillText)) return /\bbitbucket\b/.test(normalizedPrompt);
|
|
537
|
+
if (/\bslack\b/.test(skillText)) return /\bslack\b/.test(normalizedPrompt);
|
|
538
|
+
if (/\bcoda\b/.test(skillText)) return /\bcoda\b/.test(normalizedPrompt);
|
|
539
|
+
if (/\bgoogle docs\b/.test(skillText)) return /\bgoogle docs\b/.test(normalizedPrompt);
|
|
540
|
+
if (/\bgoogle drive\b/.test(skillText)) return /\bgoogle drive\b/.test(normalizedPrompt);
|
|
541
|
+
if (/\bgoogle sheets\b/.test(skillText)) return /\bgoogle sheets\b/.test(normalizedPrompt);
|
|
542
|
+
if (/\bgoogle slides\b/.test(skillText)) return /\bgoogle slides\b/.test(normalizedPrompt);
|
|
543
|
+
if (/\bnotion\b/.test(skillText)) return /\bnotion\b/.test(normalizedPrompt);
|
|
544
|
+
if (/\btelegram\b/.test(skillText)) return /\btelegram\b/.test(normalizedPrompt);
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
|
|
492
548
|
export function projectSkillHints({ cwd = process.cwd() } = {}) {
|
|
493
549
|
const hints = new Set();
|
|
494
550
|
const packagePaths = workspacePackagePaths(cwd);
|