@kubbisec/ai-linux-x64 0.1.22 → 0.1.23
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/components/kubbisec-model-selector.d.ts +47 -34
- package/bundled/components/kubbisec-model-selector.js +187 -177
- package/bundled/config/config.d.ts +6 -6
- package/bundled/config/config.js +54 -52
- package/bundled/config/detect-local-llm-providers.d.ts +26 -16
- package/bundled/config/detect-local-llm-providers.js +130 -142
- package/bundled/config/ensure-kbs-project-settings.d.ts +8 -8
- package/bundled/config/ensure-kbs-project-settings.js +27 -28
- package/bundled/config/ensure-kubbisec-project-settings.d.ts +9 -9
- package/bundled/config/ensure-kubbisec-project-settings.js +62 -67
- package/bundled/config/extended-context.d.ts +5 -6
- package/bundled/config/extended-context.js +23 -22
- package/bundled/config/feature-flags.d.ts +10 -2
- package/bundled/config/feature-flags.js +8 -2
- package/bundled/config/format-kubbisec-footer-status.d.ts +1 -1
- package/bundled/config/format-kubbisec-footer-status.js +26 -31
- package/bundled/config/kubbisec-extension-manifest.d.ts +21 -2
- package/bundled/config/kubbisec-extension-manifest.js +19 -19
- package/bundled/config/llm-config-mutations.d.ts +51 -25
- package/bundled/config/llm-config-mutations.js +173 -182
- package/bundled/config/llm-config.d.ts +54 -41
- package/bundled/config/llm-config.js +199 -199
- package/bundled/config/llm-provider-catalog.d.ts +18 -15
- package/bundled/config/llm-provider-catalog.js +45 -46
- package/bundled/config/materialize-kubbisec-pi-resources.d.ts +1 -1
- package/bundled/config/materialize-kubbisec-pi-resources.js +173 -182
- package/bundled/config/register-custom-llm-providers.d.ts +11 -5
- package/bundled/config/register-custom-llm-providers.js +17 -15
- package/bundled/config/register-kubbisec-llm-provider.d.ts +14 -10
- package/bundled/config/register-kubbisec-llm-provider.js +50 -42
- package/bundled/config/resolve-agents-context-file.d.ts +1 -1
- package/bundled/config/resolve-agents-context-file.js +33 -34
- package/bundled/config/resource-budget.d.ts +12 -12
- package/bundled/config/resource-budget.js +28 -28
- package/bundled/config/sync-kubbisec-pi-models.d.ts +6 -3
- package/bundled/config/sync-kubbisec-pi-models.js +58 -58
- package/bundled/copy/cli-reference-index.d.ts +1 -1
- package/bundled/copy/cli-reference-index.js +1 -1
- package/bundled/copy/kubbisec-shell-copy.d.ts +11 -6
- package/bundled/copy/kubbisec-shell-copy.js +1 -1
- package/bundled/extensions/cli-local-shared.d.ts +56 -32
- package/bundled/extensions/cli-local-shared.js +135 -125
- package/bundled/extensions/kubbisec-aspm-local.extension.d.ts +18 -15
- package/bundled/extensions/kubbisec-aspm-local.extension.js +109 -106
- package/bundled/extensions/kubbisec-brand.extension.d.ts +1 -1
- package/bundled/extensions/kubbisec-brand.extension.js +25 -25
- package/bundled/extensions/kubbisec-byok-provider.extension.d.ts +1 -1
- package/bundled/extensions/kubbisec-byok-provider.extension.js +2 -2
- package/bundled/extensions/kubbisec-clarify.extension.d.ts +64 -35
- package/bundled/extensions/kubbisec-clarify.extension.js +323 -305
- package/bundled/extensions/kubbisec-exit.extension.d.ts +1 -1
- package/bundled/extensions/kubbisec-exit.extension.js +29 -32
- package/bundled/extensions/kubbisec-extended-context.extension.d.ts +1 -1
- package/bundled/extensions/kubbisec-extended-context.extension.js +56 -43
- package/bundled/extensions/kubbisec-footer.extension.d.ts +14 -14
- package/bundled/extensions/kubbisec-footer.extension.js +205 -215
- package/bundled/extensions/kubbisec-github-local.extension.d.ts +26 -18
- package/bundled/extensions/kubbisec-github-local.extension.js +430 -417
- package/bundled/extensions/kubbisec-llm-config.extension.d.ts +1 -1
- package/bundled/extensions/kubbisec-llm-config.extension.js +200 -181
- package/bundled/extensions/kubbisec-memory.extension.d.ts +9 -7
- package/bundled/extensions/kubbisec-memory.extension.js +88 -95
- package/bundled/extensions/kubbisec-naus-local.extension.d.ts +18 -15
- package/bundled/extensions/kubbisec-naus-local.extension.js +123 -103
- package/bundled/extensions/kubbisec-platform-tools.extension.d.ts +31 -21
- package/bundled/extensions/kubbisec-platform-tools.extension.js +152 -152
- package/bundled/extensions/kubbisec-runtime-status.extension.d.ts +10 -8
- package/bundled/extensions/kubbisec-runtime-status.extension.js +15 -13
- package/bundled/extensions/kubbisec-scope.extension.d.ts +12 -7
- package/bundled/extensions/kubbisec-scope.extension.js +13 -13
- package/bundled/extensions/kubbisec-skill-mentions.extension.d.ts +27 -16
- package/bundled/extensions/kubbisec-skill-mentions.extension.js +74 -64
- package/bundled/extensions/kubbisec-skill-telemetry.extension.d.ts +2 -3
- package/bundled/extensions/kubbisec-skill-telemetry.extension.js +59 -64
- package/bundled/extensions/kubbisec-theme-lock.extension.d.ts +1 -1
- package/bundled/extensions/kubbisec-theme-lock.extension.js +33 -34
- package/bundled/extensions/kubbisec-ui.extension.d.ts +1 -1
- package/bundled/extensions/kubbisec-ui.extension.js +90 -92
- package/bundled/extensions/kubbisec-workflow.extension.d.ts +20 -18
- package/bundled/extensions/kubbisec-workflow.extension.js +138 -140
- package/bundled/resolve-bundled-dist-root.js +121 -130
- package/bundled/skills/at-path-mentions.d.ts +1 -1
- package/bundled/skills/at-path-mentions.js +146 -153
- package/bundled/skills/chat-mention-render.d.ts +2 -2
- package/bundled/skills/chat-mention-render.js +121 -126
- package/bundled/skills/chat-mentions.d.ts +17 -8
- package/bundled/skills/chat-mentions.js +76 -76
- package/bundled/skills/list-bundled-skills.d.ts +3 -3
- package/bundled/skills/list-bundled-skills.js +33 -35
- package/bundled/skills/skill-mention.d.ts +10 -2
- package/bundled/skills/skill-mention.js +10 -2
- package/bundled/theme/clear-terminal.d.ts +1 -1
- package/bundled/theme/clear-terminal.js +3 -4
- package/bundled/theme/footer-render-hook.d.ts +1 -1
- package/bundled/theme/footer-render-hook.js +3 -3
- package/bundled/theme/kubbisec-brand-fg.d.ts +1 -1
- package/bundled/theme/kubbisec-brand-fg.js +2 -2
- package/bundled/theme/kubbisec-menu-themes.d.ts +7 -7
- package/bundled/theme/kubbisec-menu-themes.js +30 -31
- package/bundled/theme/kubbisec-theme-name.d.ts +1 -1
- package/bundled/theme/kubbisec-theme-name.js +1 -1
- package/bundled/theme/patch-pi-settings-theme.runtime.d.ts +1 -1
- package/bundled/theme/patch-pi-settings-theme.runtime.js +11 -10
- package/bundled/theme/render-compact-header.d.ts +13 -5
- package/bundled/theme/render-compact-header.js +126 -128
- package/bundled/workflow/session-workflow-mode.d.ts +1 -1
- package/bundled/workflow/session-workflow-mode.js +33 -33
- package/package.json +1 -1
|
@@ -1,184 +1,177 @@
|
|
|
1
1
|
import { readdirSync, statSync } from "node:fs";
|
|
2
2
|
import { basename, dirname, join, relative } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
extractAtPrefix,
|
|
5
|
+
parsePlanMentionPrefix,
|
|
6
|
+
parseSkillMentionPrefix,
|
|
7
|
+
} from "./chat-mentions.js";
|
|
8
|
+
|
|
4
9
|
function toDisplayPath(value) {
|
|
5
|
-
|
|
10
|
+
return value.replace(/\\/g, "/");
|
|
6
11
|
}
|
|
7
12
|
function parsePathPrefix(prefix) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
if (prefix.startsWith('@"')) {
|
|
14
|
+
return { rawPrefix: prefix.slice(2), isAtPrefix: true, isQuotedPrefix: true };
|
|
15
|
+
}
|
|
16
|
+
if (prefix.startsWith('"')) {
|
|
17
|
+
return { rawPrefix: prefix.slice(1), isAtPrefix: false, isQuotedPrefix: true };
|
|
18
|
+
}
|
|
19
|
+
if (prefix.startsWith("@")) {
|
|
20
|
+
return { rawPrefix: prefix.slice(1), isAtPrefix: true, isQuotedPrefix: false };
|
|
21
|
+
}
|
|
22
|
+
return { rawPrefix: prefix, isAtPrefix: false, isQuotedPrefix: false };
|
|
18
23
|
}
|
|
19
24
|
function buildCompletionValue(path, options) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const needsQuotes = options.isQuotedPrefix || path.includes(" ");
|
|
26
|
+
const prefix = options.isAtPrefix ? "@" : "";
|
|
27
|
+
if (!needsQuotes) {
|
|
28
|
+
return `${prefix}${path}`;
|
|
29
|
+
}
|
|
30
|
+
const openQuote = `${prefix}"`;
|
|
31
|
+
return `${openQuote}${path}"`;
|
|
27
32
|
}
|
|
28
33
|
const DEPRIORITIZED_AT_PATH_NAMES = new Set([
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
"node_modules",
|
|
35
|
+
"dist",
|
|
36
|
+
"dist-bin",
|
|
37
|
+
".turbo",
|
|
38
|
+
".git",
|
|
39
|
+
"coverage",
|
|
40
|
+
"build",
|
|
41
|
+
".next",
|
|
42
|
+
".cache",
|
|
43
|
+
"tmp",
|
|
44
|
+
".venv",
|
|
45
|
+
"target",
|
|
41
46
|
]);
|
|
42
47
|
const PRIORITY_AT_PATH_DIRS = [
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
"src",
|
|
49
|
+
"lib",
|
|
50
|
+
"apps",
|
|
51
|
+
"packages",
|
|
52
|
+
"scripts",
|
|
53
|
+
"test",
|
|
54
|
+
"tests",
|
|
55
|
+
"docs",
|
|
56
|
+
"spec",
|
|
52
57
|
];
|
|
53
58
|
const PRIORITY_AT_PATH_FILES = [
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
"package.json",
|
|
60
|
+
"README.md",
|
|
61
|
+
"readme.md",
|
|
62
|
+
"tsconfig.json",
|
|
63
|
+
"vitest.config.ts",
|
|
64
|
+
"Cargo.toml",
|
|
65
|
+
"go.mod",
|
|
66
|
+
"pyproject.toml",
|
|
67
|
+
"Makefile",
|
|
63
68
|
];
|
|
64
69
|
function atPathSuggestionRank(label) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return 2;
|
|
70
|
+
const name = label.replace(/\/$/, "");
|
|
71
|
+
if (PRIORITY_AT_PATH_DIRS.includes(name) || PRIORITY_AT_PATH_FILES.includes(name)) {
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
if (DEPRIORITIZED_AT_PATH_NAMES.has(name)) {
|
|
75
|
+
return 3;
|
|
76
|
+
}
|
|
77
|
+
if (label.endsWith("/")) {
|
|
78
|
+
return 1;
|
|
79
|
+
}
|
|
80
|
+
return 2;
|
|
77
81
|
}
|
|
78
82
|
function sortAtPathSuggestions(items, rawPrefix) {
|
|
79
|
-
|
|
80
|
-
return items.sort((a, b) => {
|
|
81
|
-
const aIsDir = a.label.endsWith("/");
|
|
82
|
-
const bIsDir = b.label.endsWith("/");
|
|
83
|
-
if (aIsDir && !bIsDir)
|
|
84
|
-
return -1;
|
|
85
|
-
if (!aIsDir && bIsDir)
|
|
86
|
-
return 1;
|
|
87
|
-
return a.label.localeCompare(b.label);
|
|
88
|
-
});
|
|
89
|
-
}
|
|
83
|
+
if (rawPrefix !== "") {
|
|
90
84
|
return items.sort((a, b) => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
85
|
+
const aIsDir = a.label.endsWith("/");
|
|
86
|
+
const bIsDir = b.label.endsWith("/");
|
|
87
|
+
if (aIsDir && !bIsDir) return -1;
|
|
88
|
+
if (!aIsDir && bIsDir) return 1;
|
|
89
|
+
return a.label.localeCompare(b.label);
|
|
95
90
|
});
|
|
91
|
+
}
|
|
92
|
+
return items.sort((a, b) => {
|
|
93
|
+
const rankDiff = atPathSuggestionRank(a.label) - atPathSuggestionRank(b.label);
|
|
94
|
+
if (rankDiff !== 0) return rankDiff;
|
|
95
|
+
return a.label.localeCompare(b.label);
|
|
96
|
+
});
|
|
96
97
|
}
|
|
97
98
|
/** `@` file attachment (not `@skill` / `@plan`). */
|
|
98
99
|
export function isAtFileAttachmentPrefix(atPrefix) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (parsePlanMentionPrefix(atPrefix))
|
|
104
|
-
return false;
|
|
105
|
-
return atPrefix.startsWith("@");
|
|
100
|
+
if (!atPrefix) return false;
|
|
101
|
+
if (parseSkillMentionPrefix(atPrefix)) return false;
|
|
102
|
+
if (parsePlanMentionPrefix(atPrefix)) return false;
|
|
103
|
+
return atPrefix.startsWith("@");
|
|
106
104
|
}
|
|
107
105
|
/** List cwd-scoped entries for `@` / `@path` (Pi getFileSuggestions semantics). */
|
|
108
106
|
export function getAtPathFileSuggestions(cwd, atPrefix) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
107
|
+
try {
|
|
108
|
+
const { rawPrefix, isAtPrefix, isQuotedPrefix } = parsePathPrefix(atPrefix);
|
|
109
|
+
if (!isAtPrefix) return [];
|
|
110
|
+
let searchDir;
|
|
111
|
+
let searchPrefix;
|
|
112
|
+
const expandedPrefix = rawPrefix;
|
|
113
|
+
const isRootPrefix =
|
|
114
|
+
rawPrefix === "" ||
|
|
115
|
+
rawPrefix === "./" ||
|
|
116
|
+
rawPrefix === "../" ||
|
|
117
|
+
rawPrefix === "/" ||
|
|
118
|
+
(isAtPrefix && rawPrefix === "");
|
|
119
|
+
if (isRootPrefix) {
|
|
120
|
+
searchDir = join(cwd, expandedPrefix);
|
|
121
|
+
searchPrefix = "";
|
|
122
|
+
} else if (rawPrefix.endsWith("/")) {
|
|
123
|
+
searchDir = join(cwd, expandedPrefix);
|
|
124
|
+
searchPrefix = "";
|
|
125
|
+
} else {
|
|
126
|
+
searchDir = join(cwd, dirname(expandedPrefix));
|
|
127
|
+
searchPrefix = basename(expandedPrefix);
|
|
128
|
+
}
|
|
129
|
+
const entries = readdirSync(searchDir, { withFileTypes: true });
|
|
130
|
+
const suggestions = [];
|
|
131
|
+
const cwdLabel = toDisplayPath(relative(cwd, searchDir) || ".");
|
|
132
|
+
for (const entry of entries) {
|
|
133
|
+
if (!entry.name.toLowerCase().startsWith(searchPrefix.toLowerCase())) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
let isDirectory = entry.isDirectory();
|
|
137
|
+
if (!isDirectory && entry.isSymbolicLink()) {
|
|
138
|
+
try {
|
|
139
|
+
isDirectory = statSync(join(searchDir, entry.name)).isDirectory();
|
|
140
|
+
} catch {
|
|
141
|
+
// broken symlink — treat as file
|
|
132
142
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
isDirectory = statSync(join(searchDir, entry.name)).isDirectory();
|
|
144
|
-
}
|
|
145
|
-
catch {
|
|
146
|
-
// broken symlink — treat as file
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
let relativePath;
|
|
150
|
-
const displayPrefix = rawPrefix;
|
|
151
|
-
const name = entry.name;
|
|
152
|
-
if (displayPrefix.endsWith("/")) {
|
|
153
|
-
relativePath = displayPrefix + name;
|
|
154
|
-
}
|
|
155
|
-
else if (displayPrefix.includes("/")) {
|
|
156
|
-
relativePath = join(dirname(displayPrefix), name);
|
|
157
|
-
if (displayPrefix.startsWith("./") && !relativePath.startsWith("./")) {
|
|
158
|
-
relativePath = `./${relativePath}`;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
relativePath = name;
|
|
163
|
-
}
|
|
164
|
-
relativePath = toDisplayPath(relativePath);
|
|
165
|
-
const pathValue = isDirectory ? `${relativePath}/` : relativePath;
|
|
166
|
-
const value = buildCompletionValue(pathValue, { isAtPrefix, isQuotedPrefix });
|
|
167
|
-
const entryRelative = toDisplayPath(relative(cwd, join(searchDir, entry.name)));
|
|
168
|
-
suggestions.push({
|
|
169
|
-
value,
|
|
170
|
-
label: name + (isDirectory ? "/" : ""),
|
|
171
|
-
description: searchDir === cwd && rawPrefix === "" ? entryRelative : `${cwdLabel}/${entryRelative}`,
|
|
172
|
-
});
|
|
143
|
+
}
|
|
144
|
+
let relativePath;
|
|
145
|
+
const displayPrefix = rawPrefix;
|
|
146
|
+
const name = entry.name;
|
|
147
|
+
if (displayPrefix.endsWith("/")) {
|
|
148
|
+
relativePath = displayPrefix + name;
|
|
149
|
+
} else if (displayPrefix.includes("/")) {
|
|
150
|
+
relativePath = join(dirname(displayPrefix), name);
|
|
151
|
+
if (displayPrefix.startsWith("./") && !relativePath.startsWith("./")) {
|
|
152
|
+
relativePath = `./${relativePath}`;
|
|
173
153
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
154
|
+
} else {
|
|
155
|
+
relativePath = name;
|
|
156
|
+
}
|
|
157
|
+
relativePath = toDisplayPath(relativePath);
|
|
158
|
+
const pathValue = isDirectory ? `${relativePath}/` : relativePath;
|
|
159
|
+
const value = buildCompletionValue(pathValue, { isAtPrefix, isQuotedPrefix });
|
|
160
|
+
const entryRelative = toDisplayPath(relative(cwd, join(searchDir, entry.name)));
|
|
161
|
+
suggestions.push({
|
|
162
|
+
value,
|
|
163
|
+
label: name + (isDirectory ? "/" : ""),
|
|
164
|
+
description:
|
|
165
|
+
searchDir === cwd && rawPrefix === "" ? entryRelative : `${cwdLabel}/${entryRelative}`,
|
|
166
|
+
});
|
|
178
167
|
}
|
|
168
|
+
return sortAtPathSuggestions(suggestions, rawPrefix);
|
|
169
|
+
} catch {
|
|
170
|
+
return [];
|
|
171
|
+
}
|
|
179
172
|
}
|
|
180
173
|
export function extractAtFilePrefix(textBeforeCursor) {
|
|
181
|
-
|
|
182
|
-
|
|
174
|
+
const atPrefix = extractAtPrefix(textBeforeCursor);
|
|
175
|
+
return isAtFileAttachmentPrefix(atPrefix) ? atPrefix : null;
|
|
183
176
|
}
|
|
184
|
-
//# sourceMappingURL=at-path-mentions.js.map
|
|
177
|
+
//# sourceMappingURL=at-path-mentions.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type MentionChipTheme = {
|
|
2
|
-
|
|
2
|
+
fg: (role: string, text: string) => string;
|
|
3
3
|
};
|
|
4
4
|
export declare function renderLineWithMentionChips(line: string, theme: MentionChipTheme): string;
|
|
5
5
|
export declare function logicalToVisibleCol(line: string, logicalCol: number): number;
|
|
6
6
|
export declare function visibleToLogicalCol(line: string, visibleCol: number): number;
|
|
7
|
-
//# sourceMappingURL=chat-mention-render.d.ts.map
|
|
7
|
+
//# sourceMappingURL=chat-mention-render.d.ts.map
|
|
@@ -1,160 +1,155 @@
|
|
|
1
1
|
import { visibleWidth } from "@earendil-works/pi-tui";
|
|
2
2
|
import { PLAN_MENTION_ALIASES } from "./chat-mentions.js";
|
|
3
|
+
|
|
3
4
|
const SKILL_SLASH_RE = /\/skill:([a-z0-9_-]+)/gi;
|
|
4
5
|
const AT_SKILL_RE = /@skill\s+([^\s@/]+)/gi;
|
|
5
6
|
const PLAN_TOKEN_RE = /\/mode:plan\b/gi;
|
|
6
7
|
const AT_PLAN_PATTERN = PLAN_MENTION_ALIASES.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
.sort((a, b) => b.length - a.length)
|
|
9
|
+
.join("|");
|
|
9
10
|
const AT_PLAN_RE = new RegExp(`(?:^|[\\s"'=])(${AT_PLAN_PATTERN})(?=\\s|$)`, "gi");
|
|
10
11
|
const PLAN_VISIBLE_LABEL = "@plan";
|
|
11
12
|
function findNextMentionMatch(line, cursor) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
13
|
+
const candidates = [];
|
|
14
|
+
SKILL_SLASH_RE.lastIndex = cursor;
|
|
15
|
+
const slashMatch = SKILL_SLASH_RE.exec(line);
|
|
16
|
+
if (slashMatch?.index !== undefined) {
|
|
17
|
+
candidates.push({
|
|
18
|
+
index: slashMatch.index,
|
|
19
|
+
length: slashMatch[0].length,
|
|
20
|
+
span: { kind: "skill", name: slashMatch[1] ?? "", source: "slash" },
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
AT_SKILL_RE.lastIndex = cursor;
|
|
24
|
+
const atMatch = AT_SKILL_RE.exec(line);
|
|
25
|
+
if (atMatch?.index !== undefined) {
|
|
26
|
+
candidates.push({
|
|
27
|
+
index: atMatch.index,
|
|
28
|
+
length: atMatch[0].length,
|
|
29
|
+
span: { kind: "skill", name: atMatch[1] ?? "", source: "at" },
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
PLAN_TOKEN_RE.lastIndex = cursor;
|
|
33
|
+
const planMatch = PLAN_TOKEN_RE.exec(line);
|
|
34
|
+
if (planMatch?.index !== undefined) {
|
|
35
|
+
candidates.push({
|
|
36
|
+
index: planMatch.index,
|
|
37
|
+
length: planMatch[0].length,
|
|
38
|
+
span: { kind: "plan", logicalToken: planMatch[0] },
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
AT_PLAN_RE.lastIndex = cursor;
|
|
42
|
+
const atPlanMatch = AT_PLAN_RE.exec(line);
|
|
43
|
+
if (atPlanMatch?.index !== undefined) {
|
|
44
|
+
const token = atPlanMatch[1] ?? "@plan";
|
|
45
|
+
const leading = atPlanMatch[0].length - token.length;
|
|
46
|
+
const index = atPlanMatch.index + leading;
|
|
47
|
+
candidates.push({
|
|
48
|
+
index,
|
|
49
|
+
length: token.length,
|
|
50
|
+
span: { kind: "plan", logicalToken: token },
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (candidates.length === 0) return null;
|
|
54
|
+
return candidates.reduce((earliest, candidate) =>
|
|
55
|
+
candidate.index < earliest.index ? candidate : earliest,
|
|
56
|
+
);
|
|
55
57
|
}
|
|
56
58
|
function parseMentionSpans(line) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
if (nextMatch.index > cursor) {
|
|
66
|
-
spans.push({ kind: "text", value: line.slice(cursor, nextMatch.index) });
|
|
67
|
-
}
|
|
68
|
-
spans.push(nextMatch.span);
|
|
69
|
-
cursor = nextMatch.index + nextMatch.length;
|
|
59
|
+
const spans = [];
|
|
60
|
+
let cursor = 0;
|
|
61
|
+
while (cursor < line.length) {
|
|
62
|
+
const nextMatch = findNextMentionMatch(line, cursor);
|
|
63
|
+
if (!nextMatch) {
|
|
64
|
+
spans.push({ kind: "text", value: line.slice(cursor) });
|
|
65
|
+
break;
|
|
70
66
|
}
|
|
71
|
-
if (
|
|
72
|
-
|
|
67
|
+
if (nextMatch.index > cursor) {
|
|
68
|
+
spans.push({ kind: "text", value: line.slice(cursor, nextMatch.index) });
|
|
73
69
|
}
|
|
74
|
-
|
|
70
|
+
spans.push(nextMatch.span);
|
|
71
|
+
cursor = nextMatch.index + nextMatch.length;
|
|
72
|
+
}
|
|
73
|
+
if (spans.length === 0) {
|
|
74
|
+
spans.push({ kind: "text", value: line });
|
|
75
|
+
}
|
|
76
|
+
return spans;
|
|
75
77
|
}
|
|
76
78
|
function skillVisibleText(span) {
|
|
77
|
-
|
|
79
|
+
return span.source === "at" ? `@${span.name}` : span.name;
|
|
78
80
|
}
|
|
79
81
|
function skillLogicalText(span) {
|
|
80
|
-
|
|
82
|
+
return span.source === "at" ? `@skill ${span.name}` : `/skill:${span.name}`;
|
|
81
83
|
}
|
|
82
84
|
function renderSpan(span, theme) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const text = skillVisibleText(span);
|
|
87
|
-
try {
|
|
88
|
-
return theme.fg("accent", text);
|
|
89
|
-
}
|
|
90
|
-
catch {
|
|
91
|
-
return theme.fg("text", text);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
85
|
+
if (span.kind === "text") return span.value;
|
|
86
|
+
if (span.kind === "skill") {
|
|
87
|
+
const text = skillVisibleText(span);
|
|
94
88
|
try {
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return theme.fg("text", PLAN_VISIBLE_LABEL);
|
|
89
|
+
return theme.fg("accent", text);
|
|
90
|
+
} catch {
|
|
91
|
+
return theme.fg("text", text);
|
|
99
92
|
}
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
return theme.fg("planAccent", PLAN_VISIBLE_LABEL);
|
|
96
|
+
} catch {
|
|
97
|
+
return theme.fg("text", PLAN_VISIBLE_LABEL);
|
|
98
|
+
}
|
|
100
99
|
}
|
|
101
100
|
function spanLogicalWidth(span) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return skillLogicalText(span).length;
|
|
106
|
-
return span.logicalToken.length;
|
|
101
|
+
if (span.kind === "text") return span.value.length;
|
|
102
|
+
if (span.kind === "skill") return skillLogicalText(span).length;
|
|
103
|
+
return span.logicalToken.length;
|
|
107
104
|
}
|
|
108
105
|
function spanVisibleText(span) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return skillVisibleText(span);
|
|
113
|
-
return PLAN_VISIBLE_LABEL;
|
|
106
|
+
if (span.kind === "text") return span.value;
|
|
107
|
+
if (span.kind === "skill") return skillVisibleText(span);
|
|
108
|
+
return PLAN_VISIBLE_LABEL;
|
|
114
109
|
}
|
|
115
110
|
export function renderLineWithMentionChips(line, theme) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
111
|
+
return parseMentionSpans(line)
|
|
112
|
+
.map((span) => renderSpan(span, theme))
|
|
113
|
+
.join("");
|
|
119
114
|
}
|
|
120
115
|
export function logicalToVisibleCol(line, logicalCol) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
logical += logicalLen;
|
|
136
|
-
visible += visibleLen;
|
|
116
|
+
const clamped = Math.max(0, Math.min(logicalCol, line.length));
|
|
117
|
+
let logical = 0;
|
|
118
|
+
let visible = 0;
|
|
119
|
+
for (const span of parseMentionSpans(line)) {
|
|
120
|
+
const logicalLen = spanLogicalWidth(span);
|
|
121
|
+
const visibleLen = visibleWidth(spanVisibleText(span));
|
|
122
|
+
if (logical + logicalLen >= clamped) {
|
|
123
|
+
const offset = clamped - logical;
|
|
124
|
+
if (span.kind === "text") {
|
|
125
|
+
return visible + offset;
|
|
126
|
+
}
|
|
127
|
+
const ratio = logicalLen > 0 ? offset / logicalLen : 0;
|
|
128
|
+
return visible + Math.round(visibleLen * ratio);
|
|
137
129
|
}
|
|
138
|
-
|
|
130
|
+
logical += logicalLen;
|
|
131
|
+
visible += visibleLen;
|
|
132
|
+
}
|
|
133
|
+
return visible;
|
|
139
134
|
}
|
|
140
135
|
export function visibleToLogicalCol(line, visibleCol) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
logical += logicalLen;
|
|
156
|
-
visible += visibleLen;
|
|
136
|
+
const clamped = Math.max(0, visibleCol);
|
|
137
|
+
let logical = 0;
|
|
138
|
+
let visible = 0;
|
|
139
|
+
for (const span of parseMentionSpans(line)) {
|
|
140
|
+
const logicalLen = spanLogicalWidth(span);
|
|
141
|
+
const visibleLen = visibleWidth(spanVisibleText(span));
|
|
142
|
+
if (visible + visibleLen >= clamped) {
|
|
143
|
+
const offset = clamped - visible;
|
|
144
|
+
if (span.kind === "text") {
|
|
145
|
+
return logical + offset;
|
|
146
|
+
}
|
|
147
|
+
const ratio = visibleLen > 0 ? offset / visibleLen : 0;
|
|
148
|
+
return logical + Math.round(logicalLen * ratio);
|
|
157
149
|
}
|
|
158
|
-
|
|
150
|
+
logical += logicalLen;
|
|
151
|
+
visible += visibleLen;
|
|
152
|
+
}
|
|
153
|
+
return line.length;
|
|
159
154
|
}
|
|
160
|
-
//# sourceMappingURL=chat-mention-render.js.map
|
|
155
|
+
//# sourceMappingURL=chat-mention-render.js.map
|
|
@@ -7,12 +7,15 @@ export declare function extractAtPrefix(textBeforeCursor: string): string | null
|
|
|
7
7
|
/** KubbiSec: `@skill` may include a space and partial name (not only the last @ token). */
|
|
8
8
|
export declare function extractSkillMentionPrefix(textBeforeCursor: string): string | null;
|
|
9
9
|
export declare function parseSkillMentionPrefix(atPrefix: string | null): {
|
|
10
|
-
|
|
10
|
+
query: string;
|
|
11
11
|
} | null;
|
|
12
12
|
export declare function parsePlanMentionPrefix(atPrefix: string | null): {
|
|
13
|
-
|
|
13
|
+
query: string;
|
|
14
14
|
} | null;
|
|
15
|
-
export declare function filterSkillSuggestions(
|
|
15
|
+
export declare function filterSkillSuggestions(
|
|
16
|
+
skills: KubbisecSkillEntry[],
|
|
17
|
+
query: string,
|
|
18
|
+
): AutocompleteItem[];
|
|
16
19
|
/** Pi expands `/skill:name` — map `@skill name` before submit. */
|
|
17
20
|
export declare function transformAtSkillMentions(text: string): string;
|
|
18
21
|
/** Legacy: map `@plan` / `@planejar` to `/mode:plan` (prefer session state + visible @plan). */
|
|
@@ -20,9 +23,15 @@ export declare function transformAtPlanMentions(text: string): string;
|
|
|
20
23
|
/** Apply @skill → /skill:name only. @plan stays visible; plan mode is set via session state. */
|
|
21
24
|
export declare function transformChatMentions(text: string): string;
|
|
22
25
|
export declare function messageActivatesPlanMode(text: string): boolean;
|
|
23
|
-
export declare function applySkillMentionCompletion(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
export declare function applySkillMentionCompletion(
|
|
27
|
+
lines: string[],
|
|
28
|
+
cursorLine: number,
|
|
29
|
+
cursorCol: number,
|
|
30
|
+
item: AutocompleteItem,
|
|
31
|
+
prefix: string,
|
|
32
|
+
): {
|
|
33
|
+
lines: string[];
|
|
34
|
+
cursorLine: number;
|
|
35
|
+
cursorCol: number;
|
|
27
36
|
};
|
|
28
|
-
//# sourceMappingURL=chat-mentions.d.ts.map
|
|
37
|
+
//# sourceMappingURL=chat-mentions.d.ts.map
|