@kubbisec/ai-linux-arm64 0.1.3 → 0.1.5
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/bin/kubbisec +0 -0
- package/bundled/assets/terminal/banner-compact.ansi +7 -0
- package/bundled/assets/terminal/banner-wide.ansi +10 -0
- package/bundled/assets/terminal/logotipo-compact-fallback.ansi +7 -0
- package/bundled/assets/terminal/logotipo-compact.ansi +1 -0
- package/bundled/assets/terminal/logotipo-compact.png +0 -0
- package/bundled/assets/terminal/logotipo-wide-fallback.ansi +10 -0
- package/bundled/assets/terminal/logotipo-wide.ansi +1 -0
- package/bundled/assets/terminal/logotipo-wide.png +0 -0
- package/bundled/assets/terminal/mark.ansi +7 -0
- package/bundled/clarify/clarify-gate.d.ts +27 -0
- package/bundled/clarify/clarify-gate.d.ts.map +1 -0
- package/bundled/clarify/clarify-gate.js +152 -0
- package/bundled/clarify/clarify-gate.js.map +1 -0
- package/bundled/clarify/clarify-ui-state.d.ts +12 -0
- package/bundled/clarify/clarify-ui-state.d.ts.map +1 -0
- package/bundled/clarify/clarify-ui-state.js +27 -0
- package/bundled/clarify/clarify-ui-state.js.map +1 -0
- package/bundled/clarify/parse-clarify-answer.d.ts +16 -0
- package/bundled/clarify/parse-clarify-answer.d.ts.map +1 -0
- package/bundled/clarify/parse-clarify-answer.js +22 -0
- package/bundled/clarify/parse-clarify-answer.js.map +1 -0
- package/bundled/clarify/question-format.d.ts +36 -0
- package/bundled/clarify/question-format.d.ts.map +1 -0
- package/bundled/clarify/question-format.js +150 -0
- package/bundled/clarify/question-format.js.map +1 -0
- package/bundled/clarify/questionnaire-tool.d.ts +25 -0
- package/bundled/clarify/questionnaire-tool.d.ts.map +1 -0
- package/bundled/clarify/questionnaire-tool.js +157 -0
- package/bundled/clarify/questionnaire-tool.js.map +1 -0
- package/bundled/clarify/session-questionnaire.d.ts +23 -0
- package/bundled/clarify/session-questionnaire.d.ts.map +1 -0
- package/bundled/clarify/session-questionnaire.js +319 -0
- package/bundled/clarify/session-questionnaire.js.map +1 -0
- package/bundled/clarify/session-questionnaire.types.d.ts +45 -0
- package/bundled/clarify/session-questionnaire.types.d.ts.map +1 -0
- package/bundled/clarify/session-questionnaire.types.js +13 -0
- package/bundled/clarify/session-questionnaire.types.js.map +1 -0
- package/bundled/config/config.d.ts +14 -0
- package/bundled/config/config.d.ts.map +1 -0
- package/bundled/config/config.js +58 -0
- package/bundled/config/config.js.map +1 -0
- package/bundled/config/ensure-kubbisec-project-settings.d.ts +20 -0
- package/bundled/config/ensure-kubbisec-project-settings.d.ts.map +1 -0
- package/bundled/config/ensure-kubbisec-project-settings.js +65 -0
- package/bundled/config/ensure-kubbisec-project-settings.js.map +1 -0
- package/bundled/config/feature-flags.d.ts +2 -0
- package/bundled/config/feature-flags.d.ts.map +1 -0
- package/bundled/config/feature-flags.js +2 -0
- package/bundled/config/feature-flags.js.map +1 -0
- package/bundled/config/format-kubbisec-footer-status.d.ts +2 -0
- package/bundled/config/format-kubbisec-footer-status.d.ts.map +1 -0
- package/bundled/config/format-kubbisec-footer-status.js +21 -0
- package/bundled/config/format-kubbisec-footer-status.js.map +1 -0
- package/bundled/config/resolve-agents-context-file.d.ts +4 -0
- package/bundled/config/resolve-agents-context-file.d.ts.map +1 -0
- package/bundled/config/resolve-agents-context-file.js +48 -0
- package/bundled/config/resolve-agents-context-file.js.map +1 -0
- package/bundled/config/resource-budget.d.ts +17 -0
- package/bundled/config/resource-budget.d.ts.map +1 -0
- package/bundled/config/resource-budget.js +35 -0
- package/bundled/config/resource-budget.js.map +1 -0
- package/bundled/copy/kubbisec-shell-copy.d.ts +8 -0
- package/bundled/copy/kubbisec-shell-copy.d.ts.map +1 -0
- package/bundled/copy/kubbisec-shell-copy.js +8 -0
- package/bundled/copy/kubbisec-shell-copy.js.map +1 -0
- package/bundled/edit-format.md +17 -0
- package/bundled/extensions/cli-local-shared.d.ts +26 -0
- package/bundled/extensions/cli-local-shared.d.ts.map +1 -0
- package/bundled/extensions/cli-local-shared.js +97 -0
- package/bundled/extensions/cli-local-shared.js.map +1 -0
- package/bundled/extensions/kubbisec-aspm-local.extension.d.ts +17 -0
- package/bundled/extensions/kubbisec-aspm-local.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-aspm-local.extension.js +134 -0
- package/bundled/extensions/kubbisec-aspm-local.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-brand.extension.d.ts +20 -0
- package/bundled/extensions/kubbisec-brand.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-brand.extension.js +84 -0
- package/bundled/extensions/kubbisec-brand.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-byok-provider.extension.d.ts +30 -0
- package/bundled/extensions/kubbisec-byok-provider.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-byok-provider.extension.js +44 -0
- package/bundled/extensions/kubbisec-byok-provider.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-clarify.extension.d.ts +45 -0
- package/bundled/extensions/kubbisec-clarify.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-clarify.extension.js +305 -0
- package/bundled/extensions/kubbisec-clarify.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-footer.extension.d.ts +64 -0
- package/bundled/extensions/kubbisec-footer.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-footer.extension.js +187 -0
- package/bundled/extensions/kubbisec-footer.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-github-local.extension.d.ts +23 -0
- package/bundled/extensions/kubbisec-github-local.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-github-local.extension.js +105 -0
- package/bundled/extensions/kubbisec-github-local.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-memory.extension.d.ts +12 -0
- package/bundled/extensions/kubbisec-memory.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-memory.extension.js +107 -0
- package/bundled/extensions/kubbisec-memory.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-naus-local.extension.d.ts +17 -0
- package/bundled/extensions/kubbisec-naus-local.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-naus-local.extension.js +125 -0
- package/bundled/extensions/kubbisec-naus-local.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-platform-tools.extension.d.ts +27 -0
- package/bundled/extensions/kubbisec-platform-tools.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-platform-tools.extension.js +144 -0
- package/bundled/extensions/kubbisec-platform-tools.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-runtime-status.extension.d.ts +13 -0
- package/bundled/extensions/kubbisec-runtime-status.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-runtime-status.extension.js +18 -0
- package/bundled/extensions/kubbisec-runtime-status.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-scope.extension.d.ts +14 -0
- package/bundled/extensions/kubbisec-scope.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-scope.extension.js +14 -0
- package/bundled/extensions/kubbisec-scope.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-skill-mentions.extension.d.ts +24 -0
- package/bundled/extensions/kubbisec-skill-mentions.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-skill-mentions.extension.js +54 -0
- package/bundled/extensions/kubbisec-skill-mentions.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-skill-telemetry.extension.d.ts +6 -0
- package/bundled/extensions/kubbisec-skill-telemetry.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-skill-telemetry.extension.js +85 -0
- package/bundled/extensions/kubbisec-skill-telemetry.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-ui.extension.d.ts +6 -0
- package/bundled/extensions/kubbisec-ui.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-ui.extension.js +116 -0
- package/bundled/extensions/kubbisec-ui.extension.js.map +1 -0
- package/bundled/extensions/kubbisec-workflow.extension.d.ts +38 -0
- package/bundled/extensions/kubbisec-workflow.extension.d.ts.map +1 -0
- package/bundled/extensions/kubbisec-workflow.extension.js +169 -0
- package/bundled/extensions/kubbisec-workflow.extension.js.map +1 -0
- package/bundled/gate-system.md +27 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/client.d.ts +20 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/client.d.ts.map +1 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/client.js +121 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/client.js.map +1 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/feature-flags.d.ts +15 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/feature-flags.d.ts.map +1 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/feature-flags.js +34 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/feature-flags.js.map +1 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/index.d.ts +12 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/index.d.ts.map +1 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/index.js +35 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/index.js.map +1 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/sanitizer.d.ts +4 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/sanitizer.d.ts.map +1 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/sanitizer.js +89 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/sanitizer.js.map +1 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/storage-paths.d.ts +2 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/storage-paths.d.ts.map +1 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/storage-paths.js +13 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/storage-paths.js.map +1 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/types.d.ts +24 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/types.d.ts.map +1 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/types.js +9 -0
- package/bundled/node_modules/@kubbisec/chat-memory/dist/types.js.map +1 -0
- package/bundled/node_modules/@kubbisec/chat-memory/package.json +32 -0
- package/bundled/node_modules/@kubbisec/home/dist/index.d.ts +3 -0
- package/bundled/node_modules/@kubbisec/home/dist/index.d.ts.map +1 -0
- package/bundled/node_modules/@kubbisec/home/dist/index.js +3 -0
- package/bundled/node_modules/@kubbisec/home/dist/index.js.map +1 -0
- package/bundled/node_modules/@kubbisec/home/dist/migrate.d.ts +10 -0
- package/bundled/node_modules/@kubbisec/home/dist/migrate.d.ts.map +1 -0
- package/bundled/node_modules/@kubbisec/home/dist/migrate.js +107 -0
- package/bundled/node_modules/@kubbisec/home/dist/migrate.js.map +1 -0
- package/bundled/node_modules/@kubbisec/home/dist/paths.d.ts +22 -0
- package/bundled/node_modules/@kubbisec/home/dist/paths.d.ts.map +1 -0
- package/bundled/node_modules/@kubbisec/home/dist/paths.js +69 -0
- package/bundled/node_modules/@kubbisec/home/dist/paths.js.map +1 -0
- package/bundled/node_modules/@kubbisec/home/package.json +26 -0
- package/bundled/reflect-system.md +31 -0
- package/bundled/resolve-bundled-dist-root.js +165 -0
- package/bundled/resolve-bundled-dist-root.js.map +1 -0
- package/bundled/skills/aspm-platform/SKILL.md +58 -0
- package/bundled/skills/chat-mention-render.d.ts +7 -0
- package/bundled/skills/chat-mention-render.d.ts.map +1 -0
- package/bundled/skills/chat-mention-render.js +122 -0
- package/bundled/skills/chat-mention-render.js.map +1 -0
- package/bundled/skills/chat-mention-render.test.ts +47 -0
- package/bundled/skills/chat-mention-render.ts +141 -0
- package/bundled/skills/chat-mentions.d.ts +27 -0
- package/bundled/skills/chat-mentions.d.ts.map +1 -0
- package/bundled/skills/chat-mentions.js +104 -0
- package/bundled/skills/chat-mentions.js.map +1 -0
- package/bundled/skills/chat-mentions.test.ts +32 -0
- package/bundled/skills/chat-mentions.ts +126 -0
- package/bundled/skills/github-local/SKILL.md +16 -0
- package/bundled/skills/list-bundled-skills.d.ts +7 -0
- package/bundled/skills/list-bundled-skills.d.ts.map +1 -0
- package/bundled/skills/list-bundled-skills.js +44 -0
- package/bundled/skills/list-bundled-skills.js.map +1 -0
- package/bundled/skills/list-bundled-skills.ts +46 -0
- package/bundled/skills/naus-pipelines/SKILL.md +31 -0
- package/bundled/skills/remediation/SKILL.md +12 -0
- package/bundled/skills/scanner-gitleaks/SKILL.md +10 -0
- package/bundled/skills/scanner-nmap/SKILL.md +10 -0
- package/bundled/skills/scanner-osv/SKILL.md +10 -0
- package/bundled/skills/scanner-semgrep/SKILL.md +10 -0
- package/bundled/skills/scanner-skipfish/SKILL.md +10 -0
- package/bundled/skills/scanner-sonar/SKILL.md +10 -0
- package/bundled/skills/scanner-syft/SKILL.md +10 -0
- package/bundled/skills/scanner-trivy/SKILL.md +10 -0
- package/bundled/skills/sec-brainstorm/SKILL.md +74 -0
- package/bundled/skills/sec-clarify/SKILL.md +68 -0
- package/bundled/skills/sec-debug/SKILL.md +94 -0
- package/bundled/skills/sec-plan/SKILL.md +101 -0
- package/bundled/skills/sec-review/SKILL.md +110 -0
- package/bundled/skills/sec-review/code-reviewer-sec.md +176 -0
- package/bundled/skills/sec-using-skills/SKILL.md +79 -0
- package/bundled/skills/sec-verify/SKILL.md +77 -0
- package/bundled/skills/skill-mention.d.ts +3 -0
- package/bundled/skills/skill-mention.d.ts.map +1 -0
- package/bundled/skills/skill-mention.js +3 -0
- package/bundled/skills/skill-mention.js.map +1 -0
- package/bundled/skills/skill-mention.test.ts +46 -0
- package/bundled/skills/skill-mention.ts +10 -0
- package/bundled/theme/kubbisec.json +93 -0
- package/package.json +3 -2
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { visibleWidth } from "@earendil-works/pi-tui";
|
|
2
|
+
|
|
3
|
+
export type MentionChipTheme = {
|
|
4
|
+
fg: (role: string, text: string) => string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
type MentionSpan =
|
|
8
|
+
| { kind: "text"; value: string }
|
|
9
|
+
| { kind: "skill"; name: string }
|
|
10
|
+
| { kind: "plan" };
|
|
11
|
+
|
|
12
|
+
const SKILL_TOKEN_RE = /\/skill:([a-z0-9_-]+)/gi;
|
|
13
|
+
const PLAN_TOKEN_RE = /\/mode:plan\b/gi;
|
|
14
|
+
|
|
15
|
+
function parseMentionSpans(line: string): MentionSpan[] {
|
|
16
|
+
const spans: MentionSpan[] = [];
|
|
17
|
+
let cursor = 0;
|
|
18
|
+
|
|
19
|
+
while (cursor < line.length) {
|
|
20
|
+
SKILL_TOKEN_RE.lastIndex = cursor;
|
|
21
|
+
PLAN_TOKEN_RE.lastIndex = cursor;
|
|
22
|
+
const skillMatch = SKILL_TOKEN_RE.exec(line);
|
|
23
|
+
const planMatch = PLAN_TOKEN_RE.exec(line);
|
|
24
|
+
|
|
25
|
+
let nextMatch: { index: number; length: number; span: MentionSpan } | null = null;
|
|
26
|
+
if (skillMatch?.index !== undefined) {
|
|
27
|
+
nextMatch = {
|
|
28
|
+
index: skillMatch.index,
|
|
29
|
+
length: skillMatch[0].length,
|
|
30
|
+
span: { kind: "skill", name: skillMatch[1] ?? "" },
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (planMatch?.index !== undefined) {
|
|
34
|
+
const candidate = {
|
|
35
|
+
index: planMatch.index,
|
|
36
|
+
length: planMatch[0].length,
|
|
37
|
+
span: { kind: "plan" as const },
|
|
38
|
+
};
|
|
39
|
+
if (!nextMatch || candidate.index < nextMatch.index) {
|
|
40
|
+
nextMatch = candidate;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!nextMatch) {
|
|
45
|
+
spans.push({ kind: "text", value: line.slice(cursor) });
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (nextMatch.index > cursor) {
|
|
50
|
+
spans.push({ kind: "text", value: line.slice(cursor, nextMatch.index) });
|
|
51
|
+
}
|
|
52
|
+
spans.push(nextMatch.span);
|
|
53
|
+
cursor = nextMatch.index + nextMatch.length;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (spans.length === 0) {
|
|
57
|
+
spans.push({ kind: "text", value: line });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return spans;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function renderSpan(span: MentionSpan, theme: MentionChipTheme): string {
|
|
64
|
+
if (span.kind === "text") return span.value;
|
|
65
|
+
if (span.kind === "skill") {
|
|
66
|
+
try {
|
|
67
|
+
return theme.fg("accent", span.name);
|
|
68
|
+
} catch {
|
|
69
|
+
return theme.fg("text", span.name);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
return theme.fg("planAccent", "plan");
|
|
74
|
+
} catch {
|
|
75
|
+
return theme.fg("text", "plan");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function spanLogicalWidth(span: MentionSpan): number {
|
|
80
|
+
if (span.kind === "text") return span.value.length;
|
|
81
|
+
if (span.kind === "skill") return `/skill:${span.name}`.length;
|
|
82
|
+
return "/mode:plan".length;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function spanVisibleText(span: MentionSpan): string {
|
|
86
|
+
if (span.kind === "text") return span.value;
|
|
87
|
+
if (span.kind === "skill") return span.name;
|
|
88
|
+
return "plan";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function renderLineWithMentionChips(line: string, theme: MentionChipTheme): string {
|
|
92
|
+
return parseMentionSpans(line)
|
|
93
|
+
.map((span) => renderSpan(span, theme))
|
|
94
|
+
.join("");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function logicalToVisibleCol(line: string, logicalCol: number): number {
|
|
98
|
+
const clamped = Math.max(0, Math.min(logicalCol, line.length));
|
|
99
|
+
let logical = 0;
|
|
100
|
+
let visible = 0;
|
|
101
|
+
|
|
102
|
+
for (const span of parseMentionSpans(line)) {
|
|
103
|
+
const logicalLen = spanLogicalWidth(span);
|
|
104
|
+
const visibleLen = visibleWidth(spanVisibleText(span));
|
|
105
|
+
if (logical + logicalLen >= clamped) {
|
|
106
|
+
const offset = clamped - logical;
|
|
107
|
+
if (span.kind === "text") {
|
|
108
|
+
return visible + offset;
|
|
109
|
+
}
|
|
110
|
+
const ratio = logicalLen > 0 ? offset / logicalLen : 0;
|
|
111
|
+
return visible + Math.round(visibleLen * ratio);
|
|
112
|
+
}
|
|
113
|
+
logical += logicalLen;
|
|
114
|
+
visible += visibleLen;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return visible;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function visibleToLogicalCol(line: string, visibleCol: number): number {
|
|
121
|
+
const clamped = Math.max(0, visibleCol);
|
|
122
|
+
let logical = 0;
|
|
123
|
+
let visible = 0;
|
|
124
|
+
|
|
125
|
+
for (const span of parseMentionSpans(line)) {
|
|
126
|
+
const logicalLen = spanLogicalWidth(span);
|
|
127
|
+
const visibleLen = visibleWidth(spanVisibleText(span));
|
|
128
|
+
if (visible + visibleLen >= clamped) {
|
|
129
|
+
const offset = clamped - visible;
|
|
130
|
+
if (span.kind === "text") {
|
|
131
|
+
return logical + offset;
|
|
132
|
+
}
|
|
133
|
+
const ratio = visibleLen > 0 ? offset / visibleLen : 0;
|
|
134
|
+
return logical + Math.round(logicalLen * ratio);
|
|
135
|
+
}
|
|
136
|
+
logical += logicalLen;
|
|
137
|
+
visible += visibleLen;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return line.length;
|
|
141
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AutocompleteItem } from "@earendil-works/pi-tui";
|
|
2
|
+
import type { KubbisecSkillEntry } from "./list-bundled-skills.js";
|
|
3
|
+
export declare const SKILL_MENTION_TOKEN = "@skill";
|
|
4
|
+
export declare const PLAN_MENTION_ALIASES: readonly ["@plan", "@planejar"];
|
|
5
|
+
/** Same token rules as Pi CombinedAutocompleteProvider.extractAtPrefix. */
|
|
6
|
+
export declare function extractAtPrefix(textBeforeCursor: string): string | null;
|
|
7
|
+
/** KubbiSec: `@skill` may include a space and partial name (not only the last @ token). */
|
|
8
|
+
export declare function extractSkillMentionPrefix(textBeforeCursor: string): string | null;
|
|
9
|
+
export declare function parseSkillMentionPrefix(atPrefix: string | null): {
|
|
10
|
+
query: string;
|
|
11
|
+
} | null;
|
|
12
|
+
export declare function parsePlanMentionPrefix(atPrefix: string | null): {
|
|
13
|
+
query: string;
|
|
14
|
+
} | null;
|
|
15
|
+
export declare function filterSkillSuggestions(skills: KubbisecSkillEntry[], query: string): AutocompleteItem[];
|
|
16
|
+
/** Pi expands `/skill:name` — map `@skill name` before submit. */
|
|
17
|
+
export declare function transformAtSkillMentions(text: string): string;
|
|
18
|
+
/** Map `@plan` / `@planejar` to `/mode:plan` before submit. */
|
|
19
|
+
export declare function transformAtPlanMentions(text: string): string;
|
|
20
|
+
/** Apply skill transform first, then plan (CHAT-004). */
|
|
21
|
+
export declare function transformChatMentions(text: string): string;
|
|
22
|
+
export declare function applySkillMentionCompletion(lines: string[], cursorLine: number, cursorCol: number, item: AutocompleteItem, prefix: string): {
|
|
23
|
+
lines: string[];
|
|
24
|
+
cursorLine: number;
|
|
25
|
+
cursorCol: number;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=chat-mentions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-mentions.d.ts","sourceRoot":"","sources":["../../src/skills/chat-mentions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,eAAO,MAAM,mBAAmB,WAAW,CAAC;AAE5C,eAAO,MAAM,oBAAoB,iCAAkC,CAAC;AAiBpE,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOvE;AAED,2FAA2F;AAC3F,wBAAgB,yBAAyB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjF;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKzF;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CASxF;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,kBAAkB,EAAE,EAC5B,KAAK,EAAE,MAAM,GACZ,gBAAgB,EAAE,CAcpB;AAED,kEAAkE;AAClE,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,+DAA+D;AAC/D,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAS5D;AAED,yDAAyD;AACzD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,MAAM,EAAE,EACf,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,gBAAgB,EACtB,MAAM,EAAE,MAAM,GACb;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAe5D"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { fuzzyFilter } from "@earendil-works/pi-tui";
|
|
2
|
+
export const SKILL_MENTION_TOKEN = "@skill";
|
|
3
|
+
export const PLAN_MENTION_ALIASES = ["@plan", "@planejar"];
|
|
4
|
+
const PLAN_MENTION_TOKENS_LONGEST_FIRST = [...PLAN_MENTION_ALIASES].sort((a, b) => b.length - a.length);
|
|
5
|
+
const PATH_DELIMITERS = new Set([" ", "\t", '"', "'", "="]);
|
|
6
|
+
function findLastDelimiter(text) {
|
|
7
|
+
for (let i = text.length - 1; i >= 0; i -= 1) {
|
|
8
|
+
if (PATH_DELIMITERS.has(text[i] ?? "")) {
|
|
9
|
+
return i;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return -1;
|
|
13
|
+
}
|
|
14
|
+
/** Same token rules as Pi CombinedAutocompleteProvider.extractAtPrefix. */
|
|
15
|
+
export function extractAtPrefix(textBeforeCursor) {
|
|
16
|
+
const lastDelimiterIndex = findLastDelimiter(textBeforeCursor);
|
|
17
|
+
const tokenStart = lastDelimiterIndex === -1 ? 0 : lastDelimiterIndex + 1;
|
|
18
|
+
if (textBeforeCursor[tokenStart] === "@") {
|
|
19
|
+
return textBeforeCursor.slice(tokenStart);
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
/** KubbiSec: `@skill` may include a space and partial name (not only the last @ token). */
|
|
24
|
+
export function extractSkillMentionPrefix(textBeforeCursor) {
|
|
25
|
+
const idx = textBeforeCursor.lastIndexOf(SKILL_MENTION_TOKEN);
|
|
26
|
+
if (idx === -1)
|
|
27
|
+
return null;
|
|
28
|
+
if (idx > 0 && !PATH_DELIMITERS.has(textBeforeCursor[idx - 1] ?? "")) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const slice = textBeforeCursor.slice(idx);
|
|
32
|
+
if (!parseSkillMentionPrefix(slice))
|
|
33
|
+
return null;
|
|
34
|
+
return slice;
|
|
35
|
+
}
|
|
36
|
+
export function parseSkillMentionPrefix(atPrefix) {
|
|
37
|
+
if (!atPrefix?.startsWith(SKILL_MENTION_TOKEN))
|
|
38
|
+
return null;
|
|
39
|
+
const tail = atPrefix.slice(SKILL_MENTION_TOKEN.length);
|
|
40
|
+
if (tail.length > 0 && !tail.startsWith(" "))
|
|
41
|
+
return null;
|
|
42
|
+
return { query: tail.startsWith(" ") ? tail.trimStart() : "" };
|
|
43
|
+
}
|
|
44
|
+
export function parsePlanMentionPrefix(atPrefix) {
|
|
45
|
+
if (!atPrefix)
|
|
46
|
+
return null;
|
|
47
|
+
for (const token of PLAN_MENTION_TOKENS_LONGEST_FIRST) {
|
|
48
|
+
if (!atPrefix.startsWith(token))
|
|
49
|
+
continue;
|
|
50
|
+
const tail = atPrefix.slice(token.length);
|
|
51
|
+
if (tail.length > 0 && !tail.startsWith(" "))
|
|
52
|
+
continue;
|
|
53
|
+
return { query: tail.startsWith(" ") ? tail.trimStart() : "" };
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
export function filterSkillSuggestions(skills, query) {
|
|
58
|
+
const items = skills.map((skill) => ({
|
|
59
|
+
value: skill.name,
|
|
60
|
+
label: skill.name,
|
|
61
|
+
description: skill.description,
|
|
62
|
+
}));
|
|
63
|
+
if (!query)
|
|
64
|
+
return items;
|
|
65
|
+
return fuzzyFilter(items, query, (item) => `${item.label} ${item.description ?? ""}`).map((item) => ({
|
|
66
|
+
value: item.value,
|
|
67
|
+
label: item.label,
|
|
68
|
+
description: item.description,
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
/** Pi expands `/skill:name` — map `@skill name` before submit. */
|
|
72
|
+
export function transformAtSkillMentions(text) {
|
|
73
|
+
return text.replace(/@skill\s+([^\s@/]+)/g, "/skill:$1");
|
|
74
|
+
}
|
|
75
|
+
/** Map `@plan` / `@planejar` to `/mode:plan` before submit. */
|
|
76
|
+
export function transformAtPlanMentions(text) {
|
|
77
|
+
const tokenPattern = PLAN_MENTION_TOKENS_LONGEST_FIRST.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
78
|
+
const pattern = new RegExp(`(^|[\\s"'=])(${tokenPattern})(\\s[\\s\\S]*)?`, "g");
|
|
79
|
+
return text.replace(pattern, (_match, delim, _token, tail) => {
|
|
80
|
+
const query = tail ? tail.trimStart() : "";
|
|
81
|
+
return `${delim}/mode:plan${query ? ` ${query}` : ""}`;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/** Apply skill transform first, then plan (CHAT-004). */
|
|
85
|
+
export function transformChatMentions(text) {
|
|
86
|
+
return transformAtPlanMentions(transformAtSkillMentions(text));
|
|
87
|
+
}
|
|
88
|
+
export function applySkillMentionCompletion(lines, cursorLine, cursorCol, item, prefix) {
|
|
89
|
+
const currentLine = lines[cursorLine] ?? "";
|
|
90
|
+
const beforePrefix = currentLine.slice(0, cursorCol - prefix.length);
|
|
91
|
+
const afterCursor = currentLine.slice(cursorCol);
|
|
92
|
+
const atIndex = beforePrefix.lastIndexOf(SKILL_MENTION_TOKEN);
|
|
93
|
+
const head = atIndex >= 0 ? beforePrefix.slice(0, atIndex) : beforePrefix;
|
|
94
|
+
const insertion = `${SKILL_MENTION_TOKEN} ${item.value} `;
|
|
95
|
+
const newLine = `${head}${insertion}${afterCursor}`;
|
|
96
|
+
const newLines = [...lines];
|
|
97
|
+
newLines[cursorLine] = newLine;
|
|
98
|
+
return {
|
|
99
|
+
lines: newLines,
|
|
100
|
+
cursorLine,
|
|
101
|
+
cursorCol: head.length + insertion.length,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=chat-mentions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-mentions.js","sourceRoot":"","sources":["../../src/skills/chat-mentions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
parsePlanMentionPrefix,
|
|
4
|
+
PLAN_MENTION_ALIASES,
|
|
5
|
+
transformAtPlanMentions,
|
|
6
|
+
transformChatMentions,
|
|
7
|
+
} from "./chat-mentions.js";
|
|
8
|
+
|
|
9
|
+
describe("chat-mentions", () => {
|
|
10
|
+
it("exports plan mention aliases", () => {
|
|
11
|
+
expect(PLAN_MENTION_ALIASES).toEqual(["@plan", "@planejar"]);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("parses @plan and @planejar prefixes", () => {
|
|
15
|
+
expect(parsePlanMentionPrefix("@plan")).toEqual({ query: "" });
|
|
16
|
+
expect(parsePlanMentionPrefix("@plan fix HIGH")).toEqual({ query: "fix HIGH" });
|
|
17
|
+
expect(parsePlanMentionPrefix("@planejar scope")).toEqual({ query: "scope" });
|
|
18
|
+
expect(parsePlanMentionPrefix("@planful")).toBeNull();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("transforms @plan to /mode:plan", () => {
|
|
22
|
+
expect(transformAtPlanMentions("@plan fix HIGH SCA")).toBe("/mode:plan fix HIGH SCA");
|
|
23
|
+
expect(transformAtPlanMentions("@planejar foo")).toBe("/mode:plan foo");
|
|
24
|
+
expect(transformAtPlanMentions("@plan")).toBe("/mode:plan");
|
|
25
|
+
expect(transformAtPlanMentions("x@plan fix")).toBe("x@plan fix");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("transforms combined skill and plan mentions (skill first)", () => {
|
|
29
|
+
expect(transformChatMentions("@skill naus @plan fix")).toBe("/skill:naus /mode:plan fix");
|
|
30
|
+
expect(transformChatMentions("@planejar x")).toBe("/mode:plan x");
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { AutocompleteItem } from "@earendil-works/pi-tui";
|
|
2
|
+
import { fuzzyFilter } from "@earendil-works/pi-tui";
|
|
3
|
+
import type { KubbisecSkillEntry } from "./list-bundled-skills.js";
|
|
4
|
+
|
|
5
|
+
export const SKILL_MENTION_TOKEN = "@skill";
|
|
6
|
+
|
|
7
|
+
export const PLAN_MENTION_ALIASES = ["@plan", "@planejar"] as const;
|
|
8
|
+
|
|
9
|
+
const PLAN_MENTION_TOKENS_LONGEST_FIRST = [...PLAN_MENTION_ALIASES].sort(
|
|
10
|
+
(a, b) => b.length - a.length,
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
const PATH_DELIMITERS = new Set([" ", "\t", '"', "'", "="]);
|
|
14
|
+
|
|
15
|
+
function findLastDelimiter(text: string): number {
|
|
16
|
+
for (let i = text.length - 1; i >= 0; i -= 1) {
|
|
17
|
+
if (PATH_DELIMITERS.has(text[i] ?? "")) {
|
|
18
|
+
return i;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return -1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Same token rules as Pi CombinedAutocompleteProvider.extractAtPrefix. */
|
|
25
|
+
export function extractAtPrefix(textBeforeCursor: string): string | null {
|
|
26
|
+
const lastDelimiterIndex = findLastDelimiter(textBeforeCursor);
|
|
27
|
+
const tokenStart = lastDelimiterIndex === -1 ? 0 : lastDelimiterIndex + 1;
|
|
28
|
+
if (textBeforeCursor[tokenStart] === "@") {
|
|
29
|
+
return textBeforeCursor.slice(tokenStart);
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** KubbiSec: `@skill` may include a space and partial name (not only the last @ token). */
|
|
35
|
+
export function extractSkillMentionPrefix(textBeforeCursor: string): string | null {
|
|
36
|
+
const idx = textBeforeCursor.lastIndexOf(SKILL_MENTION_TOKEN);
|
|
37
|
+
if (idx === -1) return null;
|
|
38
|
+
if (idx > 0 && !PATH_DELIMITERS.has(textBeforeCursor[idx - 1] ?? "")) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const slice = textBeforeCursor.slice(idx);
|
|
42
|
+
if (!parseSkillMentionPrefix(slice)) return null;
|
|
43
|
+
return slice;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function parseSkillMentionPrefix(atPrefix: string | null): { query: string } | null {
|
|
47
|
+
if (!atPrefix?.startsWith(SKILL_MENTION_TOKEN)) return null;
|
|
48
|
+
const tail = atPrefix.slice(SKILL_MENTION_TOKEN.length);
|
|
49
|
+
if (tail.length > 0 && !tail.startsWith(" ")) return null;
|
|
50
|
+
return { query: tail.startsWith(" ") ? tail.trimStart() : "" };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function parsePlanMentionPrefix(atPrefix: string | null): { query: string } | null {
|
|
54
|
+
if (!atPrefix) return null;
|
|
55
|
+
for (const token of PLAN_MENTION_TOKENS_LONGEST_FIRST) {
|
|
56
|
+
if (!atPrefix.startsWith(token)) continue;
|
|
57
|
+
const tail = atPrefix.slice(token.length);
|
|
58
|
+
if (tail.length > 0 && !tail.startsWith(" ")) continue;
|
|
59
|
+
return { query: tail.startsWith(" ") ? tail.trimStart() : "" };
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function filterSkillSuggestions(
|
|
65
|
+
skills: KubbisecSkillEntry[],
|
|
66
|
+
query: string,
|
|
67
|
+
): AutocompleteItem[] {
|
|
68
|
+
const items = skills.map((skill) => ({
|
|
69
|
+
value: skill.name,
|
|
70
|
+
label: skill.name,
|
|
71
|
+
description: skill.description,
|
|
72
|
+
}));
|
|
73
|
+
if (!query) return items;
|
|
74
|
+
return fuzzyFilter(items, query, (item) => `${item.label} ${item.description ?? ""}`).map(
|
|
75
|
+
(item) => ({
|
|
76
|
+
value: item.value,
|
|
77
|
+
label: item.label,
|
|
78
|
+
description: item.description,
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Pi expands `/skill:name` — map `@skill name` before submit. */
|
|
84
|
+
export function transformAtSkillMentions(text: string): string {
|
|
85
|
+
return text.replace(/@skill\s+([^\s@/]+)/g, "/skill:$1");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Map `@plan` / `@planejar` to `/mode:plan` before submit. */
|
|
89
|
+
export function transformAtPlanMentions(text: string): string {
|
|
90
|
+
const tokenPattern = PLAN_MENTION_TOKENS_LONGEST_FIRST.map((t) =>
|
|
91
|
+
t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
|
|
92
|
+
).join("|");
|
|
93
|
+
const pattern = new RegExp(`(^|[\\s"'=])(${tokenPattern})(\\s[\\s\\S]*)?`, "g");
|
|
94
|
+
return text.replace(pattern, (_match, delim: string, _token: string, tail?: string) => {
|
|
95
|
+
const query = tail ? tail.trimStart() : "";
|
|
96
|
+
return `${delim}/mode:plan${query ? ` ${query}` : ""}`;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Apply skill transform first, then plan (CHAT-004). */
|
|
101
|
+
export function transformChatMentions(text: string): string {
|
|
102
|
+
return transformAtPlanMentions(transformAtSkillMentions(text));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function applySkillMentionCompletion(
|
|
106
|
+
lines: string[],
|
|
107
|
+
cursorLine: number,
|
|
108
|
+
cursorCol: number,
|
|
109
|
+
item: AutocompleteItem,
|
|
110
|
+
prefix: string,
|
|
111
|
+
): { lines: string[]; cursorLine: number; cursorCol: number } {
|
|
112
|
+
const currentLine = lines[cursorLine] ?? "";
|
|
113
|
+
const beforePrefix = currentLine.slice(0, cursorCol - prefix.length);
|
|
114
|
+
const afterCursor = currentLine.slice(cursorCol);
|
|
115
|
+
const atIndex = beforePrefix.lastIndexOf(SKILL_MENTION_TOKEN);
|
|
116
|
+
const head = atIndex >= 0 ? beforePrefix.slice(0, atIndex) : beforePrefix;
|
|
117
|
+
const insertion = `${SKILL_MENTION_TOKEN} ${item.value} `;
|
|
118
|
+
const newLine = `${head}${insertion}${afterCursor}`;
|
|
119
|
+
const newLines = [...lines];
|
|
120
|
+
newLines[cursorLine] = newLine;
|
|
121
|
+
return {
|
|
122
|
+
lines: newLines,
|
|
123
|
+
cursorLine,
|
|
124
|
+
cursorCol: head.length + insertion.length,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-local
|
|
3
|
+
description: Local gh/git, naus, and aspm on the machine running kbs chat — only when user passed --extended-context.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
If extended context is disabled, tell the user to restart:
|
|
7
|
+
|
|
8
|
+
`kbs chat --extended-context -p <project-id> -w /path/to/clone`
|
|
9
|
+
|
|
10
|
+
## Tools
|
|
11
|
+
|
|
12
|
+
- **GitHub:** `github_local_status`, `github_local_repo_summary`
|
|
13
|
+
- **NAUS:** `naus_local_status`, `naus_local_validate`, `naus_local_plan`, `naus_local_run`
|
|
14
|
+
- **ASPM:** `aspm_local_status`, `aspm_local_doctor`, `aspm_local_scan`, `aspm_local_upload`
|
|
15
|
+
|
|
16
|
+
Cloud equivalents remain on the API (e.g. `trigger_run`, `naus_validate_yaml`, platform upload via CI).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type KubbisecSkillEntry = {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
};
|
|
5
|
+
/** Skills shipped under dist/skills (same dirs passed as Pi --skill). */
|
|
6
|
+
export declare function listBundledKubbisecSkills(): KubbisecSkillEntry[];
|
|
7
|
+
//# sourceMappingURL=list-bundled-skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-bundled-skills.d.ts","sourceRoot":"","sources":["../../src/skills/list-bundled-skills.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAoBF,yEAAyE;AACzE,wBAAgB,yBAAyB,IAAI,kBAAkB,EAAE,CAiBhE"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { resolveBundledDistRoot, resolveSnapshotBundledDistDir } from "../resolve-bundled-dist-root.js";
|
|
4
|
+
function parseSkillFrontmatter(raw) {
|
|
5
|
+
const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
6
|
+
if (!match)
|
|
7
|
+
return {};
|
|
8
|
+
const block = match[1];
|
|
9
|
+
const name = block.match(/^name:\s*(.+)$/m)?.[1]?.trim();
|
|
10
|
+
const description = block.match(/^description:\s*(.+)$/m)?.[1]?.trim();
|
|
11
|
+
return { name, description };
|
|
12
|
+
}
|
|
13
|
+
function resolveSkillsDir() {
|
|
14
|
+
const distDir = path.join(resolveBundledDistRoot(), "skills");
|
|
15
|
+
if (fs.existsSync(distDir))
|
|
16
|
+
return distDir;
|
|
17
|
+
const entryDir = path.dirname(resolveSnapshotBundledDistDir());
|
|
18
|
+
const srcDir = path.join(entryDir, "src/skills");
|
|
19
|
+
if (fs.existsSync(srcDir))
|
|
20
|
+
return srcDir;
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
/** Skills shipped under dist/skills (same dirs passed as Pi --skill). */
|
|
24
|
+
export function listBundledKubbisecSkills() {
|
|
25
|
+
const skillsDir = resolveSkillsDir();
|
|
26
|
+
if (!skillsDir)
|
|
27
|
+
return [];
|
|
28
|
+
const entries = [];
|
|
29
|
+
for (const dir of fs.readdirSync(skillsDir, { withFileTypes: true })) {
|
|
30
|
+
if (!dir.isDirectory())
|
|
31
|
+
continue;
|
|
32
|
+
const skillMd = path.join(skillsDir, dir.name, "SKILL.md");
|
|
33
|
+
if (!fs.existsSync(skillMd))
|
|
34
|
+
continue;
|
|
35
|
+
const raw = fs.readFileSync(skillMd, "utf8");
|
|
36
|
+
const meta = parseSkillFrontmatter(raw);
|
|
37
|
+
entries.push({
|
|
38
|
+
name: meta.name?.trim() || dir.name,
|
|
39
|
+
description: meta.description?.trim() || dir.name,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=list-bundled-skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-bundled-skills.js","sourceRoot":"","sources":["../../src/skills/list-bundled-skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAOxG,SAAS,qBAAqB,CAAC,GAAW;IACxC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACvD,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACzD,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACvE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC9D,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,6BAA6B,EAAE,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACjD,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACzC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,yBAAyB;IACvC,MAAM,SAAS,GAAG,gBAAgB,EAAE,CAAC;IACrC,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,CAAC;IAE1B,MAAM,OAAO,GAAyB,EAAE,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACrE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE;YAAE,SAAS;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC3D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,SAAS;QACtC,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,IAAI;YACnC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,IAAI;SAClD,CAAC,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { resolveBundledDistRoot, resolveSnapshotBundledDistDir } from "../resolve-bundled-dist-root.js";
|
|
4
|
+
|
|
5
|
+
export type KubbisecSkillEntry = {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function parseSkillFrontmatter(raw: string): { name?: string; description?: string } {
|
|
11
|
+
const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
12
|
+
if (!match) return {};
|
|
13
|
+
const block = match[1];
|
|
14
|
+
const name = block.match(/^name:\s*(.+)$/m)?.[1]?.trim();
|
|
15
|
+
const description = block.match(/^description:\s*(.+)$/m)?.[1]?.trim();
|
|
16
|
+
return { name, description };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function resolveSkillsDir(): string | null {
|
|
20
|
+
const distDir = path.join(resolveBundledDistRoot(), "skills");
|
|
21
|
+
if (fs.existsSync(distDir)) return distDir;
|
|
22
|
+
const entryDir = path.dirname(resolveSnapshotBundledDistDir());
|
|
23
|
+
const srcDir = path.join(entryDir, "src/skills");
|
|
24
|
+
if (fs.existsSync(srcDir)) return srcDir;
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Skills shipped under dist/skills (same dirs passed as Pi --skill). */
|
|
29
|
+
export function listBundledKubbisecSkills(): KubbisecSkillEntry[] {
|
|
30
|
+
const skillsDir = resolveSkillsDir();
|
|
31
|
+
if (!skillsDir) return [];
|
|
32
|
+
|
|
33
|
+
const entries: KubbisecSkillEntry[] = [];
|
|
34
|
+
for (const dir of fs.readdirSync(skillsDir, { withFileTypes: true })) {
|
|
35
|
+
if (!dir.isDirectory()) continue;
|
|
36
|
+
const skillMd = path.join(skillsDir, dir.name, "SKILL.md");
|
|
37
|
+
if (!fs.existsSync(skillMd)) continue;
|
|
38
|
+
const raw = fs.readFileSync(skillMd, "utf8");
|
|
39
|
+
const meta = parseSkillFrontmatter(raw);
|
|
40
|
+
entries.push({
|
|
41
|
+
name: meta.name?.trim() || dir.name,
|
|
42
|
+
description: meta.description?.trim() || dir.name,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
46
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: naus-pipelines
|
|
3
|
+
description: NAUS CI/CD — YAML, validação @naus/validation, runners e jobs ASPM no KubbiSec.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Fluxo na plataforma (cloud)
|
|
7
|
+
|
|
8
|
+
1. `naus_pipeline_docs` — 20 secções web (paridade `kubbisec://naus/*`) + runner-management + validation.
|
|
9
|
+
2. `naus_schema_overview` — campos e kinds suportados.
|
|
10
|
+
3. `naus_validate_yaml` — validar candidato antes de persistir.
|
|
11
|
+
4. `set_editor_yaml` (preview) → `set_pipeline_yaml` (bound) → `trigger_run` → `get_run_logs_excerpt`.
|
|
12
|
+
|
|
13
|
+
## Fluxo local (`kbs chat --extended-context -w <repo>`)
|
|
14
|
+
|
|
15
|
+
- `naus_local_status` — `naus` no PATH.
|
|
16
|
+
- `naus_local_validate` — `naus validate <path>` no workspace.
|
|
17
|
+
- `naus_local_plan` — `naus plan <path>` (text ou mermaid).
|
|
18
|
+
- `naus_local_run` — `naus run <path>` (até 15 min; preferir `trigger_run` em CI cloud).
|
|
19
|
+
|
|
20
|
+
**Não** invocar `naus register`, `naus start` ou `naus daemon` via chat — processos persistentes; ver `naus_pipeline_docs` / runner-management.
|
|
21
|
+
|
|
22
|
+
## Kinds ASPM
|
|
23
|
+
|
|
24
|
+
- `kind: aspm` + `tool` (trivy, gitleaks, syft, osv, semgrep, sonar, nmap, skipfish).
|
|
25
|
+
- `kind: aspm_matrix` — `parallel` com várias tools.
|
|
26
|
+
- `kind: aspm_gate` — políticas após upload.
|
|
27
|
+
- `kind: docker` — build/registry; `aspm.tool: trivy` para scan de imagem + gate.
|
|
28
|
+
|
|
29
|
+
## Scanners locais
|
|
30
|
+
|
|
31
|
+
Para `aspm scan` / `aspm upload` no host, skill `aspm-platform` e `aspm_local_*`.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: remediation
|
|
3
|
+
description: Apply minimal security fixes from KubbiSec findings; clone via API credentials (EnvPack GITHUB_TOKEN + org GitHub); auto mode opens PR with gh+git non-interactive.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Fix the finding using the cloned repository workspace.
|
|
7
|
+
|
|
8
|
+
1. Resolve repo: `kubsec_github_repository` (token from EnvPack `GITHUB_TOKEN` / `GH_TOKEN` overrides org app token when set).
|
|
9
|
+
2. Apply minimal code changes from real evidence only — no invented CVEs or paths.
|
|
10
|
+
3. Auto-PR (`kbs fix --mode auto`): commit, `git push`, `gh pr create` with `GIT_TERMINAL_PROMPT=0` and `GH_PROMPT_DISABLED=1`.
|
|
11
|
+
|
|
12
|
+
For local machine context in chat, user must run `kbs chat --extended-context` then `github_local_status`.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scanner-gitleaks
|
|
3
|
+
description: Gitleaks — deteção de secrets em repositórios Git.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Chame `security_scanner_playbook(scanner="gitleaks", platform?, topic?)`.
|
|
7
|
+
|
|
8
|
+
Relatório: `gitleaks-report.json`. Upload: `-s gitleaks`.
|
|
9
|
+
|
|
10
|
+
NAUS: `kind: aspm` com `tool: gitleaks` ou entrada em `aspm_matrix.parallel`.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scanner-nmap
|
|
3
|
+
description: Nmap — scan de rede e portas (XML para ASPM).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Chame `security_scanner_playbook(scanner="nmap", platform?, topic?)`.
|
|
7
|
+
|
|
8
|
+
Relatório: `nmap-report.xml` (`-oX`). Upload: `-s nmap`.
|
|
9
|
+
|
|
10
|
+
NAUS: `kind: aspm` com `tool: nmap` e `target` da rede/host.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scanner-osv
|
|
3
|
+
description: OSV-Scanner — advisories em dependências e lockfiles.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Chame `security_scanner_playbook(scanner="osv", platform?, topic?)`.
|
|
7
|
+
|
|
8
|
+
Relatório: `osv-report.json`. Upload: `-s osv`.
|
|
9
|
+
|
|
10
|
+
NAUS: `kind: aspm` com `tool: osv`.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scanner-semgrep
|
|
3
|
+
description: Semgrep — SAST com regras e políticas customizadas.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Chame `security_scanner_playbook(scanner="semgrep", platform?, topic?)`.
|
|
7
|
+
|
|
8
|
+
Relatório: `semgrep-report.json`. Upload: `-s semgrep`.
|
|
9
|
+
|
|
10
|
+
NAUS: `kind: aspm` com `tool: semgrep`; imagem padrão `semgrep/semgrep:latest`.
|