@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
|
@@ -4,360 +4,378 @@
|
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import * as fs from "node:fs";
|
|
6
6
|
import { getKubbisecConfigPath } from "@kubbisec/home";
|
|
7
|
-
import { shouldClarify
|
|
7
|
+
import { shouldClarify } from "../clarify/clarify-gate.js";
|
|
8
8
|
import { setClarifyGateActive } from "../clarify/clarify-gate-state.js";
|
|
9
9
|
import { renderClarifySelectPanel } from "../clarify/clarify-select-panel.js";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
getClarifyUiSnapshot,
|
|
12
|
+
resetClarifyUiSnapshot,
|
|
13
|
+
setClarifyUiChangeListener,
|
|
14
|
+
setClarifyUiSnapshot,
|
|
15
|
+
} from "../clarify/clarify-ui-state.js";
|
|
11
16
|
import { parseClarifyAnswer } from "../clarify/parse-clarify-answer.js";
|
|
12
17
|
import { inferScenarioFromMessage } from "../clarify/question-format.js";
|
|
13
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
applyParsedUserAnswerIfPending,
|
|
20
|
+
executeQuestionnaireTool,
|
|
21
|
+
questionnaireToolParametersSchema,
|
|
22
|
+
} from "../clarify/questionnaire-tool.js";
|
|
14
23
|
import { discoverScopeHints } from "../clarify/scope-discovery.js";
|
|
15
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
buildClarifyProgressLabel,
|
|
26
|
+
finalizeQuestionnaireAtRoundLimit,
|
|
27
|
+
hasMinimumScopeForScenario,
|
|
28
|
+
readDefaultProjectId,
|
|
29
|
+
readSessionQuestionnaire,
|
|
30
|
+
shouldAcceptClarifyAnswer,
|
|
31
|
+
writeSessionQuestionnaire,
|
|
32
|
+
} from "../clarify/session-questionnaire.js";
|
|
16
33
|
import { resolveResourceBudget } from "../config/resource-budget.js";
|
|
17
34
|
import { getSessionWorkflowMode } from "../workflow/session-workflow-mode.js";
|
|
18
35
|
export const CLARIFY_MUTATION_TOOLS = new Set([
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
36
|
+
"edit",
|
|
37
|
+
"write",
|
|
38
|
+
"bash",
|
|
39
|
+
"delete",
|
|
40
|
+
"patch",
|
|
41
|
+
"apply_patch",
|
|
42
|
+
"set_pipeline_yaml",
|
|
26
43
|
]);
|
|
27
44
|
export const CLARIFY_READ_ONLY_TOOLS = new Set([
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
"read",
|
|
46
|
+
"grep",
|
|
47
|
+
"find",
|
|
48
|
+
"ls",
|
|
49
|
+
"glob",
|
|
50
|
+
"questionnaire",
|
|
51
|
+
"aspm_docs",
|
|
52
|
+
"naus_pipeline_docs",
|
|
53
|
+
"list_findings",
|
|
37
54
|
]);
|
|
38
|
-
export const CLARIFY_TOOL_BLOCK_REASON =
|
|
55
|
+
export const CLARIFY_TOOL_BLOCK_REASON =
|
|
56
|
+
"Complete o questionário de escopo (use o painel acima ou escreva a resposta) antes de editar ficheiros.";
|
|
39
57
|
export function isClarifyMutationTool(toolName) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return CLARIFY_MUTATION_TOOLS.has(toolName);
|
|
58
|
+
if (CLARIFY_READ_ONLY_TOOLS.has(toolName)) return false;
|
|
59
|
+
return CLARIFY_MUTATION_TOOLS.has(toolName);
|
|
43
60
|
}
|
|
44
61
|
export function shouldBlockClarifyTool(toolName, gateActive, questionnaire) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (!isClarifyMutationTool(toolName))
|
|
50
|
-
return false;
|
|
51
|
-
return true;
|
|
62
|
+
if (!gateActive) return false;
|
|
63
|
+
if (!questionnaire || questionnaire.status === "ready") return false;
|
|
64
|
+
if (!isClarifyMutationTool(toolName)) return false;
|
|
65
|
+
return true;
|
|
52
66
|
}
|
|
53
67
|
function readDefaultProjectConfigured() {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
68
|
+
if (readDefaultProjectId()) return true;
|
|
69
|
+
try {
|
|
70
|
+
const raw = fs.readFileSync(getKubbisecConfigPath(), "utf8");
|
|
71
|
+
const parsed = JSON.parse(raw);
|
|
72
|
+
return Boolean(parsed.defaultProject?.trim());
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
64
76
|
}
|
|
65
77
|
export function detectChatMode(prompt) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
if (getSessionWorkflowMode() === "plan") {
|
|
79
|
+
return "plan";
|
|
80
|
+
}
|
|
81
|
+
const trimmed = prompt.trim();
|
|
82
|
+
if (
|
|
83
|
+
trimmed.startsWith("/mode:plan") ||
|
|
84
|
+
/@plan\b/i.test(trimmed) ||
|
|
85
|
+
/@planejar\b/i.test(trimmed)
|
|
86
|
+
) {
|
|
87
|
+
return "plan";
|
|
88
|
+
}
|
|
89
|
+
const envMode = process.env.KUBBISEC_CHAT_MODE?.trim().toLowerCase();
|
|
90
|
+
if (envMode === "plan") return "plan";
|
|
91
|
+
return "default";
|
|
79
92
|
}
|
|
80
93
|
function resolveSurface() {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
const surface = process.env.KUBBISEC_CLARIFY_SURFACE?.trim().toLowerCase();
|
|
95
|
+
if (surface === "fix" || surface === "watch" || surface === "task-consumer") {
|
|
96
|
+
return surface;
|
|
97
|
+
}
|
|
98
|
+
if (process.env.KUBBISEC_FIX_MODE === "1" || process.env.KUBBISEC_WATCH_MODE === "1") {
|
|
99
|
+
return process.env.KUBBISEC_WATCH_MODE === "1" ? "watch" : "fix";
|
|
100
|
+
}
|
|
101
|
+
return "chat";
|
|
89
102
|
}
|
|
90
103
|
function buildGateInput(prompt, questionnaire) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
const msg = prompt.trim();
|
|
105
|
+
const budget = resolveResourceBudget();
|
|
106
|
+
const scenario = questionnaire.scenario ?? inferScenarioFromMessage(msg);
|
|
107
|
+
return {
|
|
108
|
+
surface: resolveSurface(),
|
|
109
|
+
userMessage: msg,
|
|
110
|
+
hasProjectId: readDefaultProjectConfigured() || questionnaire.fields.projectIds.length > 0,
|
|
111
|
+
hasVulnerabilityId: /\b(cve-|vuln|finding)/i.test(msg),
|
|
112
|
+
hasSeverityFilter:
|
|
113
|
+
Boolean(questionnaire.fields.severityMin) || /\b(severity|critical|high)\b/i.test(msg),
|
|
114
|
+
mode: detectChatMode(msg),
|
|
115
|
+
scenario,
|
|
116
|
+
questionnaireStatus: questionnaire.status,
|
|
117
|
+
fields: questionnaire.fields,
|
|
118
|
+
historyCount: questionnaire.history.length,
|
|
119
|
+
clarifyMaxRounds: budget.clarifyMaxRounds,
|
|
120
|
+
};
|
|
107
121
|
}
|
|
108
122
|
export function buildClarifyContextMessage(questionnaire) {
|
|
109
|
-
|
|
110
|
-
|
|
123
|
+
const panelReady = questionnaire.awaitingUserAnswer && questionnaire.pending?.questionMarkdown;
|
|
124
|
+
return `[SCOPE GATE — internal only, never repeat to user]
|
|
111
125
|
${panelReady ? "Questionnaire panel is visible — do NOT ask user to look at the panel." : "Scope still missing — questionnaire auto-ask may run."}
|
|
112
126
|
Read-only until scope ready. User-facing replies: max 2 sentences; no chain-of-thought.
|
|
113
127
|
${questionnaire.awaitingUserAnswer ? "Wait for panel answer or free text." : "Use questionnaire record if user already gave scope in prose."}`;
|
|
114
128
|
}
|
|
115
129
|
function extractQuestionText(markdown) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return markdown.split("\n")[0]?.trim() ?? "";
|
|
130
|
+
for (const line of markdown.split("\n")) {
|
|
131
|
+
const trimmed = line.trim();
|
|
132
|
+
if (trimmed && !/^[A-D]\)/.test(trimmed)) return trimmed;
|
|
133
|
+
}
|
|
134
|
+
return markdown.split("\n")[0]?.trim() ?? "";
|
|
122
135
|
}
|
|
123
136
|
export function syncClarifyUi(questionnaire) {
|
|
124
|
-
|
|
125
|
-
setClarifyUiSnapshot({
|
|
126
|
-
phase: "ready",
|
|
127
|
-
progressLabel: null,
|
|
128
|
-
questionMarkdown: null,
|
|
129
|
-
questionText: null,
|
|
130
|
-
optionLabels: [],
|
|
131
|
-
selected: [],
|
|
132
|
-
focusedIndex: 0,
|
|
133
|
-
});
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
if (!questionnaire.awaitingUserAnswer || !questionnaire.pending?.questionMarkdown) {
|
|
137
|
-
setClarifyUiSnapshot({
|
|
138
|
-
phase: "idle",
|
|
139
|
-
progressLabel: null,
|
|
140
|
-
questionMarkdown: null,
|
|
141
|
-
questionText: null,
|
|
142
|
-
optionLabels: [],
|
|
143
|
-
selected: [],
|
|
144
|
-
focusedIndex: 0,
|
|
145
|
-
});
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
const pending = questionnaire.pending;
|
|
137
|
+
if (questionnaire.status === "ready") {
|
|
149
138
|
setClarifyUiSnapshot({
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
focusedIndex: 0,
|
|
139
|
+
phase: "ready",
|
|
140
|
+
progressLabel: null,
|
|
141
|
+
questionMarkdown: null,
|
|
142
|
+
questionText: null,
|
|
143
|
+
optionLabels: [],
|
|
144
|
+
selected: [],
|
|
145
|
+
focusedIndex: 0,
|
|
158
146
|
});
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (!questionnaire.awaitingUserAnswer || !questionnaire.pending?.questionMarkdown) {
|
|
150
|
+
setClarifyUiSnapshot({
|
|
151
|
+
phase: "idle",
|
|
152
|
+
progressLabel: null,
|
|
153
|
+
questionMarkdown: null,
|
|
154
|
+
questionText: null,
|
|
155
|
+
optionLabels: [],
|
|
156
|
+
selected: [],
|
|
157
|
+
focusedIndex: 0,
|
|
158
|
+
});
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const pending = questionnaire.pending;
|
|
162
|
+
setClarifyUiSnapshot({
|
|
163
|
+
phase: "asking",
|
|
164
|
+
progressLabel: buildClarifyProgressLabel(questionnaire),
|
|
165
|
+
questionMarkdown: pending.questionMarkdown,
|
|
166
|
+
questionText: extractQuestionText(pending.questionMarkdown),
|
|
167
|
+
optionLabels: pending.optionLabels,
|
|
168
|
+
selectionMode: pending.selectionMode ?? "single",
|
|
169
|
+
selected: [],
|
|
170
|
+
focusedIndex: 0,
|
|
171
|
+
});
|
|
159
172
|
}
|
|
160
173
|
function applyDiscoveredScope(questionnaire, prompt, cwd) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
174
|
+
const discovered = discoverScopeHints(cwd, prompt);
|
|
175
|
+
if (!discovered.fields || Object.keys(discovered.fields).length === 0) {
|
|
176
|
+
return questionnaire;
|
|
177
|
+
}
|
|
178
|
+
const result = executeQuestionnaireTool(questionnaire, {
|
|
179
|
+
action: "record",
|
|
180
|
+
scenario: discovered.scenario,
|
|
181
|
+
fields: discovered.fields,
|
|
182
|
+
});
|
|
183
|
+
return result.questionnaire;
|
|
171
184
|
}
|
|
172
185
|
export function autoAskNextQuestion(questionnaire, prompt) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
return result.questionnaire;
|
|
186
|
+
if (questionnaire.awaitingUserAnswer || questionnaire.status === "ready") {
|
|
187
|
+
return questionnaire;
|
|
188
|
+
}
|
|
189
|
+
const scenario = questionnaire.scenario ?? inferScenarioFromMessage(prompt);
|
|
190
|
+
const result = executeQuestionnaireTool(questionnaire, {
|
|
191
|
+
action: "ask",
|
|
192
|
+
scenario,
|
|
193
|
+
});
|
|
194
|
+
if (!result.ok) return questionnaire;
|
|
195
|
+
return result.questionnaire;
|
|
184
196
|
}
|
|
185
197
|
function maybeMarkReady(questionnaire) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return questionnaire;
|
|
198
|
+
const scenario = questionnaire.scenario ?? "remediation";
|
|
199
|
+
if (
|
|
200
|
+
questionnaire.status === "collecting" &&
|
|
201
|
+
!questionnaire.awaitingUserAnswer &&
|
|
202
|
+
hasMinimumScopeForScenario(scenario, questionnaire.fields)
|
|
203
|
+
) {
|
|
204
|
+
return { ...questionnaire, status: "ready", pending: null };
|
|
205
|
+
}
|
|
206
|
+
return questionnaire;
|
|
193
207
|
}
|
|
194
208
|
export function updateClarifyStatus(ctx, questionnaire) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if (questionnaire.status === "ready") {
|
|
198
|
-
ctx.ui.setStatus("kubbisec-clarify", undefined);
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
if (questionnaire.awaitingUserAnswer) {
|
|
202
|
-
ctx.ui.setStatus("kubbisec-clarify", ctx.ui.theme.fg("warning", `questionário · ${questionnaire.status}`));
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
209
|
+
if (!ctx.hasUI) return;
|
|
210
|
+
if (questionnaire.status === "ready") {
|
|
205
211
|
ctx.ui.setStatus("kubbisec-clarify", undefined);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (questionnaire.awaitingUserAnswer) {
|
|
215
|
+
ctx.ui.setStatus(
|
|
216
|
+
"kubbisec-clarify",
|
|
217
|
+
ctx.ui.theme.fg("warning", `questionário · ${questionnaire.status}`),
|
|
218
|
+
);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
ctx.ui.setStatus("kubbisec-clarify", undefined);
|
|
206
222
|
}
|
|
207
223
|
export function processClarifyPrompt(questionnaire, prompt, cwd, clarifyMaxRounds) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
224
|
+
let next = questionnaire;
|
|
225
|
+
if (next.status === "collecting" && prompt.trim()) {
|
|
226
|
+
const selectionMode = next.pending?.selectionMode ?? "single";
|
|
227
|
+
const parsed = parseClarifyAnswer(prompt, selectionMode);
|
|
228
|
+
if (shouldAcceptClarifyAnswer(next, parsed)) {
|
|
229
|
+
next = applyParsedUserAnswerIfPending(next, parsed);
|
|
230
|
+
next = finalizeQuestionnaireAtRoundLimit(next, clarifyMaxRounds);
|
|
231
|
+
next = maybeMarkReady(next);
|
|
217
232
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
233
|
+
}
|
|
234
|
+
next = applyDiscoveredScope(next, prompt, cwd);
|
|
235
|
+
next = maybeMarkReady(next);
|
|
236
|
+
return next;
|
|
221
237
|
}
|
|
222
238
|
export default function kubbisecClarify(api) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
console.warn("[kubbisec-clarify] Failed to persist session questionnaire:", error);
|
|
236
|
-
}
|
|
237
|
-
updateClarifyStatus(ctx, next);
|
|
238
|
-
syncClarifyUi(next);
|
|
239
|
+
const sessionId = randomUUID();
|
|
240
|
+
let questionnaire = readSessionQuestionnaire(process.cwd(), sessionId);
|
|
241
|
+
let gateActive = false;
|
|
242
|
+
let clarifyWidgetRegistered = false;
|
|
243
|
+
let lastUserMessage = "";
|
|
244
|
+
let sessionCwd = process.cwd();
|
|
245
|
+
function persist(ctx, next) {
|
|
246
|
+
questionnaire = next;
|
|
247
|
+
try {
|
|
248
|
+
writeSessionQuestionnaire(ctx.cwd, next);
|
|
249
|
+
} catch (error) {
|
|
250
|
+
console.warn("[kubbisec-clarify] Failed to persist session questionnaire:", error);
|
|
239
251
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
252
|
+
updateClarifyStatus(ctx, next);
|
|
253
|
+
syncClarifyUi(next);
|
|
254
|
+
}
|
|
255
|
+
function ensureClarifyWidget(ctx) {
|
|
256
|
+
if (!ctx.hasUI || clarifyWidgetRegistered) return;
|
|
257
|
+
clarifyWidgetRegistered = true;
|
|
258
|
+
ctx.ui.setWidget(
|
|
259
|
+
"kubbisec-clarify-panel",
|
|
260
|
+
(tui, theme) => {
|
|
261
|
+
setClarifyUiChangeListener(() => {
|
|
262
|
+
tui.requestRender();
|
|
263
|
+
});
|
|
264
|
+
return {
|
|
265
|
+
dispose() {
|
|
266
|
+
setClarifyUiChangeListener(undefined);
|
|
267
|
+
},
|
|
268
|
+
invalidate() {
|
|
269
|
+
tui.requestRender();
|
|
270
|
+
},
|
|
271
|
+
render(w) {
|
|
272
|
+
return renderClarifySelectPanel(w, getClarifyUiSnapshot(), theme);
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
},
|
|
276
|
+
{ placement: "aboveEditor" },
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
api.registerTool({
|
|
280
|
+
name: "questionnaire",
|
|
281
|
+
label: "Scope questionnaire",
|
|
282
|
+
description:
|
|
283
|
+
"Format and track contextual scope questions (ask/record/status/complete). KubbiSec renders options in the panel above the editor.",
|
|
284
|
+
parameters: questionnaireToolParametersSchema(),
|
|
285
|
+
async execute(_toolCallId, params) {
|
|
286
|
+
const input = params;
|
|
287
|
+
const result = executeQuestionnaireTool(questionnaire, input, lastUserMessage);
|
|
288
|
+
questionnaire = result.questionnaire;
|
|
289
|
+
try {
|
|
290
|
+
writeSessionQuestionnaire(sessionCwd, questionnaire);
|
|
291
|
+
} catch {
|
|
292
|
+
// best effort
|
|
293
|
+
}
|
|
294
|
+
syncClarifyUi(questionnaire);
|
|
295
|
+
return {
|
|
296
|
+
content: [{ type: "text", text: result.message }],
|
|
297
|
+
details: { ok: result.ok, status: result.status, action: result.action },
|
|
298
|
+
};
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
api.on("session_start", async (_event, ctx) => {
|
|
302
|
+
sessionCwd = ctx.cwd;
|
|
303
|
+
questionnaire = readSessionQuestionnaire(ctx.cwd, sessionId);
|
|
304
|
+
gateActive = false;
|
|
305
|
+
setClarifyGateActive(false);
|
|
306
|
+
lastUserMessage = "";
|
|
307
|
+
resetClarifyUiSnapshot();
|
|
308
|
+
ensureClarifyWidget(ctx);
|
|
309
|
+
updateClarifyStatus(ctx, questionnaire);
|
|
310
|
+
syncClarifyUi(questionnaire);
|
|
311
|
+
});
|
|
312
|
+
api.on("session_shutdown", async () => {
|
|
313
|
+
resetClarifyUiSnapshot();
|
|
314
|
+
setClarifyGateActive(false);
|
|
315
|
+
});
|
|
316
|
+
api.on("before_agent_start", async (event, ctx) => {
|
|
317
|
+
const { prompt } = event;
|
|
318
|
+
lastUserMessage = prompt;
|
|
319
|
+
const surface = resolveSurface();
|
|
320
|
+
ensureClarifyWidget(ctx);
|
|
321
|
+
if (surface !== "chat") {
|
|
322
|
+
gateActive = false;
|
|
323
|
+
setClarifyGateActive(false);
|
|
324
|
+
resetClarifyUiSnapshot();
|
|
325
|
+
return undefined;
|
|
260
326
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
return {
|
|
278
|
-
content: [{ type: "text", text: result.message }],
|
|
279
|
-
details: { ok: result.ok, status: result.status, action: result.action },
|
|
280
|
-
};
|
|
281
|
-
},
|
|
282
|
-
});
|
|
283
|
-
api.on("session_start", async (_event, ctx) => {
|
|
284
|
-
sessionCwd = ctx.cwd;
|
|
285
|
-
questionnaire = readSessionQuestionnaire(ctx.cwd, sessionId);
|
|
286
|
-
gateActive = false;
|
|
287
|
-
setClarifyGateActive(false);
|
|
288
|
-
lastUserMessage = "";
|
|
289
|
-
resetClarifyUiSnapshot();
|
|
290
|
-
ensureClarifyWidget(ctx);
|
|
291
|
-
updateClarifyStatus(ctx, questionnaire);
|
|
292
|
-
syncClarifyUi(questionnaire);
|
|
293
|
-
});
|
|
294
|
-
api.on("session_shutdown", async () => {
|
|
295
|
-
resetClarifyUiSnapshot();
|
|
296
|
-
setClarifyGateActive(false);
|
|
297
|
-
});
|
|
298
|
-
api.on("before_agent_start", async (event, ctx) => {
|
|
299
|
-
const { prompt } = event;
|
|
300
|
-
lastUserMessage = prompt;
|
|
301
|
-
const surface = resolveSurface();
|
|
302
|
-
ensureClarifyWidget(ctx);
|
|
303
|
-
if (surface !== "chat") {
|
|
304
|
-
gateActive = false;
|
|
305
|
-
setClarifyGateActive(false);
|
|
306
|
-
resetClarifyUiSnapshot();
|
|
307
|
-
return undefined;
|
|
308
|
-
}
|
|
309
|
-
const budget = resolveResourceBudget();
|
|
310
|
-
let next = readSessionQuestionnaire(ctx.cwd, questionnaire.sessionId);
|
|
311
|
-
next = processClarifyPrompt(next, prompt, ctx.cwd, budget.clarifyMaxRounds);
|
|
312
|
-
const gateInput = buildGateInput(prompt, next);
|
|
313
|
-
gateActive = shouldClarify(gateInput);
|
|
314
|
-
setClarifyGateActive(gateActive);
|
|
315
|
-
if (!gateActive) {
|
|
316
|
-
next = maybeMarkReady(next);
|
|
317
|
-
persist(ctx, next);
|
|
318
|
-
return undefined;
|
|
319
|
-
}
|
|
320
|
-
if (next.status === "collecting" && !next.awaitingUserAnswer) {
|
|
321
|
-
next = autoAskNextQuestion(next, prompt);
|
|
322
|
-
next = maybeMarkReady(next);
|
|
323
|
-
persist(ctx, next);
|
|
324
|
-
if (next.awaitingUserAnswer) {
|
|
325
|
-
return {
|
|
326
|
-
message: {
|
|
327
|
-
customType: "kubbisec-clarify",
|
|
328
|
-
content: buildClarifyContextMessage(next),
|
|
329
|
-
display: false,
|
|
330
|
-
},
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
return {
|
|
334
|
-
message: {
|
|
335
|
-
customType: "kubbisec-clarify",
|
|
336
|
-
content: buildClarifyContextMessage(next),
|
|
337
|
-
display: false,
|
|
338
|
-
},
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
persist(ctx, next);
|
|
342
|
-
return undefined;
|
|
343
|
-
});
|
|
344
|
-
api.on("tool_call", async (event, ctx) => {
|
|
345
|
-
const surface = resolveSurface();
|
|
346
|
-
if (surface !== "chat") {
|
|
347
|
-
return undefined;
|
|
348
|
-
}
|
|
349
|
-
questionnaire = readSessionQuestionnaire(ctx.cwd, questionnaire.sessionId);
|
|
350
|
-
const { toolName } = event;
|
|
351
|
-
if (toolName === "questionnaire") {
|
|
352
|
-
return undefined;
|
|
353
|
-
}
|
|
354
|
-
if (!shouldBlockClarifyTool(toolName, gateActive, questionnaire)) {
|
|
355
|
-
return undefined;
|
|
356
|
-
}
|
|
327
|
+
const budget = resolveResourceBudget();
|
|
328
|
+
let next = readSessionQuestionnaire(ctx.cwd, questionnaire.sessionId);
|
|
329
|
+
next = processClarifyPrompt(next, prompt, ctx.cwd, budget.clarifyMaxRounds);
|
|
330
|
+
const gateInput = buildGateInput(prompt, next);
|
|
331
|
+
gateActive = shouldClarify(gateInput);
|
|
332
|
+
setClarifyGateActive(gateActive);
|
|
333
|
+
if (!gateActive) {
|
|
334
|
+
next = maybeMarkReady(next);
|
|
335
|
+
persist(ctx, next);
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
338
|
+
if (next.status === "collecting" && !next.awaitingUserAnswer) {
|
|
339
|
+
next = autoAskNextQuestion(next, prompt);
|
|
340
|
+
next = maybeMarkReady(next);
|
|
341
|
+
persist(ctx, next);
|
|
342
|
+
if (next.awaitingUserAnswer) {
|
|
357
343
|
return {
|
|
358
|
-
|
|
359
|
-
|
|
344
|
+
message: {
|
|
345
|
+
customType: "kubbisec-clarify",
|
|
346
|
+
content: buildClarifyContextMessage(next),
|
|
347
|
+
display: false,
|
|
348
|
+
},
|
|
360
349
|
};
|
|
361
|
-
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
message: {
|
|
353
|
+
customType: "kubbisec-clarify",
|
|
354
|
+
content: buildClarifyContextMessage(next),
|
|
355
|
+
display: false,
|
|
356
|
+
},
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
persist(ctx, next);
|
|
360
|
+
return undefined;
|
|
361
|
+
});
|
|
362
|
+
api.on("tool_call", async (event, ctx) => {
|
|
363
|
+
const surface = resolveSurface();
|
|
364
|
+
if (surface !== "chat") {
|
|
365
|
+
return undefined;
|
|
366
|
+
}
|
|
367
|
+
questionnaire = readSessionQuestionnaire(ctx.cwd, questionnaire.sessionId);
|
|
368
|
+
const { toolName } = event;
|
|
369
|
+
if (toolName === "questionnaire") {
|
|
370
|
+
return undefined;
|
|
371
|
+
}
|
|
372
|
+
if (!shouldBlockClarifyTool(toolName, gateActive, questionnaire)) {
|
|
373
|
+
return undefined;
|
|
374
|
+
}
|
|
375
|
+
return {
|
|
376
|
+
block: true,
|
|
377
|
+
reason: CLARIFY_TOOL_BLOCK_REASON,
|
|
378
|
+
};
|
|
379
|
+
});
|
|
362
380
|
}
|
|
363
|
-
//# sourceMappingURL=kubbisec-clarify.extension.js.map
|
|
381
|
+
//# sourceMappingURL=kubbisec-clarify.extension.js.map
|