@kubbisec/ai-linux-arm64 0.1.3 → 0.1.4

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.
Files changed (122) hide show
  1. package/bin/kubbisec +0 -0
  2. package/bundled/assets/terminal/banner-compact.ansi +7 -0
  3. package/bundled/assets/terminal/banner-wide.ansi +10 -0
  4. package/bundled/assets/terminal/logotipo-compact-fallback.ansi +7 -0
  5. package/bundled/assets/terminal/logotipo-compact.ansi +1 -0
  6. package/bundled/assets/terminal/logotipo-compact.png +0 -0
  7. package/bundled/assets/terminal/logotipo-wide-fallback.ansi +10 -0
  8. package/bundled/assets/terminal/logotipo-wide.ansi +1 -0
  9. package/bundled/assets/terminal/logotipo-wide.png +0 -0
  10. package/bundled/assets/terminal/mark.ansi +7 -0
  11. package/bundled/edit-format.md +17 -0
  12. package/bundled/extensions/cli-local-shared.d.ts +26 -0
  13. package/bundled/extensions/cli-local-shared.d.ts.map +1 -0
  14. package/bundled/extensions/cli-local-shared.js +97 -0
  15. package/bundled/extensions/cli-local-shared.js.map +1 -0
  16. package/bundled/extensions/kubbisec-aspm-local.extension.d.ts +17 -0
  17. package/bundled/extensions/kubbisec-aspm-local.extension.d.ts.map +1 -0
  18. package/bundled/extensions/kubbisec-aspm-local.extension.js +134 -0
  19. package/bundled/extensions/kubbisec-aspm-local.extension.js.map +1 -0
  20. package/bundled/extensions/kubbisec-brand.extension.d.ts +20 -0
  21. package/bundled/extensions/kubbisec-brand.extension.d.ts.map +1 -0
  22. package/bundled/extensions/kubbisec-brand.extension.js +84 -0
  23. package/bundled/extensions/kubbisec-brand.extension.js.map +1 -0
  24. package/bundled/extensions/kubbisec-byok-provider.extension.d.ts +30 -0
  25. package/bundled/extensions/kubbisec-byok-provider.extension.d.ts.map +1 -0
  26. package/bundled/extensions/kubbisec-byok-provider.extension.js +44 -0
  27. package/bundled/extensions/kubbisec-byok-provider.extension.js.map +1 -0
  28. package/bundled/extensions/kubbisec-clarify.extension.d.ts +45 -0
  29. package/bundled/extensions/kubbisec-clarify.extension.d.ts.map +1 -0
  30. package/bundled/extensions/kubbisec-clarify.extension.js +305 -0
  31. package/bundled/extensions/kubbisec-clarify.extension.js.map +1 -0
  32. package/bundled/extensions/kubbisec-footer.extension.d.ts +64 -0
  33. package/bundled/extensions/kubbisec-footer.extension.d.ts.map +1 -0
  34. package/bundled/extensions/kubbisec-footer.extension.js +187 -0
  35. package/bundled/extensions/kubbisec-footer.extension.js.map +1 -0
  36. package/bundled/extensions/kubbisec-github-local.extension.d.ts +23 -0
  37. package/bundled/extensions/kubbisec-github-local.extension.d.ts.map +1 -0
  38. package/bundled/extensions/kubbisec-github-local.extension.js +105 -0
  39. package/bundled/extensions/kubbisec-github-local.extension.js.map +1 -0
  40. package/bundled/extensions/kubbisec-memory.extension.d.ts +12 -0
  41. package/bundled/extensions/kubbisec-memory.extension.d.ts.map +1 -0
  42. package/bundled/extensions/kubbisec-memory.extension.js +107 -0
  43. package/bundled/extensions/kubbisec-memory.extension.js.map +1 -0
  44. package/bundled/extensions/kubbisec-naus-local.extension.d.ts +17 -0
  45. package/bundled/extensions/kubbisec-naus-local.extension.d.ts.map +1 -0
  46. package/bundled/extensions/kubbisec-naus-local.extension.js +125 -0
  47. package/bundled/extensions/kubbisec-naus-local.extension.js.map +1 -0
  48. package/bundled/extensions/kubbisec-platform-tools.extension.d.ts +27 -0
  49. package/bundled/extensions/kubbisec-platform-tools.extension.d.ts.map +1 -0
  50. package/bundled/extensions/kubbisec-platform-tools.extension.js +144 -0
  51. package/bundled/extensions/kubbisec-platform-tools.extension.js.map +1 -0
  52. package/bundled/extensions/kubbisec-runtime-status.extension.d.ts +13 -0
  53. package/bundled/extensions/kubbisec-runtime-status.extension.d.ts.map +1 -0
  54. package/bundled/extensions/kubbisec-runtime-status.extension.js +18 -0
  55. package/bundled/extensions/kubbisec-runtime-status.extension.js.map +1 -0
  56. package/bundled/extensions/kubbisec-scope.extension.d.ts +14 -0
  57. package/bundled/extensions/kubbisec-scope.extension.d.ts.map +1 -0
  58. package/bundled/extensions/kubbisec-scope.extension.js +14 -0
  59. package/bundled/extensions/kubbisec-scope.extension.js.map +1 -0
  60. package/bundled/extensions/kubbisec-skill-mentions.extension.d.ts +24 -0
  61. package/bundled/extensions/kubbisec-skill-mentions.extension.d.ts.map +1 -0
  62. package/bundled/extensions/kubbisec-skill-mentions.extension.js +54 -0
  63. package/bundled/extensions/kubbisec-skill-mentions.extension.js.map +1 -0
  64. package/bundled/extensions/kubbisec-skill-telemetry.extension.d.ts +6 -0
  65. package/bundled/extensions/kubbisec-skill-telemetry.extension.d.ts.map +1 -0
  66. package/bundled/extensions/kubbisec-skill-telemetry.extension.js +85 -0
  67. package/bundled/extensions/kubbisec-skill-telemetry.extension.js.map +1 -0
  68. package/bundled/extensions/kubbisec-ui.extension.d.ts +6 -0
  69. package/bundled/extensions/kubbisec-ui.extension.d.ts.map +1 -0
  70. package/bundled/extensions/kubbisec-ui.extension.js +116 -0
  71. package/bundled/extensions/kubbisec-ui.extension.js.map +1 -0
  72. package/bundled/extensions/kubbisec-workflow.extension.d.ts +38 -0
  73. package/bundled/extensions/kubbisec-workflow.extension.d.ts.map +1 -0
  74. package/bundled/extensions/kubbisec-workflow.extension.js +169 -0
  75. package/bundled/extensions/kubbisec-workflow.extension.js.map +1 -0
  76. package/bundled/gate-system.md +27 -0
  77. package/bundled/reflect-system.md +31 -0
  78. package/bundled/skills/aspm-platform/SKILL.md +58 -0
  79. package/bundled/skills/chat-mention-render.d.ts +7 -0
  80. package/bundled/skills/chat-mention-render.d.ts.map +1 -0
  81. package/bundled/skills/chat-mention-render.js +122 -0
  82. package/bundled/skills/chat-mention-render.js.map +1 -0
  83. package/bundled/skills/chat-mention-render.test.ts +47 -0
  84. package/bundled/skills/chat-mention-render.ts +141 -0
  85. package/bundled/skills/chat-mentions.d.ts +27 -0
  86. package/bundled/skills/chat-mentions.d.ts.map +1 -0
  87. package/bundled/skills/chat-mentions.js +104 -0
  88. package/bundled/skills/chat-mentions.js.map +1 -0
  89. package/bundled/skills/chat-mentions.test.ts +32 -0
  90. package/bundled/skills/chat-mentions.ts +126 -0
  91. package/bundled/skills/github-local/SKILL.md +16 -0
  92. package/bundled/skills/list-bundled-skills.d.ts +7 -0
  93. package/bundled/skills/list-bundled-skills.d.ts.map +1 -0
  94. package/bundled/skills/list-bundled-skills.js +44 -0
  95. package/bundled/skills/list-bundled-skills.js.map +1 -0
  96. package/bundled/skills/list-bundled-skills.ts +46 -0
  97. package/bundled/skills/naus-pipelines/SKILL.md +31 -0
  98. package/bundled/skills/remediation/SKILL.md +12 -0
  99. package/bundled/skills/scanner-gitleaks/SKILL.md +10 -0
  100. package/bundled/skills/scanner-nmap/SKILL.md +10 -0
  101. package/bundled/skills/scanner-osv/SKILL.md +10 -0
  102. package/bundled/skills/scanner-semgrep/SKILL.md +10 -0
  103. package/bundled/skills/scanner-skipfish/SKILL.md +10 -0
  104. package/bundled/skills/scanner-sonar/SKILL.md +10 -0
  105. package/bundled/skills/scanner-syft/SKILL.md +10 -0
  106. package/bundled/skills/scanner-trivy/SKILL.md +10 -0
  107. package/bundled/skills/sec-brainstorm/SKILL.md +74 -0
  108. package/bundled/skills/sec-clarify/SKILL.md +68 -0
  109. package/bundled/skills/sec-debug/SKILL.md +94 -0
  110. package/bundled/skills/sec-plan/SKILL.md +101 -0
  111. package/bundled/skills/sec-review/SKILL.md +110 -0
  112. package/bundled/skills/sec-review/code-reviewer-sec.md +176 -0
  113. package/bundled/skills/sec-using-skills/SKILL.md +79 -0
  114. package/bundled/skills/sec-verify/SKILL.md +77 -0
  115. package/bundled/skills/skill-mention.d.ts +3 -0
  116. package/bundled/skills/skill-mention.d.ts.map +1 -0
  117. package/bundled/skills/skill-mention.js +3 -0
  118. package/bundled/skills/skill-mention.js.map +1 -0
  119. package/bundled/skills/skill-mention.test.ts +46 -0
  120. package/bundled/skills/skill-mention.ts +10 -0
  121. package/bundled/theme/kubbisec.json +93 -0
  122. package/package.json +3 -2
