omp-vcc 0.1.0
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/LICENSE +21 -0
- package/README.md +106 -0
- package/commands/omp-vcc.md +19 -0
- package/commands/vcc-recall.md +21 -0
- package/extensions/main.ts +319 -0
- package/extensions/vcc-core/commands/vcc-recall.ts +2 -0
- package/extensions/vcc-core/core/brief.ts +404 -0
- package/extensions/vcc-core/core/build-sections.ts +77 -0
- package/extensions/vcc-core/core/compact-args.ts +46 -0
- package/extensions/vcc-core/core/content.ts +157 -0
- package/extensions/vcc-core/core/drill-down.ts +299 -0
- package/extensions/vcc-core/core/filter-noise.ts +42 -0
- package/extensions/vcc-core/core/format-recall.ts +101 -0
- package/extensions/vcc-core/core/format.ts +82 -0
- package/extensions/vcc-core/core/lineage.ts +27 -0
- package/extensions/vcc-core/core/load-messages.ts +44 -0
- package/extensions/vcc-core/core/normalize.ts +66 -0
- package/extensions/vcc-core/core/rank.ts +284 -0
- package/extensions/vcc-core/core/recall-scope.ts +31 -0
- package/extensions/vcc-core/core/render-entries.ts +55 -0
- package/extensions/vcc-core/core/report.ts +233 -0
- package/extensions/vcc-core/core/sanitize.ts +6 -0
- package/extensions/vcc-core/core/search-entries.ts +576 -0
- package/extensions/vcc-core/core/settings.ts +151 -0
- package/extensions/vcc-core/core/skill-collapse.ts +36 -0
- package/extensions/vcc-core/core/summarize.ts +208 -0
- package/extensions/vcc-core/core/token-estimate.ts +101 -0
- package/extensions/vcc-core/core/tool-args.ts +17 -0
- package/extensions/vcc-core/details.ts +12 -0
- package/extensions/vcc-core/extract/commits.ts +70 -0
- package/extensions/vcc-core/extract/files.ts +88 -0
- package/extensions/vcc-core/extract/goals.ts +80 -0
- package/extensions/vcc-core/extract/preferences.ts +56 -0
- package/extensions/vcc-core/hook.ts +1017 -0
- package/extensions/vcc-core/sections.ts +9 -0
- package/extensions/vcc-core/types.ts +17 -0
- package/package.json +104 -0
- package/scripts/smoke.ts +116 -0
- package/scripts/uninstall-reset.js +73 -0
- package/skills/omp-vcc/SKILL.md +35 -0
- package/types.d.ts +114 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import type { NormalizedBlock } from "../types";
|
|
3
|
+
import { nonEmptyLines, clip } from "../core/content";
|
|
4
|
+
import { collapseSkillLines } from "../core/skill-collapse";
|
|
5
|
+
|
|
6
|
+
const SCOPE_CHANGE_RE =
|
|
7
|
+
/\b(instead|actually|change of plan|forget that|new task|switch to|now I want|pivot|let'?s do|stop .* and)\b/i;
|
|
8
|
+
|
|
9
|
+
const TASK_RE =
|
|
10
|
+
/\b(fix|implement|add|create|build|refactor|debug|investigate|update|remove|delete|migrate|deploy|test|write|set up)\b/i;
|
|
11
|
+
|
|
12
|
+
const NOISE_SHORT_RE = /^(ok|yes|no|sure|yeah|yep|go|hi|hey|thx|thanks|ok\b.*|y|n|k)\s*[.!?]*$/i;
|
|
13
|
+
|
|
14
|
+
// Reject lines that are clearly not user goals (pasted output, code, paths, tool dumps)
|
|
15
|
+
// or meta-prompt boilerplate (command templates like `/issues` that start with "For each issue:"
|
|
16
|
+
// followed by numbered "Read the issue in full..." steps).
|
|
17
|
+
const NON_GOAL_RE =
|
|
18
|
+
/^\s*[\[│├└─╭╰]|```|^\s*(=[A-Z]+\(|function |const |let |var |import |export |class )|^(https?:|file:|\/[A-Za-z])|\\n|^\s*For each\b|\bin full\b[^\n]*\b(comments|issue|issues|PRs?|linked)\b/;
|
|
19
|
+
|
|
20
|
+
// Signals that the rest of the user message is a command template (e.g. /issues),
|
|
21
|
+
// in which case we should stop collecting goals at the signal line.
|
|
22
|
+
const TEMPLATE_SIGNAL_RE =
|
|
23
|
+
/^\s*(For each\b|Do NOT implement\b|Analyze and propose\b|If Task\/context\b|Output:\s*$)/i;
|
|
24
|
+
|
|
25
|
+
const truncateAtTemplate = (lines: string[]): string[] => {
|
|
26
|
+
const idx = lines.findIndex((l) => TEMPLATE_SIGNAL_RE.test(l));
|
|
27
|
+
return idx >= 0 ? lines.slice(0, idx) : lines;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const stripLeadingBullet = (line: string): string =>
|
|
31
|
+
line.replace(/^\s*(?:[-*+]|\d+\.)\s+/, "").trim();
|
|
32
|
+
|
|
33
|
+
const MAX_GOAL_CHARS = 200;
|
|
34
|
+
|
|
35
|
+
const isSubstantiveGoal = (text: string): boolean => {
|
|
36
|
+
const t = text.trim();
|
|
37
|
+
if (t.length <= 5) return false;
|
|
38
|
+
if (t.length > MAX_GOAL_CHARS) return false;
|
|
39
|
+
if (NOISE_SHORT_RE.test(t)) return false;
|
|
40
|
+
if (NON_GOAL_RE.test(t)) return false;
|
|
41
|
+
return true;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Test scope-change / task intent only on the leading portion of a user block
|
|
45
|
+
// so that pasted outputs below the actual instruction do not trigger matches.
|
|
46
|
+
const LEADING_CHARS = 200;
|
|
47
|
+
|
|
48
|
+
export const extractGoals = (blocks: NormalizedBlock[]): string[] => {
|
|
49
|
+
const goals: string[] = [];
|
|
50
|
+
let latestScopeChange: string[] | null = null;
|
|
51
|
+
|
|
52
|
+
for (const b of blocks) {
|
|
53
|
+
if (b.kind !== "user") continue;
|
|
54
|
+
const rawLines = nonEmptyLines(b.text);
|
|
55
|
+
const truncated = truncateAtTemplate(rawLines);
|
|
56
|
+
const lines = collapseSkillLines(truncated.filter(isSubstantiveGoal))
|
|
57
|
+
.map(stripLeadingBullet)
|
|
58
|
+
.filter((l) => l.length > 5);
|
|
59
|
+
if (lines.length === 0) continue;
|
|
60
|
+
|
|
61
|
+
if (goals.length === 0) {
|
|
62
|
+
goals.push(...lines.slice(0, 6));
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const leading = b.text.slice(0, LEADING_CHARS);
|
|
67
|
+
if (SCOPE_CHANGE_RE.test(leading)) {
|
|
68
|
+
latestScopeChange = lines.slice(0, 3).map((l) => clip(l, MAX_GOAL_CHARS));
|
|
69
|
+
} else if (TASK_RE.test(leading) && lines[0].length > 15) {
|
|
70
|
+
latestScopeChange = lines.slice(0, 2).map((l) => clip(l, MAX_GOAL_CHARS));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Only emit the [Scope change] marker when we actually captured bullets.
|
|
75
|
+
if (latestScopeChange && latestScopeChange.length > 0) {
|
|
76
|
+
goals.push("[Scope change]", ...latestScopeChange);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return goals.slice(0, 8);
|
|
80
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import type { NormalizedBlock } from "../types";
|
|
3
|
+
import { clip, nonEmptyLines } from "../core/content";
|
|
4
|
+
|
|
5
|
+
// Tightened patterns: require a clear preference construction, not bare keywords.
|
|
6
|
+
const PREF_PATTERNS = [
|
|
7
|
+
/\bprefer(?:s|red|ring)?\s+\w/i,
|
|
8
|
+
/\bdon'?t want\b/i,
|
|
9
|
+
/\balways (?:use|do|run|prefer|keep|make|format|write|add|set|put|prefix|start|include|append)\b/i,
|
|
10
|
+
/\bnever (?:use|do|run|push|commit|write|ignore|add|set|put|remove|delete|include|deploy)\b/i,
|
|
11
|
+
/\bplease (?:use|avoid|keep|make|don'?t|do not|format|write)\b/i,
|
|
12
|
+
/\b(?:style|format|language|naming)\s*[:=]\s*\S/i,
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export const extractPreferences = (blocks: NormalizedBlock[]): string[] => {
|
|
16
|
+
const prefs: string[] = [];
|
|
17
|
+
const seen = new Set<string>();
|
|
18
|
+
|
|
19
|
+
for (const b of blocks) {
|
|
20
|
+
if (b.kind !== "user") continue;
|
|
21
|
+
|
|
22
|
+
let perBlock = 0;
|
|
23
|
+
for (const line of nonEmptyLines(b.text)) {
|
|
24
|
+
const trimmed = line.trim();
|
|
25
|
+
if (!trimmed || trimmed.length < 5) continue;
|
|
26
|
+
if (trimmed.length > 200) continue;
|
|
27
|
+
// Reject questions.
|
|
28
|
+
if (trimmed.endsWith("?") || trimmed.includes("?...")) continue;
|
|
29
|
+
if (!PREF_PATTERNS.some((p) => p.test(trimmed))) continue;
|
|
30
|
+
|
|
31
|
+
const clipped = clip(trimmed, 200);
|
|
32
|
+
const key = clipped.toLowerCase();
|
|
33
|
+
if (seen.has(key)) continue;
|
|
34
|
+
seen.add(key);
|
|
35
|
+
prefs.push(clipped);
|
|
36
|
+
|
|
37
|
+
// Cap per user block to avoid pasting long rule lists as many prefs.
|
|
38
|
+
if (++perBlock >= 1) break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return prefs.slice(0, 10);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Remove preferences that duplicate goals (case-insensitive, trimmed).
|
|
47
|
+
* Called by `buildSections` so that the two sections do not overlap.
|
|
48
|
+
*/
|
|
49
|
+
export const dedupPreferencesAgainstGoals = (
|
|
50
|
+
prefs: string[],
|
|
51
|
+
goals: string[],
|
|
52
|
+
): string[] => {
|
|
53
|
+
const norm = (s: string) => s.trim().toLowerCase();
|
|
54
|
+
const goalSet = new Set(goals.map(norm));
|
|
55
|
+
return prefs.filter((p) => !goalSet.has(norm(p)));
|
|
56
|
+
};
|