robrain 2.3.7 → 2.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/commands/install.d.ts.map +1 -1
  2. package/dist/commands/install.js +17 -2
  3. package/dist/commands/install.js.map +1 -1
  4. package/dist/commands/up.test.js +2 -2
  5. package/dist/index.js +1 -1
  6. package/dist/lib/codex-hooks.d.ts +26 -0
  7. package/dist/lib/codex-hooks.d.ts.map +1 -0
  8. package/dist/lib/codex-hooks.js +65 -0
  9. package/dist/lib/codex-hooks.js.map +1 -0
  10. package/dist/lib/codex-hooks.test.d.ts +2 -0
  11. package/dist/lib/codex-hooks.test.d.ts.map +1 -0
  12. package/dist/lib/codex-hooks.test.js +64 -0
  13. package/dist/lib/codex-hooks.test.js.map +1 -0
  14. package/dist/lib/editor.codex.test.js +20 -0
  15. package/dist/lib/editor.codex.test.js.map +1 -1
  16. package/dist/lib/editor.d.ts +2 -0
  17. package/dist/lib/editor.d.ts.map +1 -1
  18. package/dist/lib/editor.js +28 -0
  19. package/dist/lib/editor.js.map +1 -1
  20. package/dist/lib/mcp-bundle.test.js +2 -2
  21. package/dist/lib/release-guard.d.ts +22 -0
  22. package/dist/lib/release-guard.d.ts.map +1 -0
  23. package/dist/lib/release-guard.js +46 -0
  24. package/dist/lib/release-guard.js.map +1 -0
  25. package/dist/lib/release-guard.test.d.ts +2 -0
  26. package/dist/lib/release-guard.test.d.ts.map +1 -0
  27. package/dist/lib/release-guard.test.js +60 -0
  28. package/dist/lib/release-guard.test.js.map +1 -0
  29. package/package.json +10 -11
  30. package/scripts/vendor-codex-hooks.mjs +31 -0
  31. package/scripts/verify-publish-tarball.mjs +9 -0
  32. package/scripts/verify-release-artifacts.mjs +77 -0
  33. package/vendor/codex-hooks/lib.mjs +276 -0
  34. package/vendor/codex-hooks/session-start.mjs +29 -0
  35. package/vendor/codex-hooks/stop.mjs +78 -0
  36. package/vendor/codex-hooks/user-prompt-submit.mjs +95 -0
  37. package/vendor/sensing-mcp/dist/index.js +26 -1
  38. package/vendor/sensing-mcp/package.json +1 -1
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+ // UserPromptSubmit hook — pre-task veto injection, two tiers:
3
+ // 1. Deterministic: POST /veto-scan — does the prompt literally name an
4
+ // option an active decision rejected? Zero embeddings, zero LLM, fires
5
+ // for ANY prompt length. An exact mention warns at confidence 1.0.
6
+ // 2. Semantic: GET /decisions?query= for prompts long enough to embed.
7
+ // Gated on SIMILARITY, not planning_score — planning_score blends in
8
+ // recency decay, and a rejection must not fade from warnings just
9
+ // because it is old.
10
+ // Warnings already shown this session are not repeated (state file) —
11
+ // injected context must never cost more than it saves.
12
+
13
+ import {
14
+ readStdin, parseHookInput, loadPerception, resolveProjectId,
15
+ perceptionFetch, emitContext, exitSilently, loadWarnedIds, recordWarnedIds,
16
+ stashPrompt,
17
+ } from './lib.mjs'
18
+
19
+ const input = parseHookInput(await readStdin())
20
+ const prompt = (input.prompt ?? '').trim()
21
+
22
+ // Skip: slash commands and empty prompts. The deterministic tier is cheap
23
+ // enough to run even on short prompts ("use Pinecone now" must warn).
24
+ if (!prompt || prompt.startsWith('/')) exitSilently()
25
+
26
+ const cwd = input.cwd ?? process.cwd()
27
+ const sessionId = typeof input.session_id === 'string' ? input.session_id : ''
28
+
29
+ // Stash the prompt for stop-hook capture on clients whose transcript format
30
+ // we do not parse (Codex pairs this with last_assistant_message).
31
+ stashPrompt(sessionId, prompt)
32
+ const perception = loadPerception()
33
+ const projectId = resolveProjectId(cwd)
34
+
35
+ // Tier 1 — deterministic rejected-option scan.
36
+ const scan = await perceptionFetch('/veto-scan', perception, {
37
+ method: 'POST',
38
+ body: JSON.stringify({ project_id: projectId, text: prompt.slice(0, 2000) }),
39
+ }, 1500)
40
+ const exact = (Array.isArray(scan?.matches) ? scan.matches : [])
41
+ .map(m => ({ ...m, exact: true }))
42
+
43
+ // Tier 2 — semantic search only for prompts worth an embedding round-trip
44
+ // (greetings, "yes", … skip it).
45
+ const MIN_SIMILARITY = 0.45
46
+ let semantic = []
47
+ if (prompt.length >= 24) {
48
+ const params = new URLSearchParams({
49
+ project_id: projectId,
50
+ query: prompt.slice(0, 2000),
51
+ limit: '8',
52
+ })
53
+ const data = await perceptionFetch(`/decisions?${params}`, perception, {}, 2500)
54
+ const decisions = Array.isArray(data) ? data : data?.decisions
55
+ if (Array.isArray(decisions)) {
56
+ semantic = decisions
57
+ .filter(d => Array.isArray(d.rejected) && d.rejected.length > 0)
58
+ .filter(d => typeof d.similarity !== 'number' || d.similarity >= MIN_SIMILARITY)
59
+ .sort((a, b) => (b.similarity ?? 0) - (a.similarity ?? 0))
60
+ }
61
+ }
62
+
63
+ // Merge: exact matches first (exempt from the similarity gate), then
64
+ // semantic; skip anything already warned in this session.
65
+ const warned = loadWarnedIds(sessionId)
66
+ const seen = new Set()
67
+ const vetoes = []
68
+ for (const d of [...exact, ...semantic]) {
69
+ if (!d.id || seen.has(d.id) || warned.has(d.id)) continue
70
+ seen.add(d.id)
71
+ vetoes.push(d)
72
+ if (vetoes.length === 3) break
73
+ }
74
+
75
+ if (vetoes.length === 0) exitSilently()
76
+
77
+ const lines = vetoes.map(d => {
78
+ const rej = d.rejected
79
+ .slice(0, 2)
80
+ .map(r => `**${r.option}** (${r.reason})`)
81
+ .join('; ')
82
+ const tag = d.exact ? ' *(exact match on rejected option)*' : ''
83
+ return `- ${d.decision}${tag}\n Rejected: ${rej}`
84
+ })
85
+
86
+ recordWarnedIds(sessionId, vetoes.map(d => d.id))
87
+
88
+ emitContext(
89
+ 'UserPromptSubmit',
90
+ [
91
+ '⚠ RoBrain — this task touches decisions with previously REJECTED approaches:',
92
+ ...lines,
93
+ 'Do not re-propose a rejected option without flagging the prior rejection and why circumstances changed.',
94
+ ].join('\n'),
95
+ )
@@ -6911,6 +6911,30 @@ var require_redact = __commonJS({
6911
6911
  }
6912
6912
  });
6913
6913
 
6914
+ // ../shared/dist/veto-match.js
6915
+ var require_veto_match = __commonJS({
6916
+ "../shared/dist/veto-match.js"(exports) {
6917
+ "use strict";
6918
+ Object.defineProperty(exports, "__esModule", { value: true });
6919
+ exports.proposalMatchesRejectedOption = proposalMatchesRejectedOption;
6920
+ function proposalMatchesRejectedOption(proposalText, rejected) {
6921
+ if (!rejected?.length)
6922
+ return null;
6923
+ for (const r of rejected) {
6924
+ const option = r.option.trim();
6925
+ if (option.length < 3)
6926
+ continue;
6927
+ const escaped = option.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6928
+ const lead = /^[A-Za-z0-9_]/.test(option) ? "\\b" : "";
6929
+ const trail = /[A-Za-z0-9_]$/.test(option) ? "\\b" : "";
6930
+ if (new RegExp(`${lead}${escaped}${trail}`, "i").test(proposalText))
6931
+ return r;
6932
+ }
6933
+ return null;
6934
+ }
6935
+ }
6936
+ });
6937
+
6914
6938
  // ../shared/dist/extract-decision.js
6915
6939
  var require_extract_decision = __commonJS({
6916
6940
  "../shared/dist/extract-decision.js"(exports) {
@@ -7045,6 +7069,7 @@ var require_dist = __commonJS({
7045
7069
  __exportStar(require_llm(), exports);
7046
7070
  __exportStar(require_embeddings(), exports);
7047
7071
  __exportStar(require_redact(), exports);
7072
+ __exportStar(require_veto_match(), exports);
7048
7073
  __exportStar(require_extract_decision(), exports);
7049
7074
  __exportStar(require_db(), exports);
7050
7075
  }
@@ -23037,7 +23062,7 @@ function resolveSessionId(raw) {
23037
23062
  function buildServer() {
23038
23063
  const server = new McpServer({
23039
23064
  name: "sensing-mcp",
23040
- version: "2.3.7"
23065
+ version: "2.3.8"
23041
23066
  });
23042
23067
  server.tool(
23043
23068
  "sensing_start_session",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robrain/sensing-mcp",
3
- "version": "2.3.7",
3
+ "version": "2.3.8",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js"