@cybedefend/vibedefend 1.4.4 → 1.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -3
- package/dist/clients/claude-code.js +27 -0
- package/dist/clients/claude-code.js.map +1 -1
- package/dist/clients/codex.js +80 -8
- package/dist/clients/codex.js.map +1 -1
- package/dist/clients/cursor-guards-rules.js +26 -1
- package/dist/clients/cursor-guards-rules.js.map +1 -1
- package/dist/clients/cursor.js +16 -0
- package/dist/clients/cursor.js.map +1 -1
- package/dist/clients/unwire.js +57 -0
- package/dist/clients/unwire.js.map +1 -0
- package/dist/clients/vscode.js +29 -1
- package/dist/clients/vscode.js.map +1 -1
- package/dist/clients/windsurf.js +24 -1
- package/dist/clients/windsurf.js.map +1 -1
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -1
- package/dist/doctor.js +3 -1
- package/dist/doctor.js.map +1 -1
- package/dist/global-cli.js +138 -0
- package/dist/global-cli.js.map +1 -0
- package/dist/hook-runner.js +154 -45
- package/dist/hooks/install.js +1 -0
- package/dist/hooks/install.js.map +1 -1
- package/dist/hooks/runtime/pre-compact.js +9 -2
- package/dist/hooks/runtime/pre-compact.js.map +1 -1
- package/dist/hooks/runtime/proposal-mode.js +75 -0
- package/dist/hooks/runtime/proposal-mode.js.map +1 -0
- package/dist/hooks/runtime/session-review.js +40 -20
- package/dist/hooks/runtime/session-review.js.map +1 -1
- package/dist/hooks/runtime/session-start.js +7 -1
- package/dist/hooks/runtime/session-start.js.map +1 -1
- package/dist/hooks/runtime/shell-writes.js +3 -2
- package/dist/hooks/runtime/shell-writes.js.map +1 -1
- package/dist/hooks/runtime/user-prompt-submit.js +12 -2
- package/dist/hooks/runtime/user-prompt-submit.js.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/install.js +23 -1
- package/dist/install.js.map +1 -1
- package/dist/prompts.js +18 -3
- package/dist/prompts.js.map +1 -1
- package/dist/self-update.js +5 -0
- package/dist/self-update.js.map +1 -1
- package/dist/uninstall.js +166 -0
- package/dist/uninstall.js.map +1 -0
- package/package.json +3 -3
package/dist/hook-runner.js
CHANGED
|
@@ -39,22 +39,31 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
39
39
|
mod
|
|
40
40
|
));
|
|
41
41
|
|
|
42
|
-
// node_modules/.pnpm/shell-quote@1.
|
|
42
|
+
// node_modules/.pnpm/shell-quote@1.12.0/node_modules/shell-quote/quote.js
|
|
43
43
|
var require_quote = __commonJS({
|
|
44
|
-
"node_modules/.pnpm/shell-quote@1.
|
|
44
|
+
"node_modules/.pnpm/shell-quote@1.12.0/node_modules/shell-quote/quote.js"(exports, module) {
|
|
45
45
|
"use strict";
|
|
46
46
|
var OPS = (
|
|
47
47
|
/** @type {const} */
|
|
48
48
|
[
|
|
49
49
|
"||",
|
|
50
50
|
"&&",
|
|
51
|
+
";;&",
|
|
51
52
|
";;",
|
|
53
|
+
";&",
|
|
52
54
|
"|&",
|
|
53
55
|
"<(",
|
|
56
|
+
">(",
|
|
54
57
|
"<<<",
|
|
58
|
+
"<<-",
|
|
59
|
+
"<<",
|
|
55
60
|
">>",
|
|
56
61
|
">&",
|
|
62
|
+
">|",
|
|
63
|
+
"&>>",
|
|
64
|
+
"&>",
|
|
57
65
|
"<&",
|
|
66
|
+
"<>",
|
|
58
67
|
"&",
|
|
59
68
|
";",
|
|
60
69
|
"(",
|
|
@@ -65,9 +74,13 @@ var require_quote = __commonJS({
|
|
|
65
74
|
]
|
|
66
75
|
);
|
|
67
76
|
var LINE_TERMINATORS = /[\n\r\u2028\u2029]/;
|
|
68
|
-
var GLOB_SHELL_SPECIAL = /[\s#!"$&'()
|
|
77
|
+
var GLOB_SHELL_SPECIAL = /[\s#!"$&'():;<=>@\\^`|~]/g;
|
|
69
78
|
module.exports = function quote(xs) {
|
|
79
|
+
var sawComment = false;
|
|
70
80
|
return xs.map(function(s) {
|
|
81
|
+
if (sawComment && typeof s === "string" && LINE_TERMINATORS.test(s)) {
|
|
82
|
+
throw new TypeError("a token after a `comment` must not contain line terminators");
|
|
83
|
+
}
|
|
71
84
|
if (s === "") {
|
|
72
85
|
return (
|
|
73
86
|
/** @type {const} */
|
|
@@ -82,6 +95,12 @@ var require_quote = __commonJS({
|
|
|
82
95
|
if (LINE_TERMINATORS.test(s.pattern)) {
|
|
83
96
|
throw new TypeError("glob `pattern` must not contain line terminators");
|
|
84
97
|
}
|
|
98
|
+
if (s.pattern === "") {
|
|
99
|
+
return (
|
|
100
|
+
/** @type {const} */
|
|
101
|
+
"''"
|
|
102
|
+
);
|
|
103
|
+
}
|
|
85
104
|
return s.pattern.replace(GLOB_SHELL_SPECIAL, "\\$&");
|
|
86
105
|
}
|
|
87
106
|
if ("op" in s && typeof s.op === "string") {
|
|
@@ -94,15 +113,19 @@ var require_quote = __commonJS({
|
|
|
94
113
|
if (LINE_TERMINATORS.test(s.comment)) {
|
|
95
114
|
throw new TypeError("`comment` must not contain line terminators");
|
|
96
115
|
}
|
|
116
|
+
sawComment = true;
|
|
97
117
|
return "#" + s.comment;
|
|
98
118
|
}
|
|
99
119
|
throw new TypeError("unrecognized object token shape");
|
|
100
120
|
}
|
|
121
|
+
if (/'/.test(s) && /!/.test(s)) {
|
|
122
|
+
return "'" + s.replace(/'/g, `'"'"'`) + "'";
|
|
123
|
+
}
|
|
101
124
|
if (/["\s\\]/.test(s) && !/'/.test(s)) {
|
|
102
|
-
return "'" + s
|
|
125
|
+
return "'" + s + "'";
|
|
103
126
|
}
|
|
104
127
|
if (/["'\s]/.test(s)) {
|
|
105
|
-
return '"' + s.replace(/(["
|
|
128
|
+
return '"' + s.replace(/(["\\$`])/g, "\\$1") + '"';
|
|
106
129
|
}
|
|
107
130
|
return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}~])/g, "$1\\$2");
|
|
108
131
|
}).join(" ");
|
|
@@ -110,23 +133,31 @@ var require_quote = __commonJS({
|
|
|
110
133
|
}
|
|
111
134
|
});
|
|
112
135
|
|
|
113
|
-
// node_modules/.pnpm/shell-quote@1.
|
|
136
|
+
// node_modules/.pnpm/shell-quote@1.12.0/node_modules/shell-quote/parse.js
|
|
114
137
|
var require_parse = __commonJS({
|
|
115
|
-
"node_modules/.pnpm/shell-quote@1.
|
|
138
|
+
"node_modules/.pnpm/shell-quote@1.12.0/node_modules/shell-quote/parse.js"(exports, module) {
|
|
116
139
|
"use strict";
|
|
117
140
|
var CONTROL = (
|
|
118
141
|
/** @type {const} */
|
|
119
142
|
"(?:" + /** @type {const} */
|
|
120
143
|
[
|
|
121
144
|
"\\|\\|",
|
|
122
|
-
"
|
|
123
|
-
|
|
124
|
-
"
|
|
145
|
+
"\\&(?:\\&|>>?)",
|
|
146
|
+
// `&&`, `&>`, and `&>>`
|
|
147
|
+
";;\\&?",
|
|
148
|
+
// `;;` and `;;&`
|
|
149
|
+
"[;|]\\&",
|
|
150
|
+
// `;&` and `|&`
|
|
125
151
|
"\\<\\(",
|
|
126
152
|
"\\<\\<\\<",
|
|
153
|
+
"\\<\\<-",
|
|
154
|
+
"\\<\\<(?!\\()",
|
|
155
|
+
// `<<(` stays `<` and `<(`, as zsh reads it; other shells reject it
|
|
127
156
|
">>",
|
|
128
|
-
"
|
|
129
|
-
|
|
157
|
+
">[&|(]",
|
|
158
|
+
// `>&`, `>|`, and `>(`
|
|
159
|
+
"<[&>]",
|
|
160
|
+
// `<&` and `<>`
|
|
130
161
|
"[&;()|<>]"
|
|
131
162
|
].join(
|
|
132
163
|
/** @type {const} */
|
|
@@ -143,10 +174,11 @@ var require_parse = __commonJS({
|
|
|
143
174
|
/** @type {const} */
|
|
144
175
|
"'([^']*?)'"
|
|
145
176
|
);
|
|
146
|
-
var
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
177
|
+
var ANSI_C_BODY = "(?:\\\\[\\s\\S]|[^\\\\'])*?";
|
|
178
|
+
var ANSI_C_QUOTE = "\\$'" + ANSI_C_BODY + "'";
|
|
179
|
+
var ansiCAt = new RegExp("\\$'" + ANSI_C_BODY + "(?:(')|\\\\?$)", "g");
|
|
180
|
+
var ANSI_C_LETTERS = "abeEfnrtv";
|
|
181
|
+
var ANSI_C_CHARS = "\x07\b\x1B\x1B\f\n\r \v";
|
|
150
182
|
var hash = /^#$/;
|
|
151
183
|
var SQ = (
|
|
152
184
|
/** @type {const} */
|
|
@@ -195,17 +227,46 @@ var require_parse = __commonJS({
|
|
|
195
227
|
}
|
|
196
228
|
return pre + r;
|
|
197
229
|
}
|
|
230
|
+
var ansiCEscape = /\\([0-7]{1,3}|x[\dA-Fa-f]{1,2}|u[\dA-Fa-f]{1,4}|U[\dA-Fa-f]{1,8}|c(?:\\\\|[\s\S])|[abeEfnrtv\\'"?])/g;
|
|
231
|
+
function expandAnsiCEscape(m, escape) {
|
|
232
|
+
var kind = escape.charAt(0);
|
|
233
|
+
if (kind === "c") {
|
|
234
|
+
var ctrl = escape.charAt(1);
|
|
235
|
+
return ctrl === "?" ? "\x7F" : String.fromCharCode(ctrl.charCodeAt(0) & 31);
|
|
236
|
+
}
|
|
237
|
+
if (kind === "x" || kind === "u" || kind === "U") {
|
|
238
|
+
var cp = parseInt(escape.slice(1), 16);
|
|
239
|
+
if (cp > 1114111) {
|
|
240
|
+
return m;
|
|
241
|
+
}
|
|
242
|
+
return String.fromCharCode.apply(null, cp > 65535 ? [55232 + (cp >> 10), 56320 + (cp & 1023)] : [cp]);
|
|
243
|
+
}
|
|
244
|
+
if (kind >= "0" && kind <= "7") {
|
|
245
|
+
return String.fromCharCode(parseInt(escape, 8) & 255);
|
|
246
|
+
}
|
|
247
|
+
var letter = ANSI_C_LETTERS.indexOf(escape);
|
|
248
|
+
return letter < 0 ? escape : ANSI_C_CHARS.charAt(letter);
|
|
249
|
+
}
|
|
250
|
+
function expandAnsiC(body) {
|
|
251
|
+
return body.replace(ansiCEscape, expandAnsiCEscape).split("\0")[0];
|
|
252
|
+
}
|
|
253
|
+
function closesAnsiC(s, i2) {
|
|
254
|
+
ansiCAt.lastIndex = i2;
|
|
255
|
+
return !!/** @type {RegExpExecArray} */
|
|
256
|
+
ansiCAt.exec(s)[1];
|
|
257
|
+
}
|
|
198
258
|
function parseInternal(string, env, opts) {
|
|
199
259
|
if (!opts) {
|
|
200
260
|
opts = {};
|
|
201
261
|
}
|
|
202
262
|
var BS = opts.escape || "\\";
|
|
203
263
|
var ifs = opts.splitUnquoted === true ? " \n" : typeof opts.splitUnquoted === "string" ? opts.splitUnquoted : "";
|
|
204
|
-
var BAREWORD = "(\\" + BS + `['"
|
|
264
|
+
var BAREWORD = "(\\" + BS + `['"$\\` + BS + META + "]|\\$\\$|\\$(?!" + ANSI_C_QUOTE.slice(2) + `)|[^\\s'"$` + META + "])+";
|
|
265
|
+
var DOUBLE_QUOTE = '"(?:\\' + BS + '[\\s\\S]|[^"\\' + BS + '])*"';
|
|
205
266
|
var chunker = new RegExp([
|
|
206
267
|
"(" + CONTROL + ")",
|
|
207
268
|
// control chars
|
|
208
|
-
"(" + BAREWORD + "|" + DOUBLE_QUOTE + "|" + SINGLE_QUOTE + ")+"
|
|
269
|
+
"(" + ANSI_C_QUOTE + "|" + BAREWORD + "|" + DOUBLE_QUOTE + "|" + SINGLE_QUOTE + ")+"
|
|
209
270
|
].join("|"), "g");
|
|
210
271
|
var matches = matchAll(string, chunker);
|
|
211
272
|
if (matches.length === 0) {
|
|
@@ -260,9 +321,8 @@ var require_parse = __commonJS({
|
|
|
260
321
|
varend -= 1;
|
|
261
322
|
varname = s.slice(i2, varend);
|
|
262
323
|
i2 = varend;
|
|
263
|
-
} else if (/[
|
|
324
|
+
} else if (/[*@#?$!-]/.test(char)) {
|
|
264
325
|
varname = char;
|
|
265
|
-
i2 += 1;
|
|
266
326
|
} else {
|
|
267
327
|
var slicedFromI = s.slice(i2);
|
|
268
328
|
varend = slicedFromI.match(/[^\w\d_]/);
|
|
@@ -352,6 +412,11 @@ var require_parse = __commonJS({
|
|
|
352
412
|
);
|
|
353
413
|
} else if (c === BS) {
|
|
354
414
|
esc = true;
|
|
415
|
+
} else if (c === DS && s.charAt(i2 + 1) === SQ && closesAnsiC(s, i2)) {
|
|
416
|
+
flushRun();
|
|
417
|
+
sawQuote = true;
|
|
418
|
+
out += expandAnsiC(s.slice(i2 + 2, ansiCAt.lastIndex - 1));
|
|
419
|
+
i2 = ansiCAt.lastIndex - 1;
|
|
355
420
|
} else if (c === DS) {
|
|
356
421
|
var value = parseEnvVar();
|
|
357
422
|
if (!ifs) {
|
|
@@ -435,9 +500,9 @@ var require_parse = __commonJS({
|
|
|
435
500
|
}
|
|
436
501
|
});
|
|
437
502
|
|
|
438
|
-
// node_modules/.pnpm/shell-quote@1.
|
|
503
|
+
// node_modules/.pnpm/shell-quote@1.12.0/node_modules/shell-quote/index.js
|
|
439
504
|
var require_shell_quote = __commonJS({
|
|
440
|
-
"node_modules/.pnpm/shell-quote@1.
|
|
505
|
+
"node_modules/.pnpm/shell-quote@1.12.0/node_modules/shell-quote/index.js"(exports) {
|
|
441
506
|
"use strict";
|
|
442
507
|
exports.quote = require_quote();
|
|
443
508
|
exports.parse = require_parse();
|
|
@@ -4742,7 +4807,7 @@ function extractShellWriteTargetsAt(command, depth) {
|
|
|
4742
4807
|
const tok = tokens[i];
|
|
4743
4808
|
if (isOp(tok)) {
|
|
4744
4809
|
if (tok.op === "&" && isOp(tokens[i + 1], ">")) continue;
|
|
4745
|
-
if (tok.op === ">" || tok.op === ">>") {
|
|
4810
|
+
if (tok.op === ">" || tok.op === ">>" || tok.op === "&>" || tok.op === "&>>") {
|
|
4746
4811
|
const next = tokens[i + 1];
|
|
4747
4812
|
const text2 = next === void 0 ? null : tokenText(next);
|
|
4748
4813
|
if (text2 !== null) {
|
|
@@ -6006,6 +6071,30 @@ function composeSecurityBody(markdown, total, filePath) {
|
|
|
6006
6071
|
].join("\n");
|
|
6007
6072
|
}
|
|
6008
6073
|
|
|
6074
|
+
// src/hooks/runtime/proposal-mode.ts
|
|
6075
|
+
var TRUTHY = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
|
|
6076
|
+
var FALSY = /* @__PURE__ */ new Set(["0", "false", "no", "off"]);
|
|
6077
|
+
function envFlag(env, name) {
|
|
6078
|
+
const raw = env[name]?.trim().toLowerCase();
|
|
6079
|
+
if (raw && TRUTHY.has(raw)) return true;
|
|
6080
|
+
if (raw && FALSY.has(raw)) return false;
|
|
6081
|
+
return void 0;
|
|
6082
|
+
}
|
|
6083
|
+
function isNonBlockingMode(config, env = process.env) {
|
|
6084
|
+
return envFlag(env, "CYBEDEFEND_NON_BLOCKING") ?? config.hooks.nonBlockingMode === true;
|
|
6085
|
+
}
|
|
6086
|
+
function resolveProposalMode(config, env = process.env) {
|
|
6087
|
+
if (isNonBlockingMode(config, env)) return "non-blocking";
|
|
6088
|
+
const auto = envFlag(env, "CYBEDEFEND_AUTO_PROPOSE") ?? config.hooks.autoProposeMode === true;
|
|
6089
|
+
return auto ? "auto" : "ask";
|
|
6090
|
+
}
|
|
6091
|
+
var NON_BLOCKING_INBOX_DIRECTIVE = "Non-blocking mode is ON (autonomous agent \u2014 nobody is in the chat to answer). This OVERRIDES step 0 of the CybeDefend doctrine: do NOT call `cybe_rules_list_proposals`, do NOT ask the user about proposals (no AskUserQuestion), and NEVER call `cybe_rules_accept_proposal` / `cybe_rules_reject_proposal` yourself. Pending proposals stay in the inbox for a human to review in the CybeDefend dashboard. Proceed directly with the task.";
|
|
6092
|
+
var REPORT_MISSING_CALL = '`cybe_rules_report_missing(projectId, { rule_text, evidence_files, rationale: "<quote user prompt>", confirmed_by_user: true })`';
|
|
6093
|
+
var DIRECT_PROPOSE_DIRECTIVES = {
|
|
6094
|
+
auto: `**Auto-propose mode is ON** \u2014 this OVERRIDES the doctrine's "ask first" step: do NOT ask the user (no AskUserQuestion). If \u2014 and ONLY if \u2014 one durable, reusable gap stands out, call ${REPORT_MISSING_CALL} directly for that single rule. The user validates it at the next session start via the Accept/Reject picker. Otherwise propose nothing.`,
|
|
6095
|
+
"non-blocking": `**Non-blocking mode is ON** (autonomous agent \u2014 nobody is in the chat to answer). Do NOT ask the user (no AskUserQuestion). If \u2014 and ONLY if \u2014 one durable, reusable gap stands out, call ${REPORT_MISSING_CALL} directly for that single rule. It lands as a pending proposal that a human accepts or rejects in the CybeDefend dashboard. Otherwise propose nothing.`
|
|
6096
|
+
};
|
|
6097
|
+
|
|
6009
6098
|
// src/hooks/runtime/self-update-check.ts
|
|
6010
6099
|
import { spawn } from "node:child_process";
|
|
6011
6100
|
import { existsSync as existsSync8, readFileSync as readFileSync7, rmSync, writeFileSync as writeFileSync4 } from "node:fs";
|
|
@@ -6046,6 +6135,7 @@ var GLOBAL_MODES = /* @__PURE__ */ new Set([
|
|
|
6046
6135
|
]);
|
|
6047
6136
|
function detectInstallMode(scriptPath) {
|
|
6048
6137
|
if (/[\\/]_npx[\\/]/i.test(scriptPath)) return "npx-cache";
|
|
6138
|
+
if (/[\\/]dlx(?:-\d+)?[\\/]/i.test(scriptPath)) return "npx-cache";
|
|
6049
6139
|
if (/[\\/]pnpm(?:[\\/]global|[\\/]nodejs|[\\/]node_modules)/i.test(scriptPath)) {
|
|
6050
6140
|
return "pnpm-global";
|
|
6051
6141
|
}
|
|
@@ -6283,7 +6373,7 @@ function readPackageMeta(opts = {}) {
|
|
|
6283
6373
|
}
|
|
6284
6374
|
}
|
|
6285
6375
|
var pkg = readPackageMeta({
|
|
6286
|
-
bakedVersion: true ? "1.4.
|
|
6376
|
+
bakedVersion: true ? "1.4.5" : void 0
|
|
6287
6377
|
});
|
|
6288
6378
|
|
|
6289
6379
|
// src/hooks/runtime/session-start.ts
|
|
@@ -6338,7 +6428,12 @@ async function sessionStartHook(deps = {}) {
|
|
|
6338
6428
|
" if your client does not surface it, load the `cybe-init` MCP prompt manually.)"
|
|
6339
6429
|
);
|
|
6340
6430
|
lines.push("");
|
|
6341
|
-
if (
|
|
6431
|
+
if (isNonBlockingMode(config)) {
|
|
6432
|
+
lines.push(
|
|
6433
|
+
`- **Step 0 \u2014 proposals inbox**: ${total === null ? "not checked" : `${total} pending`} \u2014 no action required.`,
|
|
6434
|
+
` ${NON_BLOCKING_INBOX_DIRECTIVE}`
|
|
6435
|
+
);
|
|
6436
|
+
} else if (total === null) {
|
|
6342
6437
|
lines.push(
|
|
6343
6438
|
"- **Step 0 \u2014 proposals inbox**: \u26A0 unable to verify (no MCP token reachable).",
|
|
6344
6439
|
' **YOU MUST call `cybe_rules_list_proposals(projectId, status="proposed")` as',
|
|
@@ -6410,6 +6505,11 @@ function transcriptHasReviewSentinel(transcript) {
|
|
|
6410
6505
|
return false;
|
|
6411
6506
|
}
|
|
6412
6507
|
}
|
|
6508
|
+
function resolveReviewThreshold(config, env = process.env) {
|
|
6509
|
+
const raw = env.CYBEDEFEND_REVIEW_THRESHOLD?.trim();
|
|
6510
|
+
if (raw && /^\d+$/.test(raw) && Number(raw) <= 100) return Number(raw);
|
|
6511
|
+
return config.hooks.reviewThreshold;
|
|
6512
|
+
}
|
|
6413
6513
|
async function sessionReviewHook(deps = {}) {
|
|
6414
6514
|
const readStdin = deps.readStdin ?? readStdinJson;
|
|
6415
6515
|
const loadConfig = deps.loadConfig ?? loadRuntimeConfig;
|
|
@@ -6430,20 +6530,21 @@ async function sessionReviewHook(deps = {}) {
|
|
|
6430
6530
|
editCount = parseInt(process.env.CYBEDEFEND_DRY_RUN_EDITS ?? "5", 10);
|
|
6431
6531
|
}
|
|
6432
6532
|
if (editCount === 0) return;
|
|
6433
|
-
if (editCount < config
|
|
6533
|
+
if (editCount < resolveReviewThreshold(config)) return;
|
|
6434
6534
|
const userPrompt = extractFirstUserPrompt(transcript);
|
|
6535
|
+
const proposalMode = resolveProposalMode(config);
|
|
6435
6536
|
let body = composeReviewBody(
|
|
6436
6537
|
editCount,
|
|
6437
6538
|
event.client,
|
|
6438
6539
|
userPrompt,
|
|
6439
|
-
|
|
6540
|
+
proposalMode
|
|
6440
6541
|
);
|
|
6441
6542
|
const withDiffScan = config.hooks.enableDiffScan !== false;
|
|
6442
6543
|
if (withDiffScan) {
|
|
6443
6544
|
const cwd = typeof stdin.cwd === "string" && stdin.cwd ? stdin.cwd : process.cwd();
|
|
6444
6545
|
body += "\n" + composeDiffScanBody(extractChangedFiles(transcript, void 0, cwd));
|
|
6445
6546
|
}
|
|
6446
|
-
emitFn(body, event.client, composeStopReason(withDiffScan));
|
|
6547
|
+
emitFn(body, event.client, composeStopReason(withDiffScan, proposalMode));
|
|
6447
6548
|
}
|
|
6448
6549
|
function loadTranscript(stdin, readFile) {
|
|
6449
6550
|
if (Array.isArray(stdin.transcript)) return stdin.transcript;
|
|
@@ -6605,24 +6706,16 @@ function extractFirstUserPrompt(transcript) {
|
|
|
6605
6706
|
}
|
|
6606
6707
|
return "";
|
|
6607
6708
|
}
|
|
6608
|
-
function composeReviewBody(editCount, client, userPrompt,
|
|
6709
|
+
function composeReviewBody(editCount, client, userPrompt, proposalMode) {
|
|
6609
6710
|
const safePrompt = userPrompt || "(could not extract \u2014 re-read transcript)";
|
|
6610
|
-
const proposalLine =
|
|
6611
|
-
" **Auto-propose mode is ON** (configured at install). If \u2014 and ONLY",
|
|
6612
|
-
" if \u2014 one gap clears the bar above, call WITHOUT asking the user:",
|
|
6613
|
-
" `cybe_rules_report_missing(projectId, { rule_text, evidence_files,",
|
|
6614
|
-
' rationale: "<quote user prompt>", confirmed_by_user: true })` for',
|
|
6615
|
-
" that single rule. The user validates it at the next session start",
|
|
6616
|
-
" via the Accept/Reject picker. If nothing clears the bar, propose",
|
|
6617
|
-
" nothing."
|
|
6618
|
-
].join("\n") : [
|
|
6711
|
+
const proposalLine = proposalMode === "ask" ? [
|
|
6619
6712
|
" Ask the user via AskUserQuestion:",
|
|
6620
6713
|
' > "Your prompt implied <concern>, but no business rule covers it.',
|
|
6621
6714
|
' > Propose it as a standing rule for the project?" \u2014 Yes / No / Edit.',
|
|
6622
6715
|
' ONLY on an explicit "yes": call `cybe_rules_report_missing(projectId,',
|
|
6623
6716
|
' { rule_text, evidence_files, rationale: "<quote user prompt>",',
|
|
6624
6717
|
" confirmed_by_user: true })`."
|
|
6625
|
-
].join("\n")
|
|
6718
|
+
].join("\n") : ` ${DIRECT_PROPOSE_DIRECTIVES[proposalMode]}`;
|
|
6626
6719
|
return [
|
|
6627
6720
|
`## \u{1F6E1}\uFE0F CybeDefend gap analysis (Stop hook \u2014 ${editCount} edits this session, client=${client})`,
|
|
6628
6721
|
"",
|
|
@@ -6694,9 +6787,15 @@ function composeDiffScanBody(changedFiles) {
|
|
|
6694
6787
|
""
|
|
6695
6788
|
].join("\n");
|
|
6696
6789
|
}
|
|
6697
|
-
function composeStopReason(withDiffScan) {
|
|
6790
|
+
function composeStopReason(withDiffScan, proposalMode) {
|
|
6698
6791
|
const scan = withDiffScan ? ", then run a pre-commit `cybe_scan_diff` on the files you changed (poll `cybe_scan_status`, read `cybe_scan_findings`) and fix or justify each finding" : "";
|
|
6699
|
-
|
|
6792
|
+
const directPropose = "if \u2014 and only if \u2014 one durable gap stands out, propose that single rule directly with `cybe_rules_report_missing` (`confirmed_by_user: true`). ";
|
|
6793
|
+
const propose = {
|
|
6794
|
+
ask: "for any uncovered security/data concern, offer to propose a rule via AskUserQuestion (`cybe_rules_report_missing` only on an explicit yes)",
|
|
6795
|
+
auto: directPropose + "Auto-propose mode: do NOT ask the user (no AskUserQuestion) \u2014 they review it at the next session start",
|
|
6796
|
+
"non-blocking": directPropose + "Non-blocking mode: do NOT ask the user (no AskUserQuestion) \u2014 a human reviews the proposal in the CybeDefend dashboard"
|
|
6797
|
+
};
|
|
6798
|
+
return "\u{1F6E1}\uFE0F CybeDefend \u2014 before wrapping up, run the end-of-session review: gap-analyse the request against this session's business rules and, " + propose[proposalMode] + scan + ".";
|
|
6700
6799
|
}
|
|
6701
6800
|
|
|
6702
6801
|
// src/hooks/runtime/pre-compact.ts
|
|
@@ -6717,6 +6816,11 @@ async function preCompactHook(deps = {}) {
|
|
|
6717
6816
|
);
|
|
6718
6817
|
return;
|
|
6719
6818
|
}
|
|
6819
|
+
const proposalMode = resolveProposalMode(config);
|
|
6820
|
+
const proposeStep = proposalMode === "ask" ? [
|
|
6821
|
+
"3. For uncovered concerns, ask the user via AskUserQuestion whether to propose;",
|
|
6822
|
+
' on "yes", call `cybe_rules_report_missing` with confirmed_by_user: true.'
|
|
6823
|
+
] : [`3. ${DIRECT_PROPOSE_DIRECTIVES[proposalMode]}`];
|
|
6720
6824
|
const body = [
|
|
6721
6825
|
"## \u{1F6E1}\uFE0F CybeDefend PreCompact gap analysis",
|
|
6722
6826
|
"",
|
|
@@ -6724,8 +6828,7 @@ async function preCompactHook(deps = {}) {
|
|
|
6724
6828
|
"Before the fine-grained tool history is summarised away, run a gap analysis:",
|
|
6725
6829
|
"1. Re-read the original user request (still uncompacted now).",
|
|
6726
6830
|
"2. List the CybeDefend rules returned during the session.",
|
|
6727
|
-
|
|
6728
|
-
' on "yes", call `cybe_rules_report_missing` with confirmed_by_user: true.',
|
|
6831
|
+
...proposeStep,
|
|
6729
6832
|
""
|
|
6730
6833
|
].join("\n");
|
|
6731
6834
|
emitFn(body, event.client);
|
|
@@ -6802,7 +6905,13 @@ async function userPromptSubmitHook(deps = {}) {
|
|
|
6802
6905
|
"",
|
|
6803
6906
|
"### Step 0 \u2014 Proposal inbox"
|
|
6804
6907
|
];
|
|
6805
|
-
|
|
6908
|
+
const nonBlocking = isNonBlockingMode(config);
|
|
6909
|
+
if (nonBlocking) {
|
|
6910
|
+
lines.push(
|
|
6911
|
+
`- CybeDefend: ${total === null ? "proposal inbox not checked" : `**${total}** pending proposals`} \u2014 no action required.`,
|
|
6912
|
+
`- ${NON_BLOCKING_INBOX_DIRECTIVE}`
|
|
6913
|
+
);
|
|
6914
|
+
} else if (total === null) {
|
|
6806
6915
|
lines.push(
|
|
6807
6916
|
"- CybeDefend: could not fetch proposal-inbox status (token / API unreachable).",
|
|
6808
6917
|
'- Call `cybe_rules_list_proposals(projectId, status="proposed")` yourself to verify, then handle each surfaced proposal via AskUserQuestion (Accept / Reject / Skip / Tell me more) before continuing.'
|
|
@@ -6828,7 +6937,7 @@ async function userPromptSubmitHook(deps = {}) {
|
|
|
6828
6937
|
"- The PreToolUse hook fires automatically as a backstop on Edit/Write/MultiEdit, but your explicit call with a narrative intent gets better matches.",
|
|
6829
6938
|
"",
|
|
6830
6939
|
"### Order",
|
|
6831
|
-
"1. Satisfy step 0 (acknowledge / handle the inbox).",
|
|
6940
|
+
nonBlocking ? "1. Step 0 needs no action (non-blocking mode)." : "1. Satisfy step 0 (acknowledge / handle the inbox).",
|
|
6832
6941
|
"2. Satisfy step 1 (fetch rules with a narrative intent) once you know which files you will touch.",
|
|
6833
6942
|
"3. THEN proceed with whatever skill / brainstorm / implementation flow fits the task.",
|
|
6834
6943
|
""
|
package/dist/hooks/install.js
CHANGED
|
@@ -159,6 +159,7 @@ export function installHookRuntime(opts, deps = {}) {
|
|
|
159
159
|
enableSessionReview: opts.hooks.enableSessionReview,
|
|
160
160
|
reviewThreshold: opts.hooks.reviewThreshold,
|
|
161
161
|
autoProposeMode: opts.hooks.autoProposeMode,
|
|
162
|
+
nonBlockingMode: opts.hooks.nonBlockingMode,
|
|
162
163
|
autoUpdate: useShim ? opts.hooks.autoUpdate : false,
|
|
163
164
|
enableDiffScan: opts.hooks.enableDiffScan,
|
|
164
165
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/hooks/install.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/hooks/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { sniff } from './sniff.js';
|
|
11
11
|
import { emit } from './emit.js';
|
|
12
12
|
import { loadRuntimeConfig, readStdinJson } from './config.js';
|
|
13
|
+
import { DIRECT_PROPOSE_DIRECTIVES, resolveProposalMode, } from './proposal-mode.js';
|
|
13
14
|
export async function preCompactHook(deps = {}) {
|
|
14
15
|
const readStdin = deps.readStdin ?? readStdinJson;
|
|
15
16
|
const loadConfig = deps.loadConfig ?? loadRuntimeConfig;
|
|
@@ -25,6 +26,13 @@ export async function preCompactHook(deps = {}) {
|
|
|
25
26
|
emitFn(`## 🛡️ CybeDefend PreCompact (dry-run, client=${event.client})\n`, event.client);
|
|
26
27
|
return;
|
|
27
28
|
}
|
|
29
|
+
const proposalMode = resolveProposalMode(config);
|
|
30
|
+
const proposeStep = proposalMode === 'ask'
|
|
31
|
+
? [
|
|
32
|
+
'3. For uncovered concerns, ask the user via AskUserQuestion whether to propose;',
|
|
33
|
+
' on "yes", call `cybe_rules_report_missing` with confirmed_by_user: true.',
|
|
34
|
+
]
|
|
35
|
+
: [`3. ${DIRECT_PROPOSE_DIRECTIVES[proposalMode]}`];
|
|
28
36
|
const body = [
|
|
29
37
|
'## 🛡️ CybeDefend PreCompact gap analysis',
|
|
30
38
|
'',
|
|
@@ -32,8 +40,7 @@ export async function preCompactHook(deps = {}) {
|
|
|
32
40
|
'Before the fine-grained tool history is summarised away, run a gap analysis:',
|
|
33
41
|
'1. Re-read the original user request (still uncompacted now).',
|
|
34
42
|
'2. List the CybeDefend rules returned during the session.',
|
|
35
|
-
|
|
36
|
-
' on "yes", call `cybe_rules_report_missing` with confirmed_by_user: true.',
|
|
43
|
+
...proposeStep,
|
|
37
44
|
'',
|
|
38
45
|
].join('\n');
|
|
39
46
|
emitFn(body, event.client);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pre-compact.js","sourceRoot":"","sources":["../../../src/hooks/runtime/pre-compact.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"pre-compact.js","sourceRoot":"","sources":["../../../src/hooks/runtime/pre-compact.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EACL,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAQ5B,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAuB,EAAE;IAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,aAAa,CAAC;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,iBAAiB,CAAC;IACxD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;IAEnC,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE3B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB;QAAE,OAAO;IAE9C,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,GAAG,EAAE,CAAC;QAC3C,MAAM,CACJ,iDAAiD,KAAK,CAAC,MAAM,KAAK,EAClE,KAAK,CAAC,MAAM,CACb,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,YAAY,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,WAAW,GACf,YAAY,KAAK,KAAK;QACpB,CAAC,CAAC;YACE,iFAAiF;YACjF,6EAA6E;SAC9E;QACH,CAAC,CAAC,CAAC,MAAM,yBAAyB,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG;QACX,2CAA2C;QAC3C,EAAE;QACF,uEAAuE;QACvE,8EAA8E;QAC9E,+DAA+D;QAC/D,2DAA2D;QAC3D,GAAG,WAAW;QACd,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const TRUTHY = new Set(['1', 'true', 'yes', 'on']);
|
|
2
|
+
const FALSY = new Set(['0', 'false', 'no', 'off']);
|
|
3
|
+
/**
|
|
4
|
+
* Boolean env override: `true` / `false` for a recognised value, `undefined`
|
|
5
|
+
* otherwise (unset, empty, typo) so the caller falls back to the config.
|
|
6
|
+
*/
|
|
7
|
+
function envFlag(env, name) {
|
|
8
|
+
const raw = env[name]?.trim().toLowerCase();
|
|
9
|
+
if (raw && TRUTHY.has(raw))
|
|
10
|
+
return true;
|
|
11
|
+
if (raw && FALSY.has(raw))
|
|
12
|
+
return false;
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Whether the hooks run in non-blocking mode.
|
|
17
|
+
*
|
|
18
|
+
* `CYBEDEFEND_NON_BLOCKING` wins over the installed config in both
|
|
19
|
+
* directions, so one machine can serve a human (interactive) and an
|
|
20
|
+
* autonomous agent (env var set on its process only). `undefined` in the
|
|
21
|
+
* config (written before this feature shipped) means OFF.
|
|
22
|
+
*/
|
|
23
|
+
export function isNonBlockingMode(config, env = process.env) {
|
|
24
|
+
return (envFlag(env, 'CYBEDEFEND_NON_BLOCKING') ??
|
|
25
|
+
config.hooks.nonBlockingMode === true);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the proposal mode. Non-blocking supersedes auto-propose (it already
|
|
29
|
+
* proposes without asking, and skips the inbox review on top). Auto-propose
|
|
30
|
+
* follows `CYBEDEFEND_AUTO_PROPOSE` first, in both directions, then the
|
|
31
|
+
* installed `autoProposeMode`.
|
|
32
|
+
*/
|
|
33
|
+
export function resolveProposalMode(config, env = process.env) {
|
|
34
|
+
if (isNonBlockingMode(config, env))
|
|
35
|
+
return 'non-blocking';
|
|
36
|
+
const auto = envFlag(env, 'CYBEDEFEND_AUTO_PROPOSE') ??
|
|
37
|
+
config.hooks.autoProposeMode === true;
|
|
38
|
+
return auto ? 'auto' : 'ask';
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Step-0 override shared by the SessionStart and UserPromptSubmit hooks in
|
|
42
|
+
* non-blocking mode. The agent must not triage the inbox itself either:
|
|
43
|
+
* accepting or rejecting a proposal stays a human decision, taken in the
|
|
44
|
+
* dashboard.
|
|
45
|
+
*/
|
|
46
|
+
export const NON_BLOCKING_INBOX_DIRECTIVE = 'Non-blocking mode is ON (autonomous agent — nobody is in the chat to answer). ' +
|
|
47
|
+
'This OVERRIDES step 0 of the CybeDefend doctrine: do NOT call ' +
|
|
48
|
+
'`cybe_rules_list_proposals`, do NOT ask the user about proposals (no ' +
|
|
49
|
+
'AskUserQuestion), and NEVER call `cybe_rules_accept_proposal` / ' +
|
|
50
|
+
'`cybe_rules_reject_proposal` yourself. Pending proposals stay in the inbox ' +
|
|
51
|
+
'for a human to review in the CybeDefend dashboard. Proceed directly with the task.';
|
|
52
|
+
const REPORT_MISSING_CALL = '`cybe_rules_report_missing(projectId, { rule_text, evidence_files, ' +
|
|
53
|
+
'rationale: "<quote user prompt>", confirmed_by_user: true })`';
|
|
54
|
+
/**
|
|
55
|
+
* Gap-analysis proposal step for the Stop and PreCompact hooks when the agent
|
|
56
|
+
* proposes without asking (the `ask` flow keeps each hook's own wording).
|
|
57
|
+
*
|
|
58
|
+
* `confirmed_by_user: true` is still passed: the gateway requires it for
|
|
59
|
+
* agent-sourced proposals, and here it stands for the operator's opt-in to
|
|
60
|
+
* that mode. The human gate moves to the inbox review (next session start for
|
|
61
|
+
* `auto`, the dashboard for `non-blocking`).
|
|
62
|
+
*/
|
|
63
|
+
export const DIRECT_PROPOSE_DIRECTIVES = {
|
|
64
|
+
auto: '**Auto-propose mode is ON** — this OVERRIDES the doctrine\'s "ask first" ' +
|
|
65
|
+
'step: do NOT ask the user (no AskUserQuestion). If — and ONLY if — one ' +
|
|
66
|
+
`durable, reusable gap stands out, call ${REPORT_MISSING_CALL} directly for ` +
|
|
67
|
+
'that single rule. The user validates it at the next session start via the ' +
|
|
68
|
+
'Accept/Reject picker. Otherwise propose nothing.',
|
|
69
|
+
'non-blocking': '**Non-blocking mode is ON** (autonomous agent — nobody is in the chat to ' +
|
|
70
|
+
'answer). Do NOT ask the user (no AskUserQuestion). If — and ONLY if — one ' +
|
|
71
|
+
`durable, reusable gap stands out, call ${REPORT_MISSING_CALL} directly for ` +
|
|
72
|
+
'that single rule. It lands as a pending proposal that a human accepts or ' +
|
|
73
|
+
'rejects in the CybeDefend dashboard. Otherwise propose nothing.',
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=proposal-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposal-mode.js","sourceRoot":"","sources":["../../../src/hooks/runtime/proposal-mode.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;AACnD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;AAEnD;;;GAGG;AACH,SAAS,OAAO,CAAC,GAAsB,EAAE,IAAY;IACnD,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5C,IAAI,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAqB,EACrB,MAAyB,OAAO,CAAC,GAAG;IAEpC,OAAO,CACL,OAAO,CAAC,GAAG,EAAE,yBAAyB,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,eAAe,KAAK,IAAI,CACtC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAqB,EACrB,MAAyB,OAAO,CAAC,GAAG;IAEpC,IAAI,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC;QAAE,OAAO,cAAc,CAAC;IAC1D,MAAM,IAAI,GACR,OAAO,CAAC,GAAG,EAAE,yBAAyB,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,eAAe,KAAK,IAAI,CAAC;IACxC,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,4BAA4B,GACvC,gFAAgF;IAChF,gEAAgE;IAChE,uEAAuE;IACvE,kEAAkE;IAClE,6EAA6E;IAC7E,oFAAoF,CAAC;AAEvF,MAAM,mBAAmB,GACvB,qEAAqE;IACrE,+DAA+D,CAAC;AAElE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAGlC;IACF,IAAI,EACF,2EAA2E;QAC3E,yEAAyE;QACzE,0CAA0C,mBAAmB,gBAAgB;QAC7E,4EAA4E;QAC5E,kDAAkD;IACpD,cAAc,EACZ,2EAA2E;QAC3E,4EAA4E;QAC5E,0CAA0C,mBAAmB,gBAAgB;QAC7E,2EAA2E;QAC3E,iEAAiE;CACpE,CAAC"}
|