@@ -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`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: scanner-skipfish
3
+ description: Skipfish — DAST web (crawling/fuzzing).
4
+ ---
5
+
6
+ Chame `security_scanner_playbook(scanner="skipfish", platform?, topic?)`.
7
+
8
+ Relatório: `skipfish-report.json`. Upload: `-s skipfish`.
9
+
10
+ NAUS: `kind: aspm` com `tool: skipfish` e URL em `target`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: scanner-sonar
3
+ description: SonarQube — SAST via export JSON da API Sonar.
4
+ ---
5
+
6
+ Chame `security_scanner_playbook(scanner="sonar", platform?, topic?)`.
7
+
8
+ Relatório: `sonar-report.json` (export API). Upload: `-s sonar`.
9
+
10
+ NAUS: `kind: aspm` com `tool: sonar`, frequentemente `mode: upload` após export.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: scanner-syft
3
+ description: Syft — geração de SBOM (CycloneDX/SPDX) para ASPM.
4
+ ---
5
+
6
+ Chame `security_scanner_playbook(scanner="syft", platform?, topic?)`.
7
+
8
+ Relatório: `sbom.json` (cyclonedx-json). Upload: `-s syft`.
9
+
10
+ NAUS: `kind: aspm` com `tool: syft`; matrix com `format: cyclonedx-json`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: scanner-trivy
3
+ description: Trivy — SCA, imagens Docker, IaC; upload ASPM e job NAUS.
4
+ ---
5
+
6
+ Chame `security_scanner_playbook(scanner="trivy", platform="linux"|"macos"|"windows", topic="install"|"scan"|"upload"|"naus"|"formats"|"all")`.
7
+
8
+ Relatório típico: `trivy-report.json`. Upload: `aspm upload trivy-report.json -s trivy`.
9
+
10
+ NAUS: `kind: aspm` com `tool: trivy`; preset `kind: docker` com `aspm.tool: trivy` e gate.
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: sec-brainstorm
3
+ description: "Before any implementation: explore context, threat model, design; write .kbs/specs/*.md; HARD-GATE until user approves."
4
+ metadata:
5
+ kubbisec:
6
+ category: workflow
7
+ requires: [session-questionnaire.json]
8
+ produces: kbs-spec
9
+ ---
10
+
11
+ # sec-brainstorm — Design + threat model (KubbiSec)
12
+
13
+ **Announce:** `Using sec-brainstorm to explore design and write runtime spec.`
14
+
15
+ <HARD-GATE>
16
+ Do NOT invoke implementation actions (edit/write/bash that mutates repo), domain skills that change code, or claim work complete until:
17
+
18
+ 1. A runtime spec exists at `.kbs/specs/*.md`, AND
19
+ 2. The user has explicitly approved it (`approved` / `aprovado`).
20
+
21
+ Read-only tools (read, grep, ls) are always allowed.
22
+ </HARD-GATE>
23
+
24
+ ## When to use
25
+
26
+ - New feature, refactor, or security policy change in chat
27
+ - `/mode:plan` or `@plan` with no approved runtime spec yet
28
+ - After `sec-clarify` (or equivalent structured brief)
29
+
30
+ ## When NOT to use
31
+
32
+ - CVE remediation in `kbs fix` harness
33
+ - Trivial typo-only changes (user must confirm below HARD-GATE threshold in writing)
34
+ - Mid-implementation — use domain skills instead
35
+
36
+ ## Process
37
+
38
+ 1. **Explore context** — read relevant repo paths, `docs/`, recent git log (read-only)
39
+ 2. **Clarifying questions** — one at a time, max 5 after clarify if gaps remain
40
+ 3. **Propose 2–3 approaches** — security trade-offs; recommend one
41
+ 4. **Present design** — section by section; user confirms or revises
42
+ 5. **Threat model** — STRIDE-lite table (min 3 rows for auth/network/deps)
43
+ 6. **Write spec** — `.kbs/specs/YYYY-MM-DD-<slug>.md` with `status: draft`
44
+ 7. **Self-review** — fix placeholders, contradictions inline
45
+ 8. **Request approval** — "Revise o arquivo ou responda `approved` para liberar implementação."
46
+ 9. **Handoff** — on approval, invoke **`sec-plan` only** (never direct implementation)
47
+
48
+ ## Runtime spec template
49
+
50
+ Write `.kbs/specs/YYYY-MM-DD-<slug>.md` with these sections:
51
+
52
+ - **Metadata** — yaml block: `id`, `status: draft`, `created`, `orgId`, `projectId`
53
+ - **Problem statement**
54
+ - **Threat model (required)** — table: Threat | STRIDE | Mitigation in design | Verification
55
+ - **Design** — recommended approach
56
+ - **Out of scope**
57
+ - **Approval** — checkbox for user `approved` / `aprovado`
58
+
59
+ Slug rules: `YYYY-MM-DD-<kebab-slug>.md`, max 48 chars, `[a-z0-9-]` only.
60
+
61
+ ## Threat model must address
62
+
63
+ - Injection, authz, secrets handling, supply chain (deps), logging sensitive data
64
+ - Do not propose storing credentials in repo or `.kbs/`
65
+
66
+ ## Anti-patterns
67
+
68
+ - Skipping HARD-GATE for "simple" changes without user written confirmation
69
+ - Writing app code before `approved`
70
+ - Conflicts with `docs/kubbisec-ai/specs/` — prefer repo product specs as platform truth; note conflicts in spec
71
+
72
+ ---
73
+
74
+ *Adapted from Superpowers (obra/superpowers) — MIT License.*