@ironbee-ai/cli 0.30.0 → 0.32.0
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/CHANGELOG.md +12 -0
- package/dist/analytics/claude/emit.js +1 -1
- package/dist/analytics/claude/state.js +1 -1
- package/dist/analytics/codex/events-emit.js +2 -2
- package/dist/analytics/codex/subagent-transcripts.js +3 -3
- package/dist/clients/claude/agents/ironbee-scenario.md +4 -1
- package/dist/clients/claude/agents/ironbee-verifier.md +21 -3
- package/dist/clients/claude/hooks/activity-end.js +1 -1
- package/dist/clients/claude/hooks/activity-start.js +1 -1
- package/dist/clients/claude/hooks/clear-verdict.js +1 -1
- package/dist/clients/claude/hooks/require-verdict.js +2 -2
- package/dist/clients/claude/hooks/require-verification.js +4 -4
- package/dist/clients/claude/hooks/session-end.js +1 -1
- package/dist/clients/claude/hooks/session-start.js +4 -4
- package/dist/clients/claude/hooks/session-status.js +2 -2
- package/dist/clients/claude/hooks/subagent-start.js +1 -1
- package/dist/clients/claude/hooks/subagent-stop.js +1 -1
- package/dist/clients/claude/hooks/track-action-monitor.js +1 -1
- package/dist/clients/claude/hooks/track-action.js +1 -1
- package/dist/clients/claude/hooks/verify-gate.js +4 -4
- package/dist/clients/claude/index.js +4 -4
- package/dist/clients/claude/platforms/scenario.android.md +1 -0
- package/dist/clients/claude/platforms/scenario.terminal.md +26 -0
- package/dist/clients/claude/platforms/skill.android.md +4 -0
- package/dist/clients/claude/platforms/skill.browser.md +1 -1
- package/dist/clients/claude/platforms/skill.terminal.md +62 -0
- package/dist/clients/claude/process-analytics.js +1 -1
- package/dist/clients/claude/statusline-toggle.js +2 -2
- package/dist/clients/codex/agents/ironbee-scenario.md +3 -0
- package/dist/clients/codex/agents/ironbee-verifier.md +20 -2
- package/dist/clients/codex/commands/ironbee-manage-scenario/SKILL.main.md +3 -0
- package/dist/clients/codex/commands/ironbee-search-scenario/SKILL.main.md +3 -0
- package/dist/clients/codex/commands/ironbee-sync-scenario/SKILL.main.md +3 -0
- package/dist/clients/codex/commands/ironbee-verify/SKILL.main.md +3 -0
- package/dist/clients/codex/hooks/activity-end.js +1 -1
- package/dist/clients/codex/hooks/activity-start.js +1 -1
- package/dist/clients/codex/hooks/clear-verdict.js +3 -3
- package/dist/clients/codex/hooks/require-verdict.js +2 -2
- package/dist/clients/codex/hooks/require-verification.js +3 -3
- package/dist/clients/codex/hooks/session-start.js +3 -3
- package/dist/clients/codex/hooks/subagent-start.js +1 -1
- package/dist/clients/codex/hooks/subagent-stop.js +1 -1
- package/dist/clients/codex/hooks/track-action-monitor.js +1 -1
- package/dist/clients/codex/hooks/track-action-pre.js +1 -1
- package/dist/clients/codex/hooks/track-action.js +1 -1
- package/dist/clients/codex/hooks/verify-gate.js +1 -1
- package/dist/clients/codex/index.js +2 -2
- package/dist/clients/codex/platforms/command-verify.android.md +1 -0
- package/dist/clients/codex/platforms/command-verify.terminal.md +61 -0
- package/dist/clients/codex/platforms/rule.android.md +2 -1
- package/dist/clients/codex/platforms/rule.terminal.md +31 -0
- package/dist/clients/codex/platforms/scenario.android.md +1 -0
- package/dist/clients/codex/platforms/scenario.terminal.md +36 -0
- package/dist/clients/codex/platforms/skill.android.md +4 -0
- package/dist/clients/codex/platforms/skill.browser.md +1 -1
- package/dist/clients/codex/platforms/skill.terminal.md +57 -0
- package/dist/clients/codex/process-analytics.js +2 -2
- package/dist/clients/codex/rules/ironbee-verification.main.md +3 -0
- package/dist/clients/codex/skills/ironbee-verification.main.md +3 -0
- package/dist/clients/codex/thread-map.js +1 -1
- package/dist/clients/codex/util.js +44 -31
- package/dist/clients/cursor/commands/ironbee-manage-scenario/SKILL.md +3 -0
- package/dist/clients/cursor/commands/ironbee-search-scenario/SKILL.md +3 -0
- package/dist/clients/cursor/commands/ironbee-sync-scenario/SKILL.md +3 -0
- package/dist/clients/cursor/commands/ironbee-verify/SKILL.md +3 -0
- package/dist/clients/cursor/hooks/activity-end.js +1 -1
- package/dist/clients/cursor/hooks/activity-start.js +1 -1
- package/dist/clients/cursor/hooks/clear-verdict.js +1 -1
- package/dist/clients/cursor/hooks/require-verdict.js +2 -2
- package/dist/clients/cursor/hooks/require-verification.js +3 -3
- package/dist/clients/cursor/hooks/session-end.js +1 -1
- package/dist/clients/cursor/hooks/session-start.js +4 -4
- package/dist/clients/cursor/hooks/track-action-monitor.js +1 -1
- package/dist/clients/cursor/hooks/track-action.js +1 -1
- package/dist/clients/cursor/hooks/verify-gate.js +1 -1
- package/dist/clients/cursor/index.js +1 -1
- package/dist/clients/cursor/platforms/command-verify.android.md +1 -0
- package/dist/clients/cursor/platforms/command-verify.terminal.md +61 -0
- package/dist/clients/cursor/platforms/rule.android.md +2 -1
- package/dist/clients/cursor/platforms/rule.terminal.md +31 -0
- package/dist/clients/cursor/platforms/scenario.android.md +1 -0
- package/dist/clients/cursor/platforms/scenario.terminal.md +29 -0
- package/dist/clients/cursor/platforms/skill.android.md +4 -0
- package/dist/clients/cursor/platforms/skill.browser.md +1 -1
- package/dist/clients/cursor/platforms/skill.terminal.md +54 -0
- package/dist/clients/cursor/rules/ironbee-verification.mdc +3 -0
- package/dist/clients/cursor/skills/ironbee-verification.md +9 -0
- package/dist/commands/config.js +2 -2
- package/dist/commands/hook.js +10 -10
- package/dist/commands/import.js +3 -3
- package/dist/commands/install.js +1 -1
- package/dist/commands/process-job-file.js +1 -1
- package/dist/commands/queue.js +16 -16
- package/dist/commands/scenario.js +1 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/terminal.js +1 -0
- package/dist/commands/uninstall.js +1 -1
- package/dist/commands/verify.js +2 -2
- package/dist/hooks/core/actions.js +7 -7
- package/dist/hooks/core/session-state.js +1 -1
- package/dist/hooks/core/verification-context.js +19 -15
- package/dist/hooks/core/verify-gate.js +25 -20
- package/dist/import/claude/events/tool-call.js +1 -1
- package/dist/import/codex/events/tool-call.js +1 -1
- package/dist/import/marker.js +2 -2
- package/dist/import/skip.js +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/config.js +1 -1
- package/dist/lib/install-version.js +1 -1
- package/dist/lib/platform-section.js +5 -4
- package/dist/lib/runtime-paths.js +1 -0
- package/dist/lib/scenario-staleness.js +1 -1
- package/dist/otel/claude/daemon/process.js +1 -1
- package/dist/otel/claude/daemon/reprocess.js +1 -1
- package/dist/otel/claude/daemon/response-usage.js +2 -2
- package/dist/queue/drain.js +1 -1
- package/dist/queue/flush.js +1 -1
- package/dist/queue/paths.js +1 -1
- package/dist/queue/process-file.js +2 -2
- package/dist/queue/spawn.js +1 -1
- package/dist/tui/config/schema.js +1 -1
- package/dist/tui/platforms/area.js +2 -2
- package/dist/tui/queue/read.js +4 -4
- package/dist/tui/sessions/read.js +2 -2
- package/package.json +1 -1
|
@@ -1,54 +1,67 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var $=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var M=Object.prototype.hasOwnProperty;var o=(n,t)=>$(n,"name",{value:t,configurable:!0});var J=(n,t)=>{for(var e in t)$(n,e,{get:t[e],enumerable:!0})},P=(n,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of W(t))!M.call(n,r)&&r!==e&&$(n,r,{get:()=>t[r],enumerable:!(s=L(t,r))||s.enumerable});return n};var B=n=>P($({},"__esModule",{value:!0}),n);var hn={};J(hn,{AGENTS_MD_END_MARKER:()=>y,AGENTS_MD_START_MARKER:()=>v,canonicalizeCodexServerName:()=>C,canonicalizeCodexToolName:()=>R,classifyCodexTool:()=>D,codexAgentTomlPath:()=>ln,codexConfigTomlPath:()=>O,codexHooksJsonPath:()=>pn,decodeJwtPayload:()=>E,ensureFeaturesHooksTrue:()=>Z,ensureMultiAgentV2SpawnMetadataExposed:()=>Y,ensureSandboxWritableRoot:()=>sn,extractBashBinary:()=>A,extractCodexMcpServer:()=>S,extractCodexToolInput:()=>K,extractTomlTopLevelModel:()=>un,findTomlSection:()=>p,normalizeCodexToolName:()=>j,parseCodexHookStdin:()=>z,readCodexConfigToml:()=>gn,removeAgentsTable:()=>rn,removeFeaturesHooks:()=>q,removeMcpServer:()=>tn,removeMultiAgentV2SpawnMetadata:()=>N,removeSandboxWritableRoot:()=>on,resolveCodexUsage:()=>X,stripAgentsMdBlock:()=>cn,tomlBodyFromRecord:()=>an,upsertAgentsMdBlock:()=>dn,upsertAgentsTable:()=>en,upsertMcpServer:()=>nn,userCodexAgentTomlPath:()=>_n,userCodexConfigTomlPath:()=>mn,userCodexHooksJsonPath:()=>xn,writeCodexConfigToml:()=>fn});module.exports=B(hn);var x=require("fs"),I=require("os"),m=require("path"),b=require("../../lib/logger");function z(n){try{return JSON.parse(n)}catch(t){return b.logger.debug(`failed to parse Codex hook stdin: ${t}`),{}}}o(z,"parseCodexHookStdin");const h="mcp__",H={browser_devtools:"browser-devtools",node_devtools:"node-devtools",backend_devtools:"backend-devtools",android_devtools:"android-devtools",terminal_devtools:"terminal-devtools"},F=["bdt_","ndt_","bedt_","adt_","tdt_"];function C(n){return H[n]??n}o(C,"canonicalizeCodexServerName");function R(n){if(!F.some(e=>n.startsWith(e)))return n;const t=n.split("_");return t.length>=3&&t[1]==="scenario"?`${t[0]}_scenario-${t.slice(2).join("-")}`:t.length<=3?n:`${t[0]}_${t[1]}_${t.slice(2).join("-")}`}o(R,"canonicalizeCodexToolName");const V=[["bdt_","browser-devtools"],["ndt_","node-devtools"],["bedt_","backend-devtools"],["adt_","android-devtools"],["tdt_","terminal-devtools"]];function S(n){if(!n)return null;if(n.startsWith(h)){const t=n.slice(h.length),e=t.indexOf("__");return e<0?null:C(t.slice(0,e))}for(const[t,e]of V)if(n.startsWith(t))return e;return null}o(S,"extractCodexMcpServer");function j(n){return n==="exec_command"?"Bash":n==="apply_patch"?"Edit":n==="update_plan"?"TodoWrite":n==="read_file"?"Read":n==="web_search"?"WebSearch":n==="web_fetch"?"WebFetch":n}o(j,"normalizeCodexToolName");function D(n){if(!n)return{tool_type:null,tool_name:"",mcp_server:null};if(n.startsWith(h)){const s=n.slice(h.length),r=s.indexOf("__");if(r>=0){const i=s.slice(0,r),u=C(i),l=s.slice(r+2);return{tool_type:"mcp",tool_name:R(l),mcp_server:u}}}const t=S(n);if(t!==null&&!n.startsWith(h))return{tool_type:"mcp",tool_name:R(n),mcp_server:t};const e=j(n);return n==="spawn_agent"||n==="wait_agent"||n==="close_agent"?{tool_type:"sub_agent",tool_name:e,mcp_server:null}:{tool_type:null,tool_name:e,mcp_server:null}}o(D,"classifyCodexTool");function K(n,t){if(!n||t===void 0)return;if(n==="apply_patch"){if(typeof t=="string")return{input_size:t.length};if(typeof t=="object"&&t!==null){const r=t,i=r.command??r.input;if(typeof i=="string")return{input_size:i.length}}return{input_size:void 0}}if(typeof t!="object"||t===null)return;const e=t;if(j(n)==="Bash"){const r=e.cmd??e.command,i=typeof r=="string"?A(r):void 0;return{workdir:e.workdir,binary:i}}if(n==="update_plan"){const r=e.explanation,i=e.plan;return{explanation:typeof r=="string"?r:void 0,plan_step_count:Array.isArray(i)?i.length:void 0}}if(n==="spawn_agent"){const r=e.agent_type,i=e.message,u=e.fork_context;return{agent_type:typeof r=="string"?r:void 0,message_size:typeof i=="string"?i.length:void 0,fork_context:typeof u=="boolean"?u:void 0}}if(n==="wait_agent"){const r=e.targets,i=e.timeout_ms;return{target_count:Array.isArray(r)?r.length:void 0,timeout_ms:typeof i=="number"?i:void 0}}if(n==="close_agent"){const r=e.target;return{target:typeof r=="string"?r:void 0}}if(n==="view_image"){const r=e.path,i=e.detail;return{path:typeof r=="string"?r:void 0,detail:typeof i=="string"?i:void 0}}if(n==="write_stdin"){const r=e.session_id,i=e.chars,u=e.yield_time_ms,l=e.max_output_tokens;return{session_id:typeof r=="number"?r:void 0,chars_size:typeof i=="string"?i.length:void 0,yield_time_ms:typeof u=="number"?u:void 0,max_output_tokens:typeof l=="number"?l:void 0}}if(n.startsWith(h)||S(n)!==null){if("_metadata"in e){const{_metadata:r,...i}=e;return i}return e}}o(K,"extractCodexToolInput");function A(n){const t=n.trim();if(!t)return;const e=t.split(/\s+/);for(const s of e)if(!/^[A-Za-z_][A-Za-z0-9_]*=/.test(s)&&s.length>0)return s.split(/[\\/]/).pop()??s}o(A,"extractBashBinary");function E(n){const t=n.split(".");if(t.length!==3)return null;try{const e=Buffer.from(t[1],"base64url").toString("utf-8"),s=JSON.parse(e);return typeof s!="object"||s===null?null:s}catch{return null}}o(E,"decodeJwtPayload");function U(n){if(typeof n=="string"){const t=E(n);return t?{email:t.email,planType:t["https://api.openai.com/auth"]?.chatgpt_plan_type}:{}}if(typeof n=="object"&&n!==null){const t=n;return{email:t.email,planType:t.chatgpt_plan_type}}return{}}o(U,"extractIdTokenFields");function X(n){const t=n??(0,m.join)((0,I.homedir)(),".codex","auth.json");if(!(0,x.existsSync)(t))return{};try{const e=JSON.parse((0,x.readFileSync)(t,"utf-8")),s=e.auth_mode==="chatgpt"||e.auth_mode==="swic"?"subscription":e.auth_mode==="api"?"api":void 0,{email:r,planType:i}=U(e.tokens?.id_token);return{usageType:s,usagePlan:i?.toLowerCase(),userEmail:r}}catch(e){return b.logger.debug(`failed to parse ${t}: ${e}`),{}}}o(X,"resolveCodexUsage");function G(n,t){return n.trim()===`[${t}]`}o(G,"tableHeaderLineExact");function Q(n){const t=n.trim();return/^\[\[?[^\]]+\]\]?$/.test(t)}o(Q,"isAnyTableHeader");function T(n){const e=n.trim().match(/^\[([^[\]]+)\]$/);return e===null?null:e[1]}o(T,"tableHeaderName");function p(n,t){let e=-1;for(let r=0;r<n.length;r+=1)if(G(n[r],t)){e=r;break}if(e<0)return null;let s=n.length;for(let r=e+1;r<n.length;r+=1)if(Q(n[r])){s=r;break}return{startIdx:e,endIdx:s}}o(p,"findTomlSection");function k(n){const t=[...n];for(;t.length>0&&t[t.length-1].trim()==="";)t.pop();return t}o(k,"trimTrailingBlanks");function w(n,t){return n.length===0?t.join(`
|
|
2
2
|
`)+`
|
|
3
3
|
`:n.replace(/\n+$/,"")+`
|
|
4
4
|
|
|
5
5
|
`+t.join(`
|
|
6
6
|
`)+`
|
|
7
7
|
`}o(w,"appendBlockWithSeparator");function Z(n){const t=n.split(`
|
|
8
|
-
`),e=
|
|
9
|
-
`);return
|
|
10
|
-
`)?
|
|
8
|
+
`),e=p(t,"features");if(e===null)return w(n,["[features]","hooks = true"]);const s=t.slice(e.startIdx+1,e.endIdx),r=/^\s*hooks\s*=/;let i=!1;for(let a=0;a<s.length;a+=1)if(r.test(s[a])){s[a]="hooks = true",i=!0;break}i||s.unshift("hooks = true");const u=k(s),g=[...t.slice(0,e.startIdx),t[e.startIdx],...u,...e.endIdx<t.length?[""]:[],...t.slice(e.endIdx)].join(`
|
|
9
|
+
`);return g.endsWith(`
|
|
10
|
+
`)?g:g+`
|
|
11
11
|
`}o(Z,"ensureFeaturesHooksTrue");function q(n){const t=n.split(`
|
|
12
|
-
`),e=
|
|
12
|
+
`),e=p(t,"features");if(e===null)return n;const s=t.slice(e.startIdx+1,e.endIdx),r=/^\s*hooks\s*=\s*true\s*$/,i=s.filter(a=>!r.test(a));if(i.length===s.length)return n;const u=i.some(a=>a.trim().length>0);let l;if(u){const a=k(i);l=[...t.slice(0,e.startIdx),t[e.startIdx],...a,...e.endIdx<t.length?[""]:[],...t.slice(e.endIdx)]}else l=[...t.slice(0,e.startIdx),...t.slice(e.endIdx)];const g=l.join(`
|
|
13
13
|
`).replace(/\n{3,}/g,`
|
|
14
14
|
|
|
15
|
-
`);return
|
|
16
|
-
`)?
|
|
17
|
-
`}o(q,"removeFeaturesHooks");function
|
|
18
|
-
`),e=
|
|
19
|
-
`);return
|
|
20
|
-
`)?
|
|
21
|
-
`}o(
|
|
22
|
-
`),e=
|
|
15
|
+
`);return g.endsWith(`
|
|
16
|
+
`)?g:g+`
|
|
17
|
+
`}o(q,"removeFeaturesHooks");function Y(n){const t=n.split(`
|
|
18
|
+
`),e=p(t,"features.multi_agent_v2");if(e===null)return w(n,["[features.multi_agent_v2]","hide_spawn_agent_metadata = false"]);const s=t.slice(e.startIdx+1,e.endIdx),r=/^\s*hide_spawn_agent_metadata\s*=/;let i=!1;for(let a=0;a<s.length;a+=1)if(r.test(s[a])){s[a]="hide_spawn_agent_metadata = false",i=!0;break}i||s.unshift("hide_spawn_agent_metadata = false");const u=k(s),g=[...t.slice(0,e.startIdx),t[e.startIdx],...u,...e.endIdx<t.length?[""]:[],...t.slice(e.endIdx)].join(`
|
|
19
|
+
`);return g.endsWith(`
|
|
20
|
+
`)?g:g+`
|
|
21
|
+
`}o(Y,"ensureMultiAgentV2SpawnMetadataExposed");function N(n){const t=n.split(`
|
|
22
|
+
`),e=p(t,"features.multi_agent_v2");if(e===null)return n;const s=t.slice(e.startIdx+1,e.endIdx).filter(l=>l.trim().length>0);if(!(s.length===1&&/^\s*hide_spawn_agent_metadata\s*=\s*false\s*$/.test(s[0])))return n;const u=[...t.slice(0,e.startIdx),...t.slice(e.endIdx)].join(`
|
|
23
23
|
`).replace(/\n{3,}/g,`
|
|
24
24
|
|
|
25
25
|
`);return u.endsWith(`
|
|
26
26
|
`)?u:u+`
|
|
27
|
-
`}o(
|
|
28
|
-
`),i=
|
|
27
|
+
`}o(N,"removeMultiAgentV2SpawnMetadata");function nn(n,t,e){const s=`mcp_servers.${t}`,r=n.split(`
|
|
28
|
+
`),i=p(r,s),l=[`[${s}]`,...e];if(i===null)return w(n,l);const g=r.slice(0,i.startIdx),a=r.slice(i.endIdx),d=[...g,...l,...a.length>0?[""]:[],...a].join(`
|
|
29
|
+
`);return d.endsWith(`
|
|
30
|
+
`)?d:d+`
|
|
31
|
+
`}o(nn,"upsertMcpServer");function tn(n,t){const e=`mcp_servers.${t}`,s=`${e}.`,r=n.split(`
|
|
32
|
+
`),i=[];let u=!1,l=!1;for(const d of r){const f=T(d);if(f!==null&&(u=f===e||f.startsWith(s),u)){l=!0;continue}u||i.push(d)}if(!l)return n;const g=[];let a=!1;for(const d of i){const f=d.trim().length===0;f&&a||(g.push(d),a=f)}const c=g.join(`
|
|
29
33
|
`);return c.endsWith(`
|
|
30
|
-
`)?c:c+`
|
|
31
|
-
`}o(
|
|
32
|
-
`),i=
|
|
33
|
-
`);return
|
|
34
|
-
`)
|
|
35
|
-
`}o(
|
|
36
|
-
`),i=
|
|
34
|
+
`)||c.length===0?c:c+`
|
|
35
|
+
`}o(tn,"removeMcpServer");function en(n,t,e){const s=`agents.${t}`,r=n.split(`
|
|
36
|
+
`),i=p(r,s),l=[`[${s}]`,...e];if(i===null)return w(n,l);const g=r.slice(0,i.startIdx),a=r.slice(i.endIdx),d=[...g,...l,...a.length>0?[""]:[],...a].join(`
|
|
37
|
+
`);return d.endsWith(`
|
|
38
|
+
`)?d:d+`
|
|
39
|
+
`}o(en,"upsertAgentsTable");function rn(n,t){const e=`agents.${t}`,s=`${e}.`,r=n.split(`
|
|
40
|
+
`),i=[];let u=!1,l=!1;for(const d of r){const f=T(d);if(f!==null&&(u=f===e||f.startsWith(s),u)){l=!0;continue}u||i.push(d)}if(!l)return n;const g=[];let a=!1;for(const d of i){const f=d.trim().length===0;f&&a||(g.push(d),a=f)}const c=g.join(`
|
|
41
|
+
`);return c.endsWith(`
|
|
42
|
+
`)||c.length===0?c:c+`
|
|
43
|
+
`}o(rn,"removeAgentsTable");function sn(n,t){const e=JSON.stringify(t),s=n.split(`
|
|
44
|
+
`),r=p(s,"sandbox_workspace_write");if(r===null)return w(n,["[sandbox_workspace_write]",`writable_roots = [${e}]`]);const i=s.slice(r.startIdx+1,r.endIdx);if(i.some(d=>d.includes(e)))return n;const u=/^\s*writable_roots\s*=\s*\[(.*)\]\s*$/;let l=!1;for(let d=0;d<i.length;d+=1){const f=i[d].match(u);if(f){const _=f[1].trim();i[d]=`writable_roots = [${_.length===0?e:`${_}, ${e}`}]`,l=!0;break}}if(!l){if(i.some(d=>/^\s*writable_roots\s*=/.test(d)))return b.logger.debug("codex: existing multi-line writable_roots \u2014 leaving as-is; add ~/.ironbee/projects manually if needed"),n;i.unshift(`writable_roots = [${e}]`)}const g=k(i),c=[...s.slice(0,r.startIdx),s[r.startIdx],...g,...r.endIdx<s.length?[""]:[],...s.slice(r.endIdx)].join(`
|
|
37
45
|
`);return c.endsWith(`
|
|
38
46
|
`)?c:c+`
|
|
39
|
-
`}o(
|
|
40
|
-
`),
|
|
41
|
-
`)
|
|
42
|
-
|
|
43
|
-
`
|
|
44
|
-
`)
|
|
47
|
+
`}o(sn,"ensureSandboxWritableRoot");function on(n,t){const e=JSON.stringify(t),s=n.split(`
|
|
48
|
+
`),r=p(s,"sandbox_workspace_write");if(r===null)return n;const i=s.slice(r.startIdx+1,r.endIdx),u=/^\s*writable_roots\s*=\s*\[(.*)\]\s*$/;for(let c=0;c<i.length;c+=1){const d=i[c].match(u);if(d){const f=d[1].split(",").map(_=>_.trim()).filter(_=>_.length>0&&_!==e);f.length===0?i.splice(c,1):i[c]=`writable_roots = [${f.join(", ")}]`;break}}const l=k(i);if(l.length===0){const c=[...s.slice(0,r.startIdx),...s.slice(r.endIdx)].join(`
|
|
49
|
+
`).replace(/\n{3,}/g,`
|
|
50
|
+
|
|
51
|
+
`);return c.endsWith(`
|
|
52
|
+
`)||c.length===0?c:c+`
|
|
53
|
+
`}const a=[...s.slice(0,r.startIdx),s[r.startIdx],...l,...r.endIdx<s.length?[""]:[],...s.slice(r.endIdx)].join(`
|
|
54
|
+
`);return a.endsWith(`
|
|
55
|
+
`)?a:a+`
|
|
56
|
+
`}o(on,"removeSandboxWritableRoot");function ln(n,t){return(0,m.join)(n,".codex","agents",`${t}.toml`)}o(ln,"codexAgentTomlPath");function un(n){for(const t of n.split(`
|
|
57
|
+
`)){const e=t.trim();if(e.startsWith("["))break;const s=e.match(/^model\s*=\s*"([^"]*)"/);if(s&&s[1].length>0)return s[1]}return null}o(un,"extractTomlTopLevelModel");function an(n){const t=[];for(const[e,s]of Object.entries(n))if(s!=null){if(typeof s=="string")t.push(`${e} = ${JSON.stringify(s)}`);else if(typeof s=="number"||typeof s=="boolean")t.push(`${e} = ${s}`);else if(Array.isArray(s)){const r=s.map(i=>typeof i=="string"?JSON.stringify(i):typeof i=="number"||typeof i=="boolean"?String(i):JSON.stringify(i));t.push(`${e} = [${r.join(", ")}]`)}else if(typeof s=="object"){const r=s,i=[];for(const[u,l]of Object.entries(r))l!=null&&(typeof l=="string"?i.push(`${u} = ${JSON.stringify(l)}`):typeof l=="number"||typeof l=="boolean"?i.push(`${u} = ${l}`):i.push(`${u} = ${JSON.stringify(l)}`));t.push(`${e} = { ${i.join(", ")} }`)}}return t}o(an,"tomlBodyFromRecord");const v="<!-- ironbee:start -->",y="<!-- ironbee:end -->";function dn(n,t){const e=`${v}
|
|
45
58
|
${t.trimEnd()}
|
|
46
|
-
${
|
|
59
|
+
${y}`,s=n.indexOf(v),r=n.indexOf(y);if(s>=0&&r>s){const i=n.slice(0,s),u=n.slice(r+y.length);return i+e+u}return n.trim().length===0?e+`
|
|
47
60
|
`:n.trimEnd()+`
|
|
48
61
|
|
|
49
62
|
`+e+`
|
|
50
|
-
`}o(
|
|
63
|
+
`}o(dn,"upsertAgentsMdBlock");function cn(n){const t=n.indexOf(v),e=n.indexOf(y);if(t<0||e<t)return n.trim().length===0?null:n;const s=n.slice(0,t).trimEnd(),r=n.slice(e+y.length).trimStart(),i=s+(s.length>0&&r.length>0?`
|
|
51
64
|
|
|
52
65
|
`:"")+r;return i.trim().length===0?null:i.endsWith(`
|
|
53
66
|
`)?i:i+`
|
|
54
|
-
`}o(
|
|
67
|
+
`}o(cn,"stripAgentsMdBlock");function gn(n){const t=O(n);if(!(0,x.existsSync)(t))return"";try{return(0,x.readFileSync)(t,"utf-8")}catch(e){return b.logger.debug(`failed to read ${t}: ${e}`),""}}o(gn,"readCodexConfigToml");function fn(n,t){const e=O(n);try{(0,x.writeFileSync)(e,t)}catch(s){b.logger.debug(`failed to write ${e}: ${s}`)}}o(fn,"writeCodexConfigToml");function O(n){return(0,m.join)(n,".codex","config.toml")}o(O,"codexConfigTomlPath");function pn(n){return(0,m.join)(n,".codex","hooks.json")}o(pn,"codexHooksJsonPath");function mn(){return(0,m.join)((0,I.homedir)(),".codex","config.toml")}o(mn,"userCodexConfigTomlPath");function xn(){return(0,m.join)((0,I.homedir)(),".codex","hooks.json")}o(xn,"userCodexHooksJsonPath");function _n(n){return(0,m.join)((0,I.homedir)(),".codex","agents",`${n}.toml`)}o(_n,"userCodexAgentTomlPath");0&&(module.exports={AGENTS_MD_END_MARKER,AGENTS_MD_START_MARKER,canonicalizeCodexServerName,canonicalizeCodexToolName,classifyCodexTool,codexAgentTomlPath,codexConfigTomlPath,codexHooksJsonPath,decodeJwtPayload,ensureFeaturesHooksTrue,ensureMultiAgentV2SpawnMetadataExposed,ensureSandboxWritableRoot,extractBashBinary,extractCodexMcpServer,extractCodexToolInput,extractTomlTopLevelModel,findTomlSection,normalizeCodexToolName,parseCodexHookStdin,readCodexConfigToml,removeAgentsTable,removeFeaturesHooks,removeMcpServer,removeMultiAgentV2SpawnMetadata,removeSandboxWritableRoot,resolveCodexUsage,stripAgentsMdBlock,tomlBodyFromRecord,upsertAgentsMdBlock,upsertAgentsTable,upsertMcpServer,userCodexAgentTomlPath,userCodexConfigTomlPath,userCodexHooksJsonPath,writeCodexConfigToml});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var r=Object.defineProperty;var
|
|
1
|
+
"use strict";var r=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var p=(i,o)=>r(i,"name",{value:o,configurable:!0});var S=(i,o)=>{for(var t in o)r(i,t,{get:o[t],enumerable:!0})},v=(i,o,t,n)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of m(o))!l.call(i,s)&&s!==t&&r(i,s,{get:()=>o[s],enumerable:!(n=f(o,s))||n.enumerable});return i};var y=i=>v(r({},"__esModule",{value:!0}),i);var I={};S(I,{run:()=>k});module.exports=y(I);var u=require("../../../hooks/core/activity-end"),e=require("../../../lib/logger"),a=require("../../../lib/output"),c=require("../../../lib/stdin"),d=require("../../../lib/runtime-paths");async function k(i){let o;try{o=JSON.parse((0,c.readStdin)())}catch(g){e.logger.debug(`failed to parse stdin: ${g}`),(0,a.writeAndExit)(JSON.stringify({}),0);return}const t=o.conversation_id??"default",n=(0,d.sessionDir)(i,t),s=`${n}/actions.jsonl`;(0,e.setLogFile)(`${n}/session.log`),await(0,u.runActivityEnd)({sessionDir:n,actionsFile:s,projectDir:i,sessionId:t}),(0,a.writeAndExit)(JSON.stringify({}),0)}p(k,"run");0&&(module.exports={run});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=Object.defineProperty;var
|
|
1
|
+
"use strict";var e=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var g=Object.prototype.hasOwnProperty;var p=(r,o)=>e(r,"name",{value:o,configurable:!0});var l=(r,o)=>{for(var t in o)e(r,t,{get:o[t],enumerable:!0})},S=(r,o,t,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of d(o))!g.call(r,s)&&s!==t&&e(r,s,{get:()=>o[s],enumerable:!(i=f(o,s))||i.enumerable});return r};var v=r=>S(e({},"__esModule",{value:!0}),r);var I={};l(I,{run:()=>b});module.exports=v(I);var a=require("../../../hooks/core/activity"),n=require("../../../lib/logger"),u=require("../../../lib/stdin"),c=require("../../../lib/runtime-paths");async function b(r){let o;try{o=JSON.parse((0,u.readStdin)())}catch(m){n.logger.debug(`failed to parse stdin: ${m}`),process.exit(0)}const t=o.conversation_id??"default",i=(0,c.sessionDir)(r,t);(0,n.setLogFile)(`${i}/session.log`);const s=`${i}/actions.jsonl`;await(0,a.startActivity)({sessionDir:i,actionsFile:s,source:"user_prompt"}),process.exit(0)}p(b,"run");0&&(module.exports={run});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var g=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var p=(t,e)=>g(t,"name",{value:e,configurable:!0});var W=(t,e)=>{for(var o in e)g(t,o,{get:e[o],enumerable:!0})},$=(t,e,o,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of w(e))!I.call(t,i)&&i!==o&&g(t,i,{get:()=>e[i],enumerable:!(n=b(e,i))||n.enumerable});return t};var k=t=>$(g({},"__esModule",{value:!0}),t);var L={};W(L,{run:()=>E});module.exports=k(L);var _=require("fs"),C=require("../../../hooks/core/clear-verdict"),v=require("../../../hooks/core/verification-lifecycle"),m=require("../../../hooks/core/actions"),F=require("../../../hooks/core/session-state"),x=require("../../../hooks/core/tool-use-stash"),c=require("../../../hooks/core/file-diff"),u=require("../../../lib/runtime-paths"),d=require("../../../lib/config"),a=require("../../../lib/logger"),y=require("../../../lib/stdin");function D(t,e){const o=t.tool_name,n=t.tool_input;if(!n)return null;const i=t.tool_use_id?(0,x.consumeToolUseData)(e,t.tool_use_id):null;if(o==="StrReplace"){const s=n.old_string??"",l=n.new_string??"",r=(0,c.diffLineCounts)(s,l);return{tool_name:"StrReplace",operation:"update",lines_added:r.added,lines_removed:r.removed,stash:i}}if(o==="Write"){const s=n.content??n.contents??"",l=i?.file_existed??!1;return{tool_name:"Write",operation:l?"update":"create",lines_added:(0,c.countLines)(s),lines_removed:l?null:0,stash:i}}return o==="Delete"?{tool_name:"Delete",operation:"delete",lines_added:null,lines_removed:null,stash:i}:null}p(D,"deriveChangeFacts");function U(t,e,o,n){const i=o?.prior_content??"";let s;if(e==="delete")s="";else try{s=(0,_.existsSync)(t)?(0,_.readFileSync)(t,"utf-8"):""}catch(r){a.logger.debug(`failed to read post-edit content of ${t} for changeset: ${r}`);return}return(0,c.createUnifiedDiff)(i,s,n)??void 0}p(U,"buildChangeset");async function E(t){let e;try{e=JSON.parse((0,y.readStdin)())}catch(f){a.logger.debug(`failed to parse stdin: ${f}`),process.exit(0)}const o=e.conversation_id??"default";(0,a.setLogFile)((0,u.sessionLogFile)(t,o));const n=e.tool_input?.file_path??e.tool_input?.path;n&&n.endsWith("verdict.json")&&n.replace(/\\/g,"/").startsWith((0,u.sessionsRoot)(t).replace(/\\/g,"/")+"/")&&(a.logger.debug(`skipping clear-verdict: write target is verdict file ${n}`),process.exit(0));const i=(0,d.loadConfig)(t);n&&!(0,d.requiresVerification)(n,i)&&(a.logger.debug(`skipping clear-verdict: file does not require verification (${n})`),process.exit(0)),n||a.logger.warn(`clear-verdict: ${e.tool_name} had no extractable file path (tool_input keys: [${Object.keys(e.tool_input??{}).join(", ")}]) \u2014 recording file_change with empty path so the fix cycle isn't lost`);const s=(0,u.sessionDir)(t,o),l=`${s}/actions.jsonl`,r=D(e,o);r||(a.logger.debug(`skipping clear-verdict: unsupported tool ${e.tool_name}`),process.exit(0));const S=await(0,v.openFixCycleIfFixing)({sessionDir:s,actionsFile:l}),h={...(0,m.baseFields)(l),type:"file_change",timestamp:Date.now(),tool_name:r.tool_name,file_path:n??"",operation:r.operation,lines_added:r.lines_added,lines_removed:r.lines_removed,activity_id:(0,F.getActiveActivityId)(s),fix_id:S};if((0,d.getCaptureFileChangeset)(i)&&n){const f=U(n,r.operation,r.stash,(0,d.getMaxChangesetBytes)(i));f!==void 0&&(h.changeset=f)}await(0,m.appendAction)(l,h),(0,C.runClearVerdict)({verdictFile:`${s}/verdict.json`,sessionDir:s}),process.exit(0)}p(E,"run");0&&(module.exports={run});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var u=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var x=Object.prototype.hasOwnProperty;var h=(o,t)=>u(o,"name",{value:t,configurable:!0});var k=(o,t)=>{for(var i in t)u(o,i,{get:t[i],enumerable:!0})},I=(o,t,i,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of U(t))!x.call(o,s)&&s!==i&&u(o,s,{get:()=>t[s],enumerable:!(e=P(t,s))||e.enumerable});return o};var E=o=>I(u({},"__esModule",{value:!0}),o);var $={};k($,{run:()=>F});module.exports=E($);var c=require("fs"),b=require("../../../hooks/core/actions"),v=require("../../../hooks/core/activity"),C=require("../../../hooks/core/tool-use-stash"),d=require("../../../lib/config"),n=require("../../../lib/logger"),S=require("../../../lib/stdin"),p=require("../../../lib/runtime-paths");async function F(o,t){const i=t?.soft===!0;let e;try{e=JSON.parse((0,S.readStdin)())}catch(r){n.logger.debug(`failed to parse stdin: ${r}`);const l={permission:"allow"};process.stdout.write(JSON.stringify(l)),process.exit(0);return}const s=e.conversation_id??"default";(0,n.setLogFile)((0,p.sessionLogFile)(o,s));const f=(0,p.sessionDir)(o,s),g=`${f}/actions.jsonl`;if(!i&&(0,b.hasToolCallsSinceLastVerdict)(g)){const r={permission:"deny",agent_message:`BLOCKED: You used verification tools (browser-devtools / node-devtools / backend-devtools / android-devtools / terminal-devtools) but did not submit a verdict. You MUST submit a verdict (pass or fail) before editing code.
|
|
2
2
|
|
|
3
3
|
Submit your verdict first:
|
|
4
4
|
echo '{"session_id":"${s}","status":"fail","checks":["..."],"issues":["describe what failed"]}' | ironbee hook submit-verdict
|
|
5
5
|
|
|
6
|
-
Then you can edit code to fix the issues.`};process.stdout.write(JSON.stringify(r)),process.exit(2);return}const a=e.tool_input?.file_path??e.tool_input?.path;if(a&&e.tool_use_id){const r=(0,d.loadConfig)(o),
|
|
6
|
+
Then you can edit code to fix the issues.`};process.stdout.write(JSON.stringify(r)),process.exit(2);return}const a=e.tool_input?.file_path??e.tool_input?.path;if(a&&e.tool_use_id){const r=(0,d.loadConfig)(o),l=(0,d.getCaptureFileChangeset)(r),m=(0,c.existsSync)(a),w=e.tool_name==="Write",T=e.tool_name==="StrReplace"||e.tool_name==="Delete";if(w||T&&l){const _={file_existed:m};if(l&&m)try{_.prior_content=(0,c.readFileSync)(a,"utf-8")}catch(O){n.logger.debug(`failed to pre-read ${a} for changeset capture: ${O}`)}(0,C.stashToolUseData)(s,e.tool_use_id,_)}}await(0,v.startActivity)({sessionDir:f,actionsFile:g,source:"pre_tool_use"});const y={permission:"allow"};process.stdout.write(JSON.stringify(y)),process.exit(0)}h(F,"run");0&&(module.exports={run});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"use strict";var f=Object.defineProperty;var
|
|
1
|
+
"use strict";var f=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames;var j=Object.prototype.hasOwnProperty;var R=(o,t)=>f(o,"name",{value:t,configurable:!0});var J=(o,t)=>{for(var c in t)f(o,c,{get:t[c],enumerable:!0})},L=(o,t,c,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of K(t))!j.call(o,r)&&r!==c&&f(o,r,{get:()=>t[r],enumerable:!(i=F(t,r))||i.enumerable});return o};var D=o=>L(f({},"__esModule",{value:!0}),o);var Y={};J(Y,{run:()=>q});module.exports=D(Y);var S=require("crypto"),e=require("../../../hooks/core/session-state"),I=require("../../../hooks/core/actions"),k=require("../../../hooks/core/activity"),M=require("../../../hooks/core/verification-lifecycle"),O=require("../../../lib/config"),U=require("../../../lib/recording-tools"),E=require("../../../hooks/core/scenario-tools"),p=require("../../../lib/logger"),A=require("../../../lib/stdin"),N=require("../../../lib/runtime-paths");const h={"MCP:bdt_":"browser-devtools","MCP:ndt_":"node-devtools","MCP:bedt_":"backend-devtools","MCP:adt_":"android-devtools","MCP:tdt_":"terminal-devtools"},W="browser-devtools";async function q(o,t){const c=t?.soft===!0;let i;try{i=JSON.parse((0,A.readStdin)())}catch(n){p.logger.debug(`failed to parse stdin: ${n}`);const B={permission:"allow"};process.stdout.write(JSON.stringify(B)),process.exit(0);return}const r=i.conversation_id??"default",s=(0,N.sessionDir)(o,r);(0,p.setLogFile)(`${s}/session.log`);const P=`${s}/actions.jsonl`,g=(0,E.isScenarioTool)(i.tool_name),b=(0,e.getActiveVerificationId)(s);if(!b&&!c&&!g){const n={permission:"deny",agent_message:`BLOCKED: You must start a verification cycle before using devtools tools (browser-devtools / node-devtools / backend-devtools / android-devtools / terminal-devtools).
|
|
2
2
|
|
|
3
3
|
Start verification first:
|
|
4
4
|
echo '{"session_id":"${r}"}' | ironbee hook verification-start
|
|
5
5
|
|
|
6
|
-
Then use the verification tools for the active cycle(s) \u2014 MCP:bdt_* for browser, MCP:ndt_* for node, MCP:bedt_* for backend, MCP:adt_* for android.`};process.stdout.write(JSON.stringify(n)),process.exit(2);return}const m=i.tool_name??"",v=m.startsWith("MCP:")?m.slice(4):"",u=v?(0,
|
|
6
|
+
Then use the verification tools for the active cycle(s) \u2014 MCP:bdt_* for browser, MCP:ndt_* for node, MCP:bedt_* for backend, MCP:adt_* for android, MCP:tdt_* for terminal.`};process.stdout.write(JSON.stringify(n)),process.exit(2);return}const m=i.tool_name??"",v=m.startsWith("MCP:")?m.slice(4):"",u=v?(0,U.recordingToolsForBareTool)(v):null;if(!c&&!g&&u!==null&&(0,e.isRecordingRequired)(s)&&!(0,e.isRecordingActive)(s)&&v!==u.startTool){const n={permission:"deny",agent_message:`BLOCKED: Recording is required but not started.
|
|
7
7
|
|
|
8
8
|
1. Start recording NOW:
|
|
9
9
|
Use MCP:${u.startTool}
|
|
@@ -12,4 +12,4 @@ Then use the verification tools for the active cycle(s) \u2014 MCP:bdt_* for bro
|
|
|
12
12
|
|
|
13
13
|
3. **Stop recording BEFORE submitting verdict:**
|
|
14
14
|
Use MCP:${u.stopTool}
|
|
15
|
-
submit-verdict will reject with "recording is still active" if you skip this.`};process.stdout.write(JSON.stringify(n)),process.exit(2);return}await(0,k.startActivity)({sessionDir:s,actionsFile:
|
|
15
|
+
submit-verdict will reject with "recording is still active" if you skip this.`};process.stdout.write(JSON.stringify(n)),process.exit(2);return}await(0,k.startActivity)({sessionDir:s,actionsFile:P,source:"pre_tool_use"});let d=b;c&&!d&&!g&&(d=(await(0,M.startVerification)({sessionId:r,sessionDir:s,actionsFile:P,recordingEnabled:!1})).verificationId);const $=(0,e.getActiveTraceId)(s),_=(0,e.getActiveActivityId)(s),y=(0,I.resolveProjectName)(o),C=[`prj:${y}`,`sid:${r}`];_&&C.push(`aid:${_}`),d&&C.push(`vid:${d}`);const V=`ironbee=${C.join(";")}`,a=(0,O.loadConfig)(o),T={...i.tool_input??{}},l={projectName:y,sessionId:r,activityId:_,verificationId:d,traceId:$,traceState:V,toolCallId:(0,S.randomUUID)()};i.tool_use_id&&(l.toolUseId=i.tool_use_id),l.mcpServer=(()=>{for(const n of Object.keys(h))if(m.startsWith(n))return h[n];return W})();const w=(0,e.getUserEmail)(s);w&&(l.userEmail=w),a.collector?.url&&(l.collectorUrl=a.collector.url),a.collector?.oauthToken?l.collectorOAuthToken=a.collector.oauthToken:a.collector?.apiKey&&(l.collectorApiKey=a.collector.apiKey),T._metadata=l;const x={permission:"allow",updated_input:T};process.stdout.write(JSON.stringify(x)),process.exit(0)}R(q,"run");0&&(module.exports={run});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var a=Object.defineProperty;var
|
|
1
|
+
"use strict";var a=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var c=(n,s)=>a(n,"name",{value:s,configurable:!0});var v=(n,s)=>{for(var i in s)a(n,i,{get:s[i],enumerable:!0})},A=(n,s,i,e)=>{if(s&&typeof s=="object"||typeof s=="function")for(let o of w(s))!_.call(n,o)&&o!==i&&a(n,o,{get:()=>s[o],enumerable:!(e=y(s,o))||e.enumerable});return n};var E=n=>A(a({},"__esModule",{value:!0}),n);var C={};v(C,{run:()=>b});module.exports=E(C);var t=require("../../../hooks/core/actions"),p=require("../../../hooks/core/activity"),m=require("../../../hooks/core/session-state"),r=require("../../../lib/logger"),u=require("../../../lib/stdin"),l=require("../../../queue"),f=require("../../../lib/runtime-paths");async function b(n){let s;try{s=JSON.parse((0,u.readStdin)())}catch(S){r.logger.debug(`failed to parse stdin: ${S}`),process.exit(0)}const i=s.conversation_id??"default",e=(0,f.sessionDir)(n,i),o=`${e}/actions.jsonl`;(0,r.setLogFile)(`${e}/session.log`),await(0,m.closeOpenCycles)(e,o,"session_end"),await(0,p.endActivity)({sessionDir:e,actionsFile:o});const d=Date.now(),g={...(0,t.baseFields)(o),type:"session_end",timestamp:d,session_id:i,duration:(0,t.findDurationSinceLastAction)(o,"session_start",d),reason:s.reason};await(0,t.appendAction)(o,g),await(0,l.flushSynchronously)(n,i),r.logger.debug(`session-end: ${i}`),process.exit(0)}c(b,"run");0&&(module.exports={run});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var u=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var m=(s,i)=>u(s,"name",{value:i,configurable:!0});var _=(s,i)=>{for(var t in i)u(s,t,{get:i[t],enumerable:!0})},w=(s,i,t,n)=>{if(i&&typeof i=="object"||typeof i=="function")for(let e of E(i))!I.call(s,e)&&e!==t&&u(s,e,{get:()=>i[e],enumerable:!(n=O(i,e))||n.enumerable});return s};var k=s=>w(u({},"__esModule",{value:!0}),s);var N={};_(N,{run:()=>x});module.exports=k(N);var a=require("../../../hooks/core/actions"),o=require("../../../hooks/core/session-state"),f=require("../../../lib/config"),c=require("../../../lib/logger"),d=require("../../../lib/output"),g=require("../../../lib/stdin"),S=require("../../../lib/telemetry"),r=require("../../../lib/runtime-paths");async function x(s){let i;try{i=JSON.parse((0,g.readStdin)())}catch(y){c.logger.debug(`failed to parse stdin: ${y}`),(0,d.writeAndExit)(JSON.stringify({}),0);return}const t=i.conversation_id??"default",n=(0,r.sessionActionsFile)(s,t);(0,c.setLogFile)((0,r.sessionLogFile)(s,t));const e=(0,r.sessionDir)(s,t);(0,o.setProjectDir)(e,s),(0,o.setUserEmail)(e,i.user_email??void 0);const p={...(0,a.baseFields)(n),type:"session_start",timestamp:Date.now(),session_id:t,client:"cursor",source:"startup"};await(0,a.appendAction)(n,p),await(0,o.reconcileSessionState)(e,n,a.appendAction);const l=(0,f.getVerificationEnabled)((0,f.loadConfig)(s));if(await(0,S.trackSessionStart)("cursor",t,l,s),c.logger.debug(`session-start: ${t}`),!l){(0,d.writeAndExit)(JSON.stringify({}),0);return}const b=JSON.stringify({session_id:t,status:"pass",checks:["form submits successfully","new item appears in list"]}),v=JSON.stringify({session_id:t,status:"fail",checks:["form renders","submit button unresponsive"],issues:["button click handler not firing","TypeError in console"]}),h={additional_context:`IRONBEE VERIFICATION \u2014 SESSION ACTIVE
|
|
2
2
|
Session ID: ${t}
|
|
3
3
|
|
|
4
4
|
You MUST verify all code changes in the browser before completing any task.
|
|
@@ -7,11 +7,11 @@ After EVERY verification attempt, you MUST submit a verdict BEFORE doing anythin
|
|
|
7
7
|
- If fail \u2192 submit fail verdict FIRST, then fix. Do NOT skip to fixing code without submitting.
|
|
8
8
|
|
|
9
9
|
Submit via terminal:
|
|
10
|
-
echo '${
|
|
10
|
+
echo '${b}' | ironbee hook submit-verdict
|
|
11
11
|
|
|
12
12
|
On fail (issues is required):
|
|
13
|
-
echo '${
|
|
13
|
+
echo '${v}' | ironbee hook submit-verdict
|
|
14
14
|
|
|
15
15
|
Required fields: session_id, status, checks
|
|
16
16
|
On fail, include: issues (array of strings describing what failed)
|
|
17
|
-
On pass after a previous fail, include: fixes (array of strings describing what was fixed)`};(0,
|
|
17
|
+
On pass after a previous fail, include: fixes (array of strings describing what was fixed)`};(0,d.writeAndExit)(JSON.stringify(h),0)}m(x,"run");0&&(module.exports={run});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var d=Object.defineProperty;var
|
|
1
|
+
"use strict";var d=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var c=(o,t)=>d(o,"name",{value:t,configurable:!0});var C=(o,t)=>{for(var r in t)d(o,r,{get:t[r],enumerable:!0})},P=(o,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of $(t))!v.call(o,n)&&n!==r&&d(o,n,{get:()=>t[n],enumerable:!(i=k(t,n))||i.enumerable});return o};var R=o=>P(d({},"__esModule",{value:!0}),o);var W={};C(W,{run:()=>M});module.exports=R(W);var T=require("../../../hooks/core/actions"),b=require("../../../hooks/core/activity"),m=require("../../../hooks/core/session-state"),E=require("../../../lib/config"),s=require("../../../lib/logger"),p=require("../../../lib/output"),O=require("../../../lib/stdin"),a=require("../../../queue"),f=require("../util"),A=require("../../../lib/runtime-paths");const D="bdt_",L="ndt_",S="bedt_",F="adt_",J="tdt_";async function M(o){let t;try{t=JSON.parse((0,O.readStdin)())}catch(u){s.logger.debug(`failed to parse stdin: ${u}`),(0,p.writeAndExit)(JSON.stringify({}),0);return}const r=t.conversation_id??"default",i=(0,A.sessionDir)(o,r),n=`${i}/actions.jsonl`;(0,s.setLogFile)(`${i}/session.log`),(0,m.getActiveActivityId)(i)===void 0&&await(0,b.startActivity)({sessionDir:i,actionsFile:n,source:"pre_tool_use"});const _=t.tool_name??"unknown",N=Date.now(),w=t.tool_input&&typeof t.tool_input=="object"&&!Array.isArray(t.tool_input)?{...t.tool_input,_metadata:void 0}:t.tool_input,I=(0,m.getActiveActivityId)(i),e=(0,f.classifyTool)(_,t.tool_input);if(e.tool_type==="mcp"&&(e.tool_name.startsWith(D)||e.tool_name.startsWith(L)||e.tool_name.startsWith(S)||e.tool_name.startsWith(F)||e.tool_name.startsWith(J))){s.logger.debug(`track-action-monitor: skipped devtools tool ${_}`),(0,p.writeAndExit)(JSON.stringify({}),0);return}const g=typeof t.error_message=="string"&&t.error_message.length>0?t.error_message:void 0;let l;if(g){const u=[];t.failure_type&&u.push(t.failure_type),t.is_interrupt&&u.push("interrupted"),l=`${u.length>0?`${u.join(",")}: `:""}${g}`}const h={...(0,T.baseFields)(n),type:"tool_call",timestamp:N,tool_name:e.tool_name,tool_type:e.tool_type,tool_use_id:t.tool_use_id,tool_input:(0,f.extractCursorToolInput)(_,w),tool_input_size:y(t.tool_input),tool_response:l?void 0:t.tool_output,tool_response_size:y(l?void 0:t.tool_output),activity_id:I,duration:typeof t.duration=="number"?t.duration:null,mcp_server:e.mcp_server,error:l};x(o,r,h),s.logger.debug(`track-action-monitor: ${_}${l?" (failed)":""}`),(0,p.writeAndExit)(JSON.stringify({}),0)}c(M,"run");function x(o,t,r){if(!(0,E.isJobQueueEnabled)(o))return;const i={...r};delete i.tool_response;try{(0,a.submit)(o,t,a.SEND_EVENT_TYPE,i)}catch(n){if(n instanceof a.JobTooLargeError){s.logger.debug(`track-action-monitor: wire event too large for ${r.tool_name}; dropping`);return}s.logger.debug(`track-action-monitor: failed to submit ${r.tool_name}: ${n instanceof Error?n.message:n}`)}}c(x,"submitEvent");function y(o){if(o==null)return 0;try{const t=typeof o=="string"?o:JSON.stringify(o);return t===void 0?0:Buffer.byteLength(t,"utf-8")}catch{return 0}}c(y,"byteSize");0&&(module.exports={run});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var T=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var q=Object.prototype.hasOwnProperty;var g=(o,t)=>T(o,"name",{value:t,configurable:!0});var G=(o,t)=>{for(var l in t)T(o,l,{get:t[l],enumerable:!0})},H=(o,t,l,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Y(t))!q.call(o,r)&&r!==l&&T(o,r,{get:()=>t[r],enumerable:!(i=Q(t,r))||i.enumerable});return o};var Z=o=>H(T({},"__esModule",{value:!0}),o);var at={};G(at,{run:()=>st});module.exports=Z(at);var p=require("../../../hooks/core/actions"),y=require("../../../hooks/core/nested-tools"),a=require("../../../hooks/core/session-state"),F=require("../../../hooks/core/verification-context"),E=require("../../../lib/config"),s=require("../../../lib/logger"),R=require("../../../lib/recording-tools"),P=require("../../../lib/output"),W=require("../../../lib/stdin"),f=require("../../../queue"),b=require("../util"),M=require("../../../lib/runtime-paths");const N="bdt_",$="ndt_",D="bedt_",L="adt_",x="tdt_",tt="browser-devtools",ot="node-devtools",nt="backend-devtools",et="android-devtools",it="terminal-devtools";function rt(o){return o.startsWith(D)?nt:o.startsWith(L)?et:o.startsWith(x)?it:o.startsWith(N)?tt:o.startsWith($)?ot:null}g(rt,"resolveServerByPrefix");async function st(o){let t;try{t=JSON.parse((0,W.readStdin)())}catch(n){s.logger.debug(`failed to parse stdin: ${n}`),process.stdout.write(JSON.stringify({})),process.exit(0);return}const l=t.conversation_id??"default",i=(0,M.sessionDir)(o,l),r=`${i}/actions.jsonl`;(0,s.setLogFile)(`${i}/session.log`);const v=t.tool_name??"unknown",A=Date.now(),k=t.tool_input&&typeof t.tool_input=="object"&&!Array.isArray(t.tool_input)?{...t.tool_input,_metadata:void 0}:t.tool_input,w=(0,a.getActiveActivityId)(i),O=(0,a.getActiveVerificationId)(i),I=(0,a.getActiveTraceId)(i),e=(0,b.classifyTool)(v,t.tool_input),B=e.tool_type==="mcp"&&e.tool_name.startsWith(N),J=e.tool_type==="mcp"&&e.tool_name.startsWith($),X=e.tool_type==="mcp"&&e.tool_name.startsWith(D),z=e.tool_type==="mcp"&&e.tool_name.startsWith(L),U=e.tool_type==="mcp"&&e.tool_name.startsWith(x),m=B||J||X||z||U,c=e.tool_type==="mcp"?rt(e.tool_name)??e.mcp_server:e.mcp_server,K=m?k:(0,b.extractCursorToolInput)(v,k),C=typeof t.error_message=="string"&&t.error_message.length>0?t.error_message:void 0;let u;if(C){const n=[];t.failure_type&&n.push(t.failure_type),t.is_interrupt&&n.push("interrupted"),u=`${n.length>0?`${n.join(",")}: `:""}${C}`}const S={...(0,p.baseFields)(r),type:"tool_call",timestamp:A,tool_name:e.tool_name,tool_type:e.tool_type,tool_use_id:t.tool_use_id,tool_input:K,tool_input_size:V(t.tool_input),tool_response:u?void 0:t.tool_output,tool_response_size:V(u?void 0:t.tool_output),activity_id:w,verification_id:O,trace_id:I,duration:typeof t.duration=="number"?t.duration:null,mcp_server:c,error:u};if(m){await(0,p.appendAction)(r,S);const n=(0,R.recordingToolsForServer)(c);n!==null&&(e.tool_name===n.startTool?((0,a.setRecordingActive)(i,!0),s.logger.debug(`track-action: recording started (${n.cycle})`)):e.tool_name===n.stopTool&&((0,a.setRecordingActive)(i,!1),s.logger.debug(`track-action: recording stopped (${n.cycle})`)))}else lt(o,l,S);if(s.logger.debug(`track-action: ${v}${u?" (failed)":""}`),m&&c!==null&&e.tool_name===(0,y.executeToolBareName)(c)&&!u){const n=(0,y.extractNestedToolCalls)(t.tool_input,c),_=(0,R.recordingToolsForServer)(c);for(const d of n){_!==null&&(d.name===_.startTool?((0,a.setRecordingActive)(i,!0),s.logger.debug(`track-action (nested): recording started (${_.cycle})`)):d.name===_.stopTool&&((0,a.setRecordingActive)(i,!1),s.logger.debug(`track-action (nested): recording stopped (${_.cycle})`)));const j={...(0,p.baseFields)(r),type:"tool_call",timestamp:d.startTime??A,tool_name:d.name,tool_type:"mcp",tool_input:d.args,activity_id:w,verification_id:O,trace_id:I,duration:d.duration??null,mcp_server:c,nested:!0,parent_tool_use_id:t.tool_use_id};await(0,p.appendAction)(r,j),s.logger.debug(`track-action (nested): ${d.name}`)}}const h={};if(m)try{const n=(0,F.buildVerificationContextOnceForCycle)({projectDir:o,sessionId:l,sessionDir:i,activeVerificationId:O,config:(0,E.loadConfig)(o)});n.length>0&&(h.additional_context=n)}catch(n){s.logger.debug(`track-action: verification-context injection skipped: ${n instanceof Error?n.message:n}`)}(0,P.writeAndExit)(JSON.stringify(h),0)}g(st,"run");function lt(o,t,l){if(!(0,E.isJobQueueEnabled)(o))return;const i={...l};delete i.tool_response;try{(0,f.submit)(o,t,f.SEND_EVENT_TYPE,i)}catch(r){if(r instanceof f.JobTooLargeError){s.logger.debug(`track-action: wire event too large for ${l.tool_name}; dropping`);return}s.logger.debug(`track-action: failed to submit ${l.tool_name}: ${r instanceof Error?r.message:r}`)}}g(lt,"submitEvent");function V(o){if(o==null)return 0;try{const t=typeof o=="string"?o:JSON.stringify(o);return t===void 0?0:Buffer.byteLength(t,"utf-8")}catch{return 0}}g(V,"byteSize");0&&(module.exports={run});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var e=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var p=(o,t)=>e(o,"name",{value:t,configurable:!0});var I=(o,t)=>{for(var s in t)e(o,s,{get:t[s],enumerable:!0})},_=(o,t,s,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of y(t))!C.call(o,n)&&n!==s&&e(o,n,{get:()=>t[n],enumerable:!(i=w(t,n))||i.enumerable});return o};var H=o=>_(e({},"__esModule",{value:!0}),o);var h={};I(h,{run:()=>O});module.exports=H(h);var d=require("../../../hooks/core/verify-gate"),k=require("../../../hooks/core/activity"),a=require("../../../lib/config"),u=require("../../../lib/logger"),l=require("../../../lib/output"),S=require("../../../lib/stdin"),g=require("../../../queue"),f=require("../../../lib/runtime-paths");async function O(o){let t;try{t=JSON.parse((0,S.readStdin)())}catch(v){u.logger.debug(`failed to parse stdin: ${v}`),(0,l.writeAndExit)(JSON.stringify({}),0);return}const s=t.conversation_id??"default";(0,u.setLogFile)((0,f.sessionLogFile)(o,s));const i=(0,f.sessionDir)(o,s),n=`${i}/actions.jsonl`,m=(0,a.loadConfig)(o),r=await(0,d.runVerifyGate)({sessionId:s,sessionDir:i,actionsFile:n,verdictFile:`${i}/verdict.json`,maxRetries:(0,a.getMaxRetries)(m),config:m,projectDir:o}),c={};r.action==="allow"&&await(0,k.endActivity)({sessionDir:i,actionsFile:n}),r.action==="block"&&r.message&&(c.followup_message=r.message),(0,g.flushInBackground)(o,s),(0,g.flushStragglersInBackground)(o,s),(0,l.writeAndExit)(JSON.stringify(c),0)}p(O,"run");0&&(module.exports={run});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var $=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var z=Object.getOwnPropertyNames;var Q=Object.prototype.hasOwnProperty;var v=(c,o)=>$(c,"name",{value:o,configurable:!0});var X=(c,o)=>{for(var e in o)$(c,e,{get:o[e],enumerable:!0})},Y=(c,o,e,s)=>{if(o&&typeof o=="object"||typeof o=="function")for(let t of z(o))!Q.call(c,t)&&t!==e&&$(c,t,{get:()=>o[t],enumerable:!(s=x(o,t))||s.enumerable});return c};var Z=c=>Y($({},"__esModule",{value:!0}),c);var no={};X(no,{CursorClient:()=>io});module.exports=Z(no);var i=require("fs"),l=require("path"),p=require("../../lib/logger"),n=require("../../lib/output"),T=require("../../lib/fs-prune"),N=require("./hooks/verify-gate"),P=require("./hooks/clear-verdict"),L=require("./hooks/track-action"),B=require("./hooks/track-action-monitor"),V=require("./hooks/session-start"),J=require("./hooks/require-verdict"),D=require("./hooks/require-verification"),F=require("./hooks/activity-start"),U=require("./hooks/activity-end"),K=require("./hooks/session-end"),a=require("../../lib/config"),q=require("../../lib/platform-section"),j=require("../../lib/gitignore");const y="browser-devtools",b="node-devtools",h="backend-devtools",S="android-devtools",oo="ironbee",O=["ironbee-manage-scenario","ironbee-search-scenario","ironbee-sync-scenario"];function eo(c){return(0,l.join)(__dirname,"..",c,"platforms")}v(eo,"platformsDirFor");function _(c){const o=Object.keys(c);if(o.length===0)return!0;if(o.length===1&&o[0]==="mcpServers"){const e=c.mcpServers;return e===void 0||Object.keys(e).length===0}return!1}v(_,"isMcpConfigEmpty");const E="ironbee",I=[`${y}:*`,`${b}:*`,`${h}:*`,`${S}:*`];function ro(c){const o=new Set(["mcpAllowlist","terminalAllowlist"]);for(const t of Object.keys(c))if(!o.has(t))return!1;const e=c.mcpAllowlist??[],s=c.terminalAllowlist??[];return e.length===0&&s.length===0}v(ro,"isPermissionsEmpty");function so(c){const o=new Set(["version","hooks"]);for(const e of Object.keys(c))if(!o.has(e))return!1;return Object.keys(c.hooks??{}).length===0}v(so,"isCursorHooksEmpty");function d(c){return n.pc.dim(c)}v(d,"cursorColor");class io{constructor(){this.name="cursor"}static{v(this,"CursorClient")}detect(o){return(0,i.existsSync)((0,l.join)(o,".cursor"))}resolveProjectDir(){return process.env.CURSOR_PROJECT_DIR??process.env.IRONBEE_PROJECT_DIR??process.cwd()}install(o,e){const s=e??(0,a.loadConfig)(o),t=(0,a.getVerificationMode)(s),r=t!=="monitor";this.cleanupArtifacts(o),(0,j.ensureIronBeeGitignored)(o);const u=(0,l.join)(o,".cursor"),g=(0,l.join)(u,"rules"),f=(0,l.join)(u,"skills");(0,i.mkdirSync)(g,{recursive:!0}),(0,i.mkdirSync)(f,{recursive:!0});const m=(0,l.join)(u,"hooks.json");if(this.mergeHooksConfig(m,t),r){if(t==="enforce"){const C=(0,l.join)(f,"ironbee-verification.md"),w=(0,i.readFileSync)((0,l.join)(__dirname,"skills","ironbee-verification.md"),"utf-8");(0,i.writeFileSync)(C,w);const H=(0,l.join)(g,"ironbee-verification.mdc"),W=(0,i.readFileSync)((0,l.join)(__dirname,"rules","ironbee-verification.mdc"),"utf-8");(0,i.writeFileSync)(H,W),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} skill ${n.pc.dim("\u2192")} ${n.pc.dim(C)}`),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} rule ${n.pc.dim("\u2192")} ${n.pc.dim(H)}`)}const k=(0,l.join)(f,"ironbee-verify");(0,i.mkdirSync)(k,{recursive:!0});const A=(0,l.join)(k,"SKILL.md"),G=(0,i.readFileSync)((0,l.join)(__dirname,"commands","ironbee-verify","SKILL.md"),"utf-8");(0,i.writeFileSync)(A,G);for(const C of O){const w=(0,l.join)(f,C);(0,i.mkdirSync)(w,{recursive:!0}),(0,i.writeFileSync)((0,l.join)(w,"SKILL.md"),(0,i.readFileSync)((0,l.join)(__dirname,"commands",C,"SKILL.md"),"utf-8"))}const M=(0,l.join)(u,"mcp.json");this.writeMcpConfig(M,o);const R=(0,l.join)(u,"permissions.json");this.writePermissionsConfig(R,o),(0,q.syncPlatformSectionsToConfig)(o,eo),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} hooks ${n.pc.dim("\u2192")} ${n.pc.dim(m)}`),t==="assist"&&console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} ${n.pc.yellow("assist mode")} (verification.auto: false) \u2014 manual /ironbee-verify only, no enforcement`),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} command ${n.pc.dim("\u2192")} ${n.pc.dim(A)}`),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} mcp ${n.pc.dim("\u2192")} ${n.pc.dim(M)}`),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} perms ${n.pc.dim("\u2192")} ${n.pc.dim(R)}`),console.log(),console.log(` ${n.pc.yellow("\u26A0")} ${n.pc.yellow("Cursor requires manual steps:")}`),console.log(` ${n.pc.yellow("1.")} Restart Cursor to load the new hooks and MCP config`),console.log(` ${n.pc.yellow("2.")} Go to ${n.pc.bold("Settings \u2192 Tools & MCP")} and verify ${n.pc.bold("browser-devtools")} is enabled`),console.log(` ${n.pc.yellow("3.")} If the server shows as enabled but tools are unavailable, toggle it off and on`)}else console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} ${n.pc.yellow("monitoring-only mode")} (verification.enable: false)`),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} hooks ${n.pc.dim("\u2192")} ${n.pc.dim(m)}`),console.log(),console.log(` ${n.pc.yellow("\u26A0")} Restart Cursor to load the new hook config`)}uninstall(o){this.cleanupArtifacts(o),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} removed hooks, skill, rule, command, and MCP`),console.log(),console.log(` ${n.pc.yellow("\u26A0")} Restart Cursor to apply changes`)}cleanupArtifacts(o){const e=(0,l.join)(o,".cursor"),s=(0,l.join)(e,"skills","ironbee-verification.md"),t=(0,l.join)(e,"rules","ironbee-verification.mdc"),r=(0,l.join)(e,"skills","ironbee-analyze","SKILL.md"),u=(0,l.join)(e,"skills","ironbee-verify","SKILL.md");this.removeFile(s),this.removeFile(t),this.removeFile(r),this.removeFile(u);for(const k of O)this.removeFile((0,l.join)(e,"skills",k,"SKILL.md"));this.removeFile((0,l.join)(e,"skills","ironbee-run-scenario","SKILL.md"));const g=(0,l.join)(e,"hooks.json");this.removeIronBeeHooks(g),this.maybeDeleteEmptyHooks(g);const f=(0,l.join)(e,"mcp.json");this.removeMcpServer(f);const m=(0,l.join)(e,"permissions.json");this.removePermissionsEntries(m),(0,T.pruneEmptyDirs)(e)}maybeDeleteEmptyHooks(o){if((0,i.existsSync)(o))try{const e=JSON.parse((0,i.readFileSync)(o,"utf-8"));so(e)&&(0,i.unlinkSync)(o)}catch(e){p.logger.debug(`failed to inspect ${o} for emptiness: ${e}`)}}async runVerifyGate(o){await(0,N.run)(o)}async runClearVerdict(o){await(0,P.run)(o)}async runTrackAction(o){await(0,L.run)(o)}async runSessionStart(o){await(0,V.run)(o)}async runRequireVerdict(o,e){await(0,J.run)(o,e)}async runRequireVerification(o,e){await(0,D.run)(o,e)}async runActivityStart(o){await(0,F.run)(o)}async runActivityEnd(o){await(0,U.run)(o)}async runTrackActionMonitor(o){await(0,B.run)(o)}async runSessionEnd(o){await(0,K.run)(o)}async runTrackActionPre(o){}isIronBeeHook(o){return o.command.includes(oo)}mergeHooksConfig(o,e){const s=e!=="monitor",t=e==="assist"?" --soft":"";let r={version:1,hooks:{}};if((0,i.existsSync)(o))try{r=JSON.parse((0,i.readFileSync)(o,"utf-8")),r.hooks||(r.hooks={})}catch(f){p.logger.debug(`failed to parse ${o}: ${f}`),r={version:1,hooks:{}}}for(const f of Object.keys(r.hooks)){const m=r.hooks[f].filter(k=>!this.isIronBeeHook(k));m.length===0?delete r.hooks[f]:r.hooks[f]=m}r.hooks.sessionStart||(r.hooks.sessionStart=[]),r.hooks.sessionStart.push({command:"ironbee hook session-start --client cursor"}),r.hooks.beforeSubmitPrompt||(r.hooks.beforeSubmitPrompt=[]),r.hooks.beforeSubmitPrompt.push({command:"ironbee hook activity-start --client cursor"}),s&&(r.hooks.preToolUse||(r.hooks.preToolUse=[]),r.hooks.preToolUse.push({command:`ironbee hook require-verification --client cursor${t}`,matcher:"MCP:(bdt|ndt|bedt|adt)_.*",failClosed:e==="enforce"}),r.hooks.preToolUse.push({command:`ironbee hook require-verdict --client cursor${t}`,matcher:"Write|StrReplace|Delete",failClosed:e==="enforce"}),r.hooks.postToolUse||(r.hooks.postToolUse=[]),r.hooks.postToolUse.push({command:"ironbee hook clear-verdict --client cursor",matcher:"Write|StrReplace|Delete"})),r.hooks.postToolUse||(r.hooks.postToolUse=[]);const u=s?"ironbee hook track-action --client cursor":"ironbee hook track-action-monitor --client cursor";r.hooks.postToolUse.push({command:u}),r.hooks.postToolUseFailure||(r.hooks.postToolUseFailure=[]),r.hooks.postToolUseFailure.push({command:u}),r.hooks.stop||(r.hooks.stop=[]);const g=e==="enforce"?"ironbee hook verify-gate --client cursor":"ironbee hook activity-end --client cursor";r.hooks.stop.push({command:g}),r.hooks.sessionEnd||(r.hooks.sessionEnd=[]),r.hooks.sessionEnd.push({command:"ironbee hook session-end --client cursor"}),r.version=1,(0,i.writeFileSync)(o,JSON.stringify(r,null,2))}removeIronBeeHooks(o){if((0,i.existsSync)(o))try{const e=JSON.parse((0,i.readFileSync)(o,"utf-8"));if(!e.hooks)return;for(const s of Object.keys(e.hooks)){const t=e.hooks[s].filter(r=>!this.isIronBeeHook(r));t.length===0?delete e.hooks[s]:e.hooks[s]=t}(0,i.writeFileSync)(o,JSON.stringify(e,null,2))}catch(e){p.logger.debug(`failed to remove hooks from ${o}: ${e}`)}}removeMcpServer(o){if((0,i.existsSync)(o))try{const e=JSON.parse((0,i.readFileSync)(o,"utf-8"));let s=!1;e.mcpServers&&e.mcpServers[y]&&(delete e.mcpServers[y],s=!0),e.mcpServers&&e.mcpServers[b]&&(delete e.mcpServers[b],s=!0),e.mcpServers&&e.mcpServers[h]&&(delete e.mcpServers[h],s=!0),e.mcpServers&&e.mcpServers[S]&&(delete e.mcpServers[S],s=!0),_(e)?(0,i.unlinkSync)(o):s&&(0,i.writeFileSync)(o,JSON.stringify(e,null,2))}catch(e){p.logger.debug(`failed to remove MCP server from ${o}: ${e}`)}}removeFile(o){(0,i.existsSync)(o)&&(0,i.unlinkSync)(o)}writeMcpConfig(o,e){let s={mcpServers:{}};if((0,i.existsSync)(o))try{s=JSON.parse((0,i.readFileSync)(o,"utf-8")),s.mcpServers||(s.mcpServers={})}catch(r){p.logger.debug(`failed to parse ${o}: ${r}`),s={mcpServers:{}}}const t=(0,a.loadConfig)(e);if((0,a.isCycleEnabled)(t,"browser")?s.mcpServers[y]=(0,a.getMcpServerEntry)(e):delete s.mcpServers[y],(0,a.isCycleEnabled)(t,"node")?s.mcpServers[b]=(0,a.getNodeDevToolsMcpEntry)(e):delete s.mcpServers[b],(0,a.isCycleEnabled)(t,"backend")?s.mcpServers[h]=(0,a.getBackendDevToolsMcpEntry)(e):delete s.mcpServers[h],(0,a.isCycleEnabled)(t,"android")?s.mcpServers[S]=(0,a.getAndroidDevToolsMcpEntry)(e):delete s.mcpServers[S],_(s)){try{(0,i.rmSync)(o,{force:!0})}catch(r){p.logger.debug(`failed to remove empty ${o}: ${r}`)}return}(0,i.writeFileSync)(o,JSON.stringify(s,null,2))}writePermissionsConfig(o,e){let s={};if((0,i.existsSync)(o))try{s=JSON.parse((0,i.readFileSync)(o,"utf-8"))}catch(m){p.logger.debug(`failed to parse ${o}: ${m}`),s={}}const t=(0,a.loadConfig)(e),r=[];(0,a.isCycleEnabled)(t,"browser")&&r.push(`${y}:*`),(0,a.isCycleEnabled)(t,"node")&&r.push(`${b}:*`),(0,a.isCycleEnabled)(t,"backend")&&r.push(`${h}:*`),(0,a.isCycleEnabled)(t,"android")&&r.push(`${S}:*`);const u=new Set(I),g=(s.mcpAllowlist??[]).filter(m=>!u.has(m));for(const m of r)g.includes(m)||g.push(m);g.length>0?s.mcpAllowlist=g:delete s.mcpAllowlist;const f=(s.terminalAllowlist??[]).filter(m=>m!==E);f.push(E),s.terminalAllowlist=f,(0,i.writeFileSync)(o,JSON.stringify(s,null,2))}removePermissionsEntries(o){if((0,i.existsSync)(o))try{const e=JSON.parse((0,i.readFileSync)(o,"utf-8")),s=new Set(I);Array.isArray(e.mcpAllowlist)&&(e.mcpAllowlist=e.mcpAllowlist.filter(t=>!s.has(t)),e.mcpAllowlist.length===0&&delete e.mcpAllowlist),Array.isArray(e.terminalAllowlist)&&(e.terminalAllowlist=e.terminalAllowlist.filter(t=>t!==E),e.terminalAllowlist.length===0&&delete e.terminalAllowlist),ro(e)?(0,i.unlinkSync)(o):(0,i.writeFileSync)(o,JSON.stringify(e,null,2))}catch(e){p.logger.debug(`failed to remove permissions from ${o}: ${e}`)}}}0&&(module.exports={CursorClient});
|
|
1
|
+
"use strict";var E=Object.defineProperty;var z=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var X=Object.prototype.hasOwnProperty;var v=(a,o)=>E(a,"name",{value:o,configurable:!0});var Y=(a,o)=>{for(var e in o)E(a,e,{get:o[e],enumerable:!0})},Z=(a,o,e,s)=>{if(o&&typeof o=="object"||typeof o=="function")for(let t of Q(o))!X.call(a,t)&&t!==e&&E(a,t,{get:()=>o[t],enumerable:!(s=z(o,t))||s.enumerable});return a};var oo=a=>Z(E({},"__esModule",{value:!0}),a);var to={};Y(to,{CursorClient:()=>no});module.exports=oo(to);var i=require("fs"),l=require("path"),p=require("../../lib/logger"),n=require("../../lib/output"),N=require("../../lib/fs-prune"),P=require("./hooks/verify-gate"),L=require("./hooks/clear-verdict"),B=require("./hooks/track-action"),V=require("./hooks/track-action-monitor"),J=require("./hooks/session-start"),D=require("./hooks/require-verdict"),F=require("./hooks/require-verification"),U=require("./hooks/activity-start"),K=require("./hooks/activity-end"),q=require("./hooks/session-end"),c=require("../../lib/config"),j=require("../../lib/platform-section"),G=require("../../lib/gitignore");const y="browser-devtools",h="node-devtools",S="backend-devtools",b="android-devtools",C="terminal-devtools",eo="ironbee",O=["ironbee-manage-scenario","ironbee-search-scenario","ironbee-sync-scenario"];function ro(a){return(0,l.join)(__dirname,"..",a,"platforms")}v(ro,"platformsDirFor");function I(a){const o=Object.keys(a);if(o.length===0)return!0;if(o.length===1&&o[0]==="mcpServers"){const e=a.mcpServers;return e===void 0||Object.keys(e).length===0}return!1}v(I,"isMcpConfigEmpty");const A="ironbee",T=[`${y}:*`,`${h}:*`,`${S}:*`,`${b}:*`,`${C}:*`];function so(a){const o=new Set(["mcpAllowlist","terminalAllowlist"]);for(const t of Object.keys(a))if(!o.has(t))return!1;const e=a.mcpAllowlist??[],s=a.terminalAllowlist??[];return e.length===0&&s.length===0}v(so,"isPermissionsEmpty");function io(a){const o=new Set(["version","hooks"]);for(const e of Object.keys(a))if(!o.has(e))return!1;return Object.keys(a.hooks??{}).length===0}v(io,"isCursorHooksEmpty");function d(a){return n.pc.dim(a)}v(d,"cursorColor");class no{constructor(){this.name="cursor"}static{v(this,"CursorClient")}detect(o){return(0,i.existsSync)((0,l.join)(o,".cursor"))}resolveProjectDir(){return process.env.CURSOR_PROJECT_DIR??process.env.IRONBEE_PROJECT_DIR??process.cwd()}install(o,e){const s=e??(0,c.loadConfig)(o),t=(0,c.getVerificationMode)(s),r=t!=="monitor";this.cleanupArtifacts(o),(0,G.ensureIronBeeGitignored)(o);const u=(0,l.join)(o,".cursor"),g=(0,l.join)(u,"rules"),f=(0,l.join)(u,"skills");(0,i.mkdirSync)(g,{recursive:!0}),(0,i.mkdirSync)(f,{recursive:!0});const m=(0,l.join)(u,"hooks.json");if(this.mergeHooksConfig(m,t),r){if(t==="enforce"){const w=(0,l.join)(f,"ironbee-verification.md"),$=(0,i.readFileSync)((0,l.join)(__dirname,"skills","ironbee-verification.md"),"utf-8");(0,i.writeFileSync)(w,$);const H=(0,l.join)(g,"ironbee-verification.mdc"),x=(0,i.readFileSync)((0,l.join)(__dirname,"rules","ironbee-verification.mdc"),"utf-8");(0,i.writeFileSync)(H,x),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} skill ${n.pc.dim("\u2192")} ${n.pc.dim(w)}`),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} rule ${n.pc.dim("\u2192")} ${n.pc.dim(H)}`)}const k=(0,l.join)(f,"ironbee-verify");(0,i.mkdirSync)(k,{recursive:!0});const M=(0,l.join)(k,"SKILL.md"),W=(0,i.readFileSync)((0,l.join)(__dirname,"commands","ironbee-verify","SKILL.md"),"utf-8");(0,i.writeFileSync)(M,W);for(const w of O){const $=(0,l.join)(f,w);(0,i.mkdirSync)($,{recursive:!0}),(0,i.writeFileSync)((0,l.join)($,"SKILL.md"),(0,i.readFileSync)((0,l.join)(__dirname,"commands",w,"SKILL.md"),"utf-8"))}const R=(0,l.join)(u,"mcp.json");this.writeMcpConfig(R,o);const _=(0,l.join)(u,"permissions.json");this.writePermissionsConfig(_,o),(0,j.syncPlatformSectionsToConfig)(o,ro),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} hooks ${n.pc.dim("\u2192")} ${n.pc.dim(m)}`),t==="assist"&&console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} ${n.pc.yellow("assist mode")} (verification.auto: false) \u2014 manual /ironbee-verify only, no enforcement`),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} command ${n.pc.dim("\u2192")} ${n.pc.dim(M)}`),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} mcp ${n.pc.dim("\u2192")} ${n.pc.dim(R)}`),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} perms ${n.pc.dim("\u2192")} ${n.pc.dim(_)}`),console.log(),console.log(` ${n.pc.yellow("\u26A0")} ${n.pc.yellow("Cursor requires manual steps:")}`),console.log(` ${n.pc.yellow("1.")} Restart Cursor to load the new hooks and MCP config`),console.log(` ${n.pc.yellow("2.")} Go to ${n.pc.bold("Settings \u2192 Tools & MCP")} and verify ${n.pc.bold("browser-devtools")} is enabled`),console.log(` ${n.pc.yellow("3.")} If the server shows as enabled but tools are unavailable, toggle it off and on`)}else console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} ${n.pc.yellow("monitoring-only mode")} (verification.enable: false)`),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} hooks ${n.pc.dim("\u2192")} ${n.pc.dim(m)}`),console.log(),console.log(` ${n.pc.yellow("\u26A0")} Restart Cursor to load the new hook config`)}uninstall(o){this.cleanupArtifacts(o),console.log(` ${n.pc.dim("\u2192")} ${d("[cursor]")} removed hooks, skill, rule, command, and MCP`),console.log(),console.log(` ${n.pc.yellow("\u26A0")} Restart Cursor to apply changes`)}cleanupArtifacts(o){const e=(0,l.join)(o,".cursor"),s=(0,l.join)(e,"skills","ironbee-verification.md"),t=(0,l.join)(e,"rules","ironbee-verification.mdc"),r=(0,l.join)(e,"skills","ironbee-analyze","SKILL.md"),u=(0,l.join)(e,"skills","ironbee-verify","SKILL.md");this.removeFile(s),this.removeFile(t),this.removeFile(r),this.removeFile(u);for(const k of O)this.removeFile((0,l.join)(e,"skills",k,"SKILL.md"));this.removeFile((0,l.join)(e,"skills","ironbee-run-scenario","SKILL.md"));const g=(0,l.join)(e,"hooks.json");this.removeIronBeeHooks(g),this.maybeDeleteEmptyHooks(g);const f=(0,l.join)(e,"mcp.json");this.removeMcpServer(f);const m=(0,l.join)(e,"permissions.json");this.removePermissionsEntries(m),(0,N.pruneEmptyDirs)(e)}maybeDeleteEmptyHooks(o){if((0,i.existsSync)(o))try{const e=JSON.parse((0,i.readFileSync)(o,"utf-8"));io(e)&&(0,i.unlinkSync)(o)}catch(e){p.logger.debug(`failed to inspect ${o} for emptiness: ${e}`)}}async runVerifyGate(o){await(0,P.run)(o)}async runClearVerdict(o){await(0,L.run)(o)}async runTrackAction(o){await(0,B.run)(o)}async runSessionStart(o){await(0,J.run)(o)}async runRequireVerdict(o,e){await(0,D.run)(o,e)}async runRequireVerification(o,e){await(0,F.run)(o,e)}async runActivityStart(o){await(0,U.run)(o)}async runActivityEnd(o){await(0,K.run)(o)}async runTrackActionMonitor(o){await(0,V.run)(o)}async runSessionEnd(o){await(0,q.run)(o)}async runTrackActionPre(o){}isIronBeeHook(o){return o.command.includes(eo)}mergeHooksConfig(o,e){const s=e!=="monitor",t=e==="assist"?" --soft":"";let r={version:1,hooks:{}};if((0,i.existsSync)(o))try{r=JSON.parse((0,i.readFileSync)(o,"utf-8")),r.hooks||(r.hooks={})}catch(f){p.logger.debug(`failed to parse ${o}: ${f}`),r={version:1,hooks:{}}}for(const f of Object.keys(r.hooks)){const m=r.hooks[f].filter(k=>!this.isIronBeeHook(k));m.length===0?delete r.hooks[f]:r.hooks[f]=m}r.hooks.sessionStart||(r.hooks.sessionStart=[]),r.hooks.sessionStart.push({command:"ironbee hook session-start --client cursor"}),r.hooks.beforeSubmitPrompt||(r.hooks.beforeSubmitPrompt=[]),r.hooks.beforeSubmitPrompt.push({command:"ironbee hook activity-start --client cursor"}),s&&(r.hooks.preToolUse||(r.hooks.preToolUse=[]),r.hooks.preToolUse.push({command:`ironbee hook require-verification --client cursor${t}`,matcher:"MCP:(bdt|ndt|bedt|adt|tdt)_.*",failClosed:e==="enforce"}),r.hooks.preToolUse.push({command:`ironbee hook require-verdict --client cursor${t}`,matcher:"Write|StrReplace|Delete",failClosed:e==="enforce"}),r.hooks.postToolUse||(r.hooks.postToolUse=[]),r.hooks.postToolUse.push({command:"ironbee hook clear-verdict --client cursor",matcher:"Write|StrReplace|Delete"})),r.hooks.postToolUse||(r.hooks.postToolUse=[]);const u=s?"ironbee hook track-action --client cursor":"ironbee hook track-action-monitor --client cursor";r.hooks.postToolUse.push({command:u}),r.hooks.postToolUseFailure||(r.hooks.postToolUseFailure=[]),r.hooks.postToolUseFailure.push({command:u}),r.hooks.stop||(r.hooks.stop=[]);const g=e==="enforce"?"ironbee hook verify-gate --client cursor":"ironbee hook activity-end --client cursor";r.hooks.stop.push({command:g}),r.hooks.sessionEnd||(r.hooks.sessionEnd=[]),r.hooks.sessionEnd.push({command:"ironbee hook session-end --client cursor"}),r.version=1,(0,i.writeFileSync)(o,JSON.stringify(r,null,2))}removeIronBeeHooks(o){if((0,i.existsSync)(o))try{const e=JSON.parse((0,i.readFileSync)(o,"utf-8"));if(!e.hooks)return;for(const s of Object.keys(e.hooks)){const t=e.hooks[s].filter(r=>!this.isIronBeeHook(r));t.length===0?delete e.hooks[s]:e.hooks[s]=t}(0,i.writeFileSync)(o,JSON.stringify(e,null,2))}catch(e){p.logger.debug(`failed to remove hooks from ${o}: ${e}`)}}removeMcpServer(o){if((0,i.existsSync)(o))try{const e=JSON.parse((0,i.readFileSync)(o,"utf-8"));let s=!1;e.mcpServers&&e.mcpServers[y]&&(delete e.mcpServers[y],s=!0),e.mcpServers&&e.mcpServers[h]&&(delete e.mcpServers[h],s=!0),e.mcpServers&&e.mcpServers[S]&&(delete e.mcpServers[S],s=!0),e.mcpServers&&e.mcpServers[b]&&(delete e.mcpServers[b],s=!0),e.mcpServers&&e.mcpServers[C]&&(delete e.mcpServers[C],s=!0),I(e)?(0,i.unlinkSync)(o):s&&(0,i.writeFileSync)(o,JSON.stringify(e,null,2))}catch(e){p.logger.debug(`failed to remove MCP server from ${o}: ${e}`)}}removeFile(o){(0,i.existsSync)(o)&&(0,i.unlinkSync)(o)}writeMcpConfig(o,e){let s={mcpServers:{}};if((0,i.existsSync)(o))try{s=JSON.parse((0,i.readFileSync)(o,"utf-8")),s.mcpServers||(s.mcpServers={})}catch(r){p.logger.debug(`failed to parse ${o}: ${r}`),s={mcpServers:{}}}const t=(0,c.loadConfig)(e);if((0,c.isCycleEnabled)(t,"browser")?s.mcpServers[y]=(0,c.getMcpServerEntry)(e):delete s.mcpServers[y],(0,c.isCycleEnabled)(t,"node")?s.mcpServers[h]=(0,c.getNodeDevToolsMcpEntry)(e):delete s.mcpServers[h],(0,c.isCycleEnabled)(t,"backend")?s.mcpServers[S]=(0,c.getBackendDevToolsMcpEntry)(e):delete s.mcpServers[S],(0,c.isCycleEnabled)(t,"android")?s.mcpServers[b]=(0,c.getAndroidDevToolsMcpEntry)(e):delete s.mcpServers[b],(0,c.isCycleEnabled)(t,"terminal")?s.mcpServers[C]=(0,c.getTerminalDevToolsMcpEntry)(e):delete s.mcpServers[C],I(s)){try{(0,i.rmSync)(o,{force:!0})}catch(r){p.logger.debug(`failed to remove empty ${o}: ${r}`)}return}(0,i.writeFileSync)(o,JSON.stringify(s,null,2))}writePermissionsConfig(o,e){let s={};if((0,i.existsSync)(o))try{s=JSON.parse((0,i.readFileSync)(o,"utf-8"))}catch(m){p.logger.debug(`failed to parse ${o}: ${m}`),s={}}const t=(0,c.loadConfig)(e),r=[];(0,c.isCycleEnabled)(t,"browser")&&r.push(`${y}:*`),(0,c.isCycleEnabled)(t,"node")&&r.push(`${h}:*`),(0,c.isCycleEnabled)(t,"backend")&&r.push(`${S}:*`),(0,c.isCycleEnabled)(t,"android")&&r.push(`${b}:*`),(0,c.isCycleEnabled)(t,"terminal")&&r.push(`${C}:*`);const u=new Set(T),g=(s.mcpAllowlist??[]).filter(m=>!u.has(m));for(const m of r)g.includes(m)||g.push(m);g.length>0?s.mcpAllowlist=g:delete s.mcpAllowlist;const f=(s.terminalAllowlist??[]).filter(m=>m!==A);f.push(A),s.terminalAllowlist=f,(0,i.writeFileSync)(o,JSON.stringify(s,null,2))}removePermissionsEntries(o){if((0,i.existsSync)(o))try{const e=JSON.parse((0,i.readFileSync)(o,"utf-8")),s=new Set(T);Array.isArray(e.mcpAllowlist)&&(e.mcpAllowlist=e.mcpAllowlist.filter(t=>!s.has(t)),e.mcpAllowlist.length===0&&delete e.mcpAllowlist),Array.isArray(e.terminalAllowlist)&&(e.terminalAllowlist=e.terminalAllowlist.filter(t=>t!==A),e.terminalAllowlist.length===0&&delete e.terminalAllowlist),so(e)?(0,i.unlinkSync)(o):(0,i.writeFileSync)(o,JSON.stringify(e,null,2))}catch(e){p.logger.debug(`failed to remove permissions from ${o}: ${e}`)}}}0&&(module.exports={CursorClient});
|
|
@@ -18,6 +18,7 @@ If the project has android verification enabled (`ironbee android enable` once a
|
|
|
18
18
|
4. **Pick an evidence path** for the changed code:
|
|
19
19
|
- **Device-evidence** (proves the change is visible / functional): drive UI (`MCP:adt_interaction_tap` / `MCP:adt_interaction_input-text` / `MCP:adt_interaction_swipe`) → screenshot (`MCP:adt_content_take-screenshot`) → UI snapshot (`MCP:adt_a11y_take-ui-snapshot`). **STOP and visually analyze the screenshot** — readability, layout, cut-off content, expected state rendered; the snapshot reports structure, the screenshot shows what the user actually sees. Both are MANDATORY on this path.
|
|
20
20
|
- **Log-evidence** (proves the changed code path executed): `MCP:adt_o11y_log-read` or `MCP:adt_o11y_log-follow`. Confirm expected log lines present AND no FATAL/crash from the app package.
|
|
21
|
+
- **Network-evidence** (proves a network/API change behaved correctly): `MCP:adt_o11y_get-http-requests` — forward-looking, so start capture, drive the app to trigger traffic, then read again; confirm the expected request(s)/status. Auxiliary (NOT gate evidence): `MCP:adt_o11y_new-trace-id` pins a correlation root; `MCP:adt_stub_*` mocks/intercepts responses for setup.
|
|
21
22
|
5. **If recording was started, stop it now** — `MCP:adt_content_stop-recording`. submit-verdict rejects with `"recording is still active"` when this step is skipped.
|
|
22
23
|
6. **Submit verdict** — platform-agnostic, just status + checks (+ issues/fixes).
|
|
23
24
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<!-- Terminal verification is ENABLED for this project. -->
|
|
2
|
+
|
|
3
|
+
## Terminal Mode (when `terminal.verifyPatterns` matches an edited file)
|
|
4
|
+
|
|
5
|
+
> **Precondition: the change must actually have terminal-observable behavior.** If the edited code is not reachable from a CLI / REPL / shell / full-screen TUI, this section does NOT apply — `MCP:tdt_*` tools drive a program through a PTY. Just do browser verification.
|
|
6
|
+
|
|
7
|
+
If the project has terminal verification enabled (`ironbee terminal enable` once at setup) and your edits touch matching paths, the stop hook also enforces a terminal cycle. The same `verification-start` covers both cycles; one platform-agnostic verdict covers both.
|
|
8
|
+
|
|
9
|
+
### Mode behavior (terminal cycle)
|
|
10
|
+
- **default** (no arg or `default`): exercise only the CLI flows / commands your diff touched.
|
|
11
|
+
- **full**: exercise every CLI command / flow reachable from files matching `terminal.verifyPatterns`.
|
|
12
|
+
- `visual` / `functional`: browser-only modes; terminal cycle behaves as `default` when they are passed.
|
|
13
|
+
|
|
14
|
+
### Steps (run within step 3 of the Universal steps above)
|
|
15
|
+
1. **Pick an evidence path** for the changed code:
|
|
16
|
+
- **Run-evidence** (a one-shot command proves the change works): `MCP:tdt_pty_run` with the command line — it returns the full output AND the exit code in one call. Confirm the output is what the change should produce AND the exit code is expected (`0` for success, or the specific non-zero code an error/flag path returns). A command that prints the right text but exits non-zero is a fail.
|
|
17
|
+
- **Interactive-evidence** (driving a REPL / shell / full-screen TUI proves the change is live):
|
|
18
|
+
- Spawn the program: `MCP:tdt_pty_start` → returns a `paneId`.
|
|
19
|
+
- Drive input: `MCP:tdt_interaction_send-keys` (tmux key syntax — `Enter`, `C-c`, `Up`, `Tab`) or `MCP:tdt_interaction_send-text` (literal text).
|
|
20
|
+
- **Synchronize, don't guess delays**: `MCP:tdt_sync_wait-for` blocks until the expected output appears.
|
|
21
|
+
- Capture: `MCP:tdt_content_capture` — `mode: stream` for line-oriented programs (REPLs, shells; pass an incremental `since` cursor to read only new lines), `mode: screen` for full-screen TUIs (rendered screen buffer). Confirm it shows the expected result.
|
|
22
|
+
- Stop the pane: `MCP:tdt_pty_stop`.
|
|
23
|
+
- Auxiliary (NOT gate evidence): `MCP:tdt_sync_wait-for-idle` waits until output stops changing; `MCP:tdt_content_get-cursor` reports cursor position; `MCP:tdt_pty_resize` / `MCP:tdt_pty_signal` / `MCP:tdt_pty_list` manage panes.
|
|
24
|
+
2. **Submit verdict** — platform-agnostic, just status + checks (+ issues/fixes).
|
|
25
|
+
|
|
26
|
+
### Verdict (platform-agnostic)
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"session_id": "...",
|
|
30
|
+
"status": "pass",
|
|
31
|
+
"checks": ["`mycli --json` emits valid JSON and exits 0", "REPL `:help` lists the new command"]
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For a multi-cycle pass, both browser and terminal pass criteria must hold.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Default Mode (terminal cycle)
|
|
40
|
+
|
|
41
|
+
Focus on the CLI flows or commands your diff touched — not the entire program.
|
|
42
|
+
|
|
43
|
+
### 1. Study the changes
|
|
44
|
+
1. Run `git diff --name-only` and `git diff --name-only HEAD~1`
|
|
45
|
+
2. **Ignore `.ironbee/`, `.claude/`, `.cursor/`** — tool config, not application code
|
|
46
|
+
3. **Read the full diff** for every terminal-facing file in scope — note new commands, changed flags / args, new output formats, changed exit codes, new REPL / TUI states
|
|
47
|
+
4. Before running, identify: which command / subcommand / REPL state is affected? Which invocation exercises it? What output and exit code should it now produce?
|
|
48
|
+
|
|
49
|
+
### 2. Verify in a PTY
|
|
50
|
+
- **Run-evidence**: run the affected command via `MCP:tdt_pty_run` — confirm the output matches the change AND the exit code is correct
|
|
51
|
+
- **Interactive-evidence**: spawn the program, drive the affected flow with `send-keys` / `send-text`, `wait-for` the expected output, then capture it — the captured output must show the expected result after your change
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Full Mode (`/ironbee-verify full`, terminal cycle)
|
|
56
|
+
|
|
57
|
+
Verify every CLI command / flow reachable from files matching `terminal.verifyPatterns`, not just the changed files. Do NOT run `git diff` or scope to recent changes.
|
|
58
|
+
|
|
59
|
+
- Run every command / subcommand in scope
|
|
60
|
+
- Exercise at least one happy-path invocation AND one error-path invocation (bad flag / missing arg) per command, confirming both output and exit code
|
|
61
|
+
- For REPL / TUI surfaces, drive each affected state and capture the rendered output
|