@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.
Files changed (125) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/analytics/claude/emit.js +1 -1
  3. package/dist/analytics/claude/state.js +1 -1
  4. package/dist/analytics/codex/events-emit.js +2 -2
  5. package/dist/analytics/codex/subagent-transcripts.js +3 -3
  6. package/dist/clients/claude/agents/ironbee-scenario.md +4 -1
  7. package/dist/clients/claude/agents/ironbee-verifier.md +21 -3
  8. package/dist/clients/claude/hooks/activity-end.js +1 -1
  9. package/dist/clients/claude/hooks/activity-start.js +1 -1
  10. package/dist/clients/claude/hooks/clear-verdict.js +1 -1
  11. package/dist/clients/claude/hooks/require-verdict.js +2 -2
  12. package/dist/clients/claude/hooks/require-verification.js +4 -4
  13. package/dist/clients/claude/hooks/session-end.js +1 -1
  14. package/dist/clients/claude/hooks/session-start.js +4 -4
  15. package/dist/clients/claude/hooks/session-status.js +2 -2
  16. package/dist/clients/claude/hooks/subagent-start.js +1 -1
  17. package/dist/clients/claude/hooks/subagent-stop.js +1 -1
  18. package/dist/clients/claude/hooks/track-action-monitor.js +1 -1
  19. package/dist/clients/claude/hooks/track-action.js +1 -1
  20. package/dist/clients/claude/hooks/verify-gate.js +4 -4
  21. package/dist/clients/claude/index.js +4 -4
  22. package/dist/clients/claude/platforms/scenario.android.md +1 -0
  23. package/dist/clients/claude/platforms/scenario.terminal.md +26 -0
  24. package/dist/clients/claude/platforms/skill.android.md +4 -0
  25. package/dist/clients/claude/platforms/skill.browser.md +1 -1
  26. package/dist/clients/claude/platforms/skill.terminal.md +62 -0
  27. package/dist/clients/claude/process-analytics.js +1 -1
  28. package/dist/clients/claude/statusline-toggle.js +2 -2
  29. package/dist/clients/codex/agents/ironbee-scenario.md +3 -0
  30. package/dist/clients/codex/agents/ironbee-verifier.md +20 -2
  31. package/dist/clients/codex/commands/ironbee-manage-scenario/SKILL.main.md +3 -0
  32. package/dist/clients/codex/commands/ironbee-search-scenario/SKILL.main.md +3 -0
  33. package/dist/clients/codex/commands/ironbee-sync-scenario/SKILL.main.md +3 -0
  34. package/dist/clients/codex/commands/ironbee-verify/SKILL.main.md +3 -0
  35. package/dist/clients/codex/hooks/activity-end.js +1 -1
  36. package/dist/clients/codex/hooks/activity-start.js +1 -1
  37. package/dist/clients/codex/hooks/clear-verdict.js +3 -3
  38. package/dist/clients/codex/hooks/require-verdict.js +2 -2
  39. package/dist/clients/codex/hooks/require-verification.js +3 -3
  40. package/dist/clients/codex/hooks/session-start.js +3 -3
  41. package/dist/clients/codex/hooks/subagent-start.js +1 -1
  42. package/dist/clients/codex/hooks/subagent-stop.js +1 -1
  43. package/dist/clients/codex/hooks/track-action-monitor.js +1 -1
  44. package/dist/clients/codex/hooks/track-action-pre.js +1 -1
  45. package/dist/clients/codex/hooks/track-action.js +1 -1
  46. package/dist/clients/codex/hooks/verify-gate.js +1 -1
  47. package/dist/clients/codex/index.js +2 -2
  48. package/dist/clients/codex/platforms/command-verify.android.md +1 -0
  49. package/dist/clients/codex/platforms/command-verify.terminal.md +61 -0
  50. package/dist/clients/codex/platforms/rule.android.md +2 -1
  51. package/dist/clients/codex/platforms/rule.terminal.md +31 -0
  52. package/dist/clients/codex/platforms/scenario.android.md +1 -0
  53. package/dist/clients/codex/platforms/scenario.terminal.md +36 -0
  54. package/dist/clients/codex/platforms/skill.android.md +4 -0
  55. package/dist/clients/codex/platforms/skill.browser.md +1 -1
  56. package/dist/clients/codex/platforms/skill.terminal.md +57 -0
  57. package/dist/clients/codex/process-analytics.js +2 -2
  58. package/dist/clients/codex/rules/ironbee-verification.main.md +3 -0
  59. package/dist/clients/codex/skills/ironbee-verification.main.md +3 -0
  60. package/dist/clients/codex/thread-map.js +1 -1
  61. package/dist/clients/codex/util.js +44 -31
  62. package/dist/clients/cursor/commands/ironbee-manage-scenario/SKILL.md +3 -0
  63. package/dist/clients/cursor/commands/ironbee-search-scenario/SKILL.md +3 -0
  64. package/dist/clients/cursor/commands/ironbee-sync-scenario/SKILL.md +3 -0
  65. package/dist/clients/cursor/commands/ironbee-verify/SKILL.md +3 -0
  66. package/dist/clients/cursor/hooks/activity-end.js +1 -1
  67. package/dist/clients/cursor/hooks/activity-start.js +1 -1
  68. package/dist/clients/cursor/hooks/clear-verdict.js +1 -1
  69. package/dist/clients/cursor/hooks/require-verdict.js +2 -2
  70. package/dist/clients/cursor/hooks/require-verification.js +3 -3
  71. package/dist/clients/cursor/hooks/session-end.js +1 -1
  72. package/dist/clients/cursor/hooks/session-start.js +4 -4
  73. package/dist/clients/cursor/hooks/track-action-monitor.js +1 -1
  74. package/dist/clients/cursor/hooks/track-action.js +1 -1
  75. package/dist/clients/cursor/hooks/verify-gate.js +1 -1
  76. package/dist/clients/cursor/index.js +1 -1
  77. package/dist/clients/cursor/platforms/command-verify.android.md +1 -0
  78. package/dist/clients/cursor/platforms/command-verify.terminal.md +61 -0
  79. package/dist/clients/cursor/platforms/rule.android.md +2 -1
  80. package/dist/clients/cursor/platforms/rule.terminal.md +31 -0
  81. package/dist/clients/cursor/platforms/scenario.android.md +1 -0
  82. package/dist/clients/cursor/platforms/scenario.terminal.md +29 -0
  83. package/dist/clients/cursor/platforms/skill.android.md +4 -0
  84. package/dist/clients/cursor/platforms/skill.browser.md +1 -1
  85. package/dist/clients/cursor/platforms/skill.terminal.md +54 -0
  86. package/dist/clients/cursor/rules/ironbee-verification.mdc +3 -0
  87. package/dist/clients/cursor/skills/ironbee-verification.md +9 -0
  88. package/dist/commands/config.js +2 -2
  89. package/dist/commands/hook.js +10 -10
  90. package/dist/commands/import.js +3 -3
  91. package/dist/commands/install.js +1 -1
  92. package/dist/commands/process-job-file.js +1 -1
  93. package/dist/commands/queue.js +16 -16
  94. package/dist/commands/scenario.js +1 -1
  95. package/dist/commands/status.js +1 -1
  96. package/dist/commands/terminal.js +1 -0
  97. package/dist/commands/uninstall.js +1 -1
  98. package/dist/commands/verify.js +2 -2
  99. package/dist/hooks/core/actions.js +7 -7
  100. package/dist/hooks/core/session-state.js +1 -1
  101. package/dist/hooks/core/verification-context.js +19 -15
  102. package/dist/hooks/core/verify-gate.js +25 -20
  103. package/dist/import/claude/events/tool-call.js +1 -1
  104. package/dist/import/codex/events/tool-call.js +1 -1
  105. package/dist/import/marker.js +2 -2
  106. package/dist/import/skip.js +1 -1
  107. package/dist/index.js +1 -1
  108. package/dist/lib/config.js +1 -1
  109. package/dist/lib/install-version.js +1 -1
  110. package/dist/lib/platform-section.js +5 -4
  111. package/dist/lib/runtime-paths.js +1 -0
  112. package/dist/lib/scenario-staleness.js +1 -1
  113. package/dist/otel/claude/daemon/process.js +1 -1
  114. package/dist/otel/claude/daemon/reprocess.js +1 -1
  115. package/dist/otel/claude/daemon/response-usage.js +2 -2
  116. package/dist/queue/drain.js +1 -1
  117. package/dist/queue/flush.js +1 -1
  118. package/dist/queue/paths.js +1 -1
  119. package/dist/queue/process-file.js +2 -2
  120. package/dist/queue/spawn.js +1 -1
  121. package/dist/tui/config/schema.js +1 -1
  122. package/dist/tui/platforms/area.js +2 -2
  123. package/dist/tui/queue/read.js +4 -4
  124. package/dist/tui/sessions/read.js +2 -2
  125. package/package.json +1 -1
@@ -1,54 +1,67 @@
1
- "use strict";var k=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var o=(n,t)=>k(n,"name",{value:t,configurable:!0});var M=(n,t)=>{for(var e in t)k(n,e,{get:t[e],enumerable:!0})},P=(n,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of L(t))!W.call(n,r)&&r!==e&&k(n,r,{get:()=>t[r],enumerable:!(s=E(t,r))||s.enumerable});return n};var J=n=>P(k({},"__esModule",{value:!0}),n);var mn={};M(mn,{AGENTS_MD_END_MARKER:()=>x,AGENTS_MD_START_MARKER:()=>I,canonicalizeCodexServerName:()=>v,canonicalizeCodexToolName:()=>C,classifyCodexTool:()=>V,codexAgentTomlPath:()=>rn,codexConfigTomlPath:()=>T,codexHooksJsonPath:()=>cn,decodeJwtPayload:()=>A,ensureFeaturesHooksTrue:()=>Z,ensureMultiAgentV2SpawnMetadataExposed:()=>Q,extractBashBinary:()=>O,extractCodexMcpServer:()=>S,extractCodexToolInput:()=>D,extractTomlTopLevelModel:()=>sn,findTomlSection:()=>_,normalizeCodexToolName:()=>R,parseCodexHookStdin:()=>B,readCodexConfigToml:()=>ln,removeAgentsTable:()=>en,removeFeaturesHooks:()=>q,removeMcpServer:()=>nn,removeMultiAgentV2SpawnMetadata:()=>Y,resolveCodexUsage:()=>U,stripAgentsMdBlock:()=>an,tomlBodyFromRecord:()=>on,upsertAgentsMdBlock:()=>un,upsertAgentsTable:()=>tn,upsertMcpServer:()=>N,userCodexAgentTomlPath:()=>pn,userCodexConfigTomlPath:()=>gn,userCodexHooksJsonPath:()=>fn,writeCodexConfigToml:()=>dn});module.exports=J(mn);var m=require("fs"),b=require("os"),p=require("path"),y=require("../../lib/logger");function B(n){try{return JSON.parse(n)}catch(t){return y.logger.debug(`failed to parse Codex hook stdin: ${t}`),{}}}o(B,"parseCodexHookStdin");const h="mcp__",z={browser_devtools:"browser-devtools",node_devtools:"node-devtools",backend_devtools:"backend-devtools",android_devtools:"android-devtools"},H=["bdt_","ndt_","bedt_","adt_"];function v(n){return z[n]??n}o(v,"canonicalizeCodexServerName");function C(n){if(!H.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(C,"canonicalizeCodexToolName");const F=[["bdt_","browser-devtools"],["ndt_","node-devtools"],["bedt_","backend-devtools"],["adt_","android-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:v(t.slice(0,e))}for(const[t,e]of F)if(n.startsWith(t))return e;return null}o(S,"extractCodexMcpServer");function R(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(R,"normalizeCodexToolName");function V(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=v(i),a=s.slice(r+2);return{tool_type:"mcp",tool_name:C(a),mcp_server:u}}}const t=S(n);if(t!==null&&!n.startsWith(h))return{tool_type:"mcp",tool_name:C(n),mcp_server:t};const e=R(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(V,"classifyCodexTool");function D(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(R(n)==="Bash"){const r=e.cmd??e.command,i=typeof r=="string"?O(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,a=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 a=="number"?a:void 0}}if(n.startsWith(h)||S(n)!==null){if("_metadata"in e){const{_metadata:r,...i}=e;return i}return e}}o(D,"extractCodexToolInput");function O(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(O,"extractBashBinary");function A(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(A,"decodeJwtPayload");function K(n){if(typeof n=="string"){const t=A(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(K,"extractIdTokenFields");function U(n){const t=n??(0,p.join)((0,b.homedir)(),".codex","auth.json");if(!(0,m.existsSync)(t))return{};try{const e=JSON.parse((0,m.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}=K(e.tokens?.id_token);return{usageType:s,usagePlan:i?.toLowerCase(),userEmail:r}}catch(e){return y.logger.debug(`failed to parse ${t}: ${e}`),{}}}o(U,"resolveCodexUsage");function X(n,t){return n.trim()===`[${t}]`}o(X,"tableHeaderLineExact");function G(n){const t=n.trim();return/^\[\[?[^\]]+\]\]?$/.test(t)}o(G,"isAnyTableHeader");function j(n){const e=n.trim().match(/^\[([^[\]]+)\]$/);return e===null?null:e[1]}o(j,"tableHeaderName");function _(n,t){let e=-1;for(let r=0;r<n.length;r+=1)if(X(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(G(n[r])){s=r;break}return{startIdx:e,endIdx:s}}o(_,"findTomlSection");function $(n){const t=[...n];for(;t.length>0&&t[t.length-1].trim()==="";)t.pop();return t}o($,"trimTrailingBlanks");function w(n,t){return n.length===0?t.join(`
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=_(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 l=0;l<s.length;l+=1)if(r.test(s[l])){s[l]="hooks = true",i=!0;break}i||s.unshift("hooks = true");const u=$(s),d=[...t.slice(0,e.startIdx),t[e.startIdx],...u,...e.endIdx<t.length?[""]:[],...t.slice(e.endIdx)].join(`
9
- `);return d.endsWith(`
10
- `)?d:d+`
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=_(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(l=>!r.test(l));if(i.length===s.length)return n;const u=i.some(l=>l.trim().length>0);let a;if(u){const l=$(i);a=[...t.slice(0,e.startIdx),t[e.startIdx],...l,...e.endIdx<t.length?[""]:[],...t.slice(e.endIdx)]}else a=[...t.slice(0,e.startIdx),...t.slice(e.endIdx)];const d=a.join(`
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 d.endsWith(`
16
- `)?d:d+`
17
- `}o(q,"removeFeaturesHooks");function Q(n){const t=n.split(`
18
- `),e=_(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 l=0;l<s.length;l+=1)if(r.test(s[l])){s[l]="hide_spawn_agent_metadata = false",i=!0;break}i||s.unshift("hide_spawn_agent_metadata = false");const u=$(s),d=[...t.slice(0,e.startIdx),t[e.startIdx],...u,...e.endIdx<t.length?[""]:[],...t.slice(e.endIdx)].join(`
19
- `);return d.endsWith(`
20
- `)?d:d+`
21
- `}o(Q,"ensureMultiAgentV2SpawnMetadataExposed");function Y(n){const t=n.split(`
22
- `),e=_(t,"features.multi_agent_v2");if(e===null)return n;const s=t.slice(e.startIdx+1,e.endIdx).filter(a=>a.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(`
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(Y,"removeMultiAgentV2SpawnMetadata");function N(n,t,e){const s=`mcp_servers.${t}`,r=n.split(`
28
- `),i=_(r,s),a=[`[${s}]`,...e];if(i===null)return w(n,a);const d=r.slice(0,i.startIdx),l=r.slice(i.endIdx),c=[...d,...a,...l.length>0?[""]:[],...l].join(`
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(N,"upsertMcpServer");function nn(n,t){const e=`mcp_servers.${t}`,s=`${e}.`,r=n.split(`
32
- `),i=[];let u=!1,a=!1;for(const c of r){const g=j(c);if(g!==null&&(u=g===e||g.startsWith(s),u)){a=!0;continue}u||i.push(c)}if(!a)return n;const d=[];let l=!1;for(const c of i){const g=c.trim().length===0;g&&l||(d.push(c),l=g)}const f=d.join(`
33
- `);return f.endsWith(`
34
- `)||f.length===0?f:f+`
35
- `}o(nn,"removeMcpServer");function tn(n,t,e){const s=`agents.${t}`,r=n.split(`
36
- `),i=_(r,s),a=[`[${s}]`,...e];if(i===null)return w(n,a);const d=r.slice(0,i.startIdx),l=r.slice(i.endIdx),c=[...d,...a,...l.length>0?[""]:[],...l].join(`
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(tn,"upsertAgentsTable");function en(n,t){const e=`agents.${t}`,s=`${e}.`,r=n.split(`
40
- `),i=[];let u=!1,a=!1;for(const c of r){const g=j(c);if(g!==null&&(u=g===e||g.startsWith(s),u)){a=!0;continue}u||i.push(c)}if(!a)return n;const d=[];let l=!1;for(const c of i){const g=c.trim().length===0;g&&l||(d.push(c),l=g)}const f=d.join(`
41
- `);return f.endsWith(`
42
- `)||f.length===0?f:f+`
43
- `}o(en,"removeAgentsTable");function rn(n,t){return(0,p.join)(n,".codex","agents",`${t}.toml`)}o(rn,"codexAgentTomlPath");function sn(n){for(const t of n.split(`
44
- `)){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(sn,"extractTomlTopLevelModel");function on(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,a]of Object.entries(r))a!=null&&(typeof a=="string"?i.push(`${u} = ${JSON.stringify(a)}`):typeof a=="number"||typeof a=="boolean"?i.push(`${u} = ${a}`):i.push(`${u} = ${JSON.stringify(a)}`));t.push(`${e} = { ${i.join(", ")} }`)}}return t}o(on,"tomlBodyFromRecord");const I="<!-- ironbee:start -->",x="<!-- ironbee:end -->";function un(n,t){const e=`${I}
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
- ${x}`,s=n.indexOf(I),r=n.indexOf(x);if(s>=0&&r>s){const i=n.slice(0,s),u=n.slice(r+x.length);return i+e+u}return n.trim().length===0?e+`
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(un,"upsertAgentsMdBlock");function an(n){const t=n.indexOf(I),e=n.indexOf(x);if(t<0||e<t)return n.trim().length===0?null:n;const s=n.slice(0,t).trimEnd(),r=n.slice(e+x.length).trimStart(),i=s+(s.length>0&&r.length>0?`
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(an,"stripAgentsMdBlock");function ln(n){const t=T(n);if(!(0,m.existsSync)(t))return"";try{return(0,m.readFileSync)(t,"utf-8")}catch(e){return y.logger.debug(`failed to read ${t}: ${e}`),""}}o(ln,"readCodexConfigToml");function dn(n,t){const e=T(n);try{(0,m.writeFileSync)(e,t)}catch(s){y.logger.debug(`failed to write ${e}: ${s}`)}}o(dn,"writeCodexConfigToml");function T(n){return(0,p.join)(n,".codex","config.toml")}o(T,"codexConfigTomlPath");function cn(n){return(0,p.join)(n,".codex","hooks.json")}o(cn,"codexHooksJsonPath");function gn(){return(0,p.join)((0,b.homedir)(),".codex","config.toml")}o(gn,"userCodexConfigTomlPath");function fn(){return(0,p.join)((0,b.homedir)(),".codex","hooks.json")}o(fn,"userCodexHooksJsonPath");function pn(n){return(0,p.join)((0,b.homedir)(),".codex","agents",`${n}.toml`)}o(pn,"userCodexAgentTomlPath");0&&(module.exports={AGENTS_MD_END_MARKER,AGENTS_MD_START_MARKER,canonicalizeCodexServerName,canonicalizeCodexToolName,classifyCodexTool,codexAgentTomlPath,codexConfigTomlPath,codexHooksJsonPath,decodeJwtPayload,ensureFeaturesHooksTrue,ensureMultiAgentV2SpawnMetadataExposed,extractBashBinary,extractCodexMcpServer,extractCodexToolInput,extractTomlTopLevelModel,findTomlSection,normalizeCodexToolName,parseCodexHookStdin,readCodexConfigToml,removeAgentsTable,removeFeaturesHooks,removeMcpServer,removeMultiAgentV2SpawnMetadata,resolveCodexUsage,stripAgentsMdBlock,tomlBodyFromRecord,upsertAgentsMdBlock,upsertAgentsTable,upsertMcpServer,userCodexAgentTomlPath,userCodexConfigTomlPath,userCodexHooksJsonPath,writeCodexConfigToml});
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});
@@ -98,3 +98,6 @@ The platform sections below list each enabled cycle's server, tool prefix, and s
98
98
 
99
99
  <!--IRONBEE:PLATFORM:android-->
100
100
  <!--/IRONBEE:PLATFORM:android-->
101
+
102
+ <!--IRONBEE:PLATFORM:terminal-->
103
+ <!--/IRONBEE:PLATFORM:terminal-->
@@ -32,3 +32,6 @@ The platform sections below list each enabled cycle's server, tool prefix, and s
32
32
 
33
33
  <!--IRONBEE:PLATFORM:android-->
34
34
  <!--/IRONBEE:PLATFORM:android-->
35
+
36
+ <!--IRONBEE:PLATFORM:terminal-->
37
+ <!--/IRONBEE:PLATFORM:terminal-->
@@ -52,3 +52,6 @@ running anything, use `ironbee scenario status`.)
52
52
 
53
53
  <!--IRONBEE:PLATFORM:android-->
54
54
  <!--/IRONBEE:PLATFORM:android-->
55
+
56
+ <!--IRONBEE:PLATFORM:terminal-->
57
+ <!--/IRONBEE:PLATFORM:terminal-->
@@ -61,6 +61,9 @@ Whatever the scenario directs, the gate is unchanged — you must still call eve
61
61
  <!--IRONBEE:PLATFORM:android-->
62
62
  <!--/IRONBEE:PLATFORM:android-->
63
63
 
64
+ <!--IRONBEE:PLATFORM:terminal-->
65
+ <!--/IRONBEE:PLATFORM:terminal-->
66
+
64
67
  ---
65
68
 
66
69
  ## When to FAIL
@@ -1 +1 @@
1
- "use strict";var r=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var u=(t,o)=>r(t,"name",{value:o,configurable:!0});var l=(t,o)=>{for(var n in o)r(t,n,{get:o[n],enumerable:!0})},S=(t,o,n,s)=>{if(o&&typeof o=="object"||typeof o=="function")for(let i of f(o))!m.call(t,i)&&i!==n&&r(t,i,{get:()=>o[i],enumerable:!(s=g(o,i))||s.enumerable});return t};var y=t=>S(r({},"__esModule",{value:!0}),t);var k={};l(k,{run:()=>$});module.exports=y(k);var p=require("../../../hooks/core/activity-end"),e=require("../../../lib/logger"),a=require("../../../lib/output"),c=require("../../../lib/stdin");async function $(t){let o;try{o=JSON.parse((0,c.readStdin)())}catch(d){e.logger.debug(`failed to parse stdin: ${d}`),(0,a.writeAndExit)(JSON.stringify({}),0);return}const n=o.conversation_id??"default",s=`${t}/.ironbee/sessions/${n}`,i=`${s}/actions.jsonl`;(0,e.setLogFile)(`${s}/session.log`),await(0,p.runActivityEnd)({sessionDir:s,actionsFile:i,projectDir:t,sessionId:n}),(0,a.writeAndExit)(JSON.stringify({}),0)}u($,"run");0&&(module.exports={run});
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 m=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var f=Object.prototype.hasOwnProperty;var p=(o,t)=>e(o,"name",{value:t,configurable:!0});var g=(o,t)=>{for(var r in t)e(o,r,{get:t[r],enumerable:!0})},l=(o,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of d(t))!f.call(o,s)&&s!==r&&e(o,s,{get:()=>t[s],enumerable:!(i=m(t,s))||i.enumerable});return o};var b=o=>l(e({},"__esModule",{value:!0}),o);var $={};g($,{run:()=>S});module.exports=b($);var u=require("../../../hooks/core/activity"),n=require("../../../lib/logger"),a=require("../../../lib/stdin");async function S(o){let t;try{t=JSON.parse((0,a.readStdin)())}catch(c){n.logger.debug(`failed to parse stdin: ${c}`),process.exit(0)}const r=t.conversation_id??"default",i=`${o}/.ironbee/sessions/${r}`;(0,n.setLogFile)(`${i}/session.log`);const s=`${i}/actions.jsonl`;await(0,u.startActivity)({sessionDir:i,actionsFile:s,source:"user_prompt"}),process.exit(0)}p(S,"run");0&&(module.exports={run});
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 f=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var $=Object.prototype.hasOwnProperty;var g=(t,e)=>f(t,"name",{value:e,configurable:!0});var w=(t,e)=>{for(var o in e)f(t,o,{get:e[o],enumerable:!0})},I=(t,e,o,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of S(e))!$.call(t,i)&&i!==o&&f(t,i,{get:()=>e[i],enumerable:!(n=y(e,i))||n.enumerable});return t};var k=t=>I(f({},"__esModule",{value:!0}),t);var E={};w(E,{run:()=>U});module.exports=k(E);var p=require("fs"),h=require("../../../hooks/core/clear-verdict"),C=require("../../../hooks/core/verification-lifecycle"),_=require("../../../hooks/core/actions"),v=require("../../../hooks/core/session-state"),F=require("../../../hooks/core/tool-use-stash"),c=require("../../../hooks/core/file-diff"),d=require("../../../lib/config"),a=require("../../../lib/logger"),b=require("../../../lib/stdin");function W(t,e){const o=t.tool_name,n=t.tool_input;if(!n)return null;const i=t.tool_use_id?(0,F.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}g(W,"deriveChangeFacts");function D(t,e,o,n){const i=o?.prior_content??"";let s;if(e==="delete")s="";else try{s=(0,p.existsSync)(t)?(0,p.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}g(D,"buildChangeset");async function U(t){let e;try{e=JSON.parse((0,b.readStdin)())}catch(u){a.logger.debug(`failed to parse stdin: ${u}`),process.exit(0)}const o=e.conversation_id??"default";(0,a.setLogFile)(`${t}/.ironbee/sessions/${o}/session.log`);const n=e.tool_input?.file_path??e.tool_input?.path;n&&n.includes(".ironbee/sessions/")&&n.endsWith("verdict.json")&&(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=`${t}/.ironbee/sessions/${o}`,l=`${s}/actions.jsonl`,r=W(e,o);r||(a.logger.debug(`skipping clear-verdict: unsupported tool ${e.tool_name}`),process.exit(0));const x=await(0,C.openFixCycleIfFixing)({sessionDir:s,actionsFile:l}),m={...(0,_.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,v.getActiveActivityId)(s),fix_id:x};if((0,d.getCaptureFileChangeset)(i)&&n){const u=D(n,r.operation,r.stash,(0,d.getMaxChangesetBytes)(i));u!==void 0&&(m.changeset=u)}await(0,_.appendAction)(l,m),(0,h.runClearVerdict)({verdictFile:`${s}/verdict.json`,sessionDir:s}),process.exit(0)}g(U,"run");0&&(module.exports={run});
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 l=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var U=Object.prototype.hasOwnProperty;var _=(o,t)=>l(o,"name",{value:t,configurable:!0});var $=(o,t)=>{for(var i in t)l(o,i,{get:t[i],enumerable:!0})},x=(o,t,i,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of P(t))!U.call(o,s)&&s!==i&&l(o,s,{get:()=>t[s],enumerable:!(e=O(t,s))||e.enumerable});return o};var k=o=>x(l({},"__esModule",{value:!0}),o);var E={};$(E,{run:()=>I});module.exports=k(E);var c=require("fs"),b=require("../../../hooks/core/actions"),h=require("../../../hooks/core/activity"),C=require("../../../hooks/core/tool-use-stash"),d=require("../../../lib/config"),n=require("../../../lib/logger"),v=require("../../../lib/stdin");async function I(o,t){const i=t?.soft===!0;let e;try{e=JSON.parse((0,v.readStdin)())}catch(r){n.logger.debug(`failed to parse stdin: ${r}`);const u={permission:"allow"};process.stdout.write(JSON.stringify(u)),process.exit(0);return}const s=e.conversation_id??"default";(0,n.setLogFile)(`${o}/.ironbee/sessions/${s}/session.log`);const p=`${o}/.ironbee/sessions/${s}`,f=`${p}/actions.jsonl`;if(!i&&(0,b.hasToolCallsSinceLastVerdict)(f)){const r={permission:"deny",agent_message:`BLOCKED: You used verification tools (browser-devtools / node-devtools / backend-devtools / android-devtools) but did not submit a verdict. You MUST submit a verdict (pass or fail) before editing code.
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),u=(0,d.getCaptureFileChangeset)(r),g=(0,c.existsSync)(a),S=e.tool_name==="Write",w=e.tool_name==="StrReplace"||e.tool_name==="Delete";if(S||w&&u){const m={file_existed:g};if(u&&g)try{m.prior_content=(0,c.readFileSync)(a,"utf-8")}catch(T){n.logger.debug(`failed to pre-read ${a} for changeset capture: ${T}`)}(0,C.stashToolUseData)(s,e.tool_use_id,m)}}await(0,h.startActivity)({sessionDir:p,actionsFile:f,source:"pre_tool_use"});const y={permission:"allow"};process.stdout.write(JSON.stringify(y)),process.exit(0)}_(I,"run");0&&(module.exports={run});
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 B=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var K=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})},J=(o,t,c,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of F(t))!K.call(o,r)&&r!==c&&f(o,r,{get:()=>t[r],enumerable:!(i=B(t,r))||i.enumerable});return o};var L=o=>J(f({},"__esModule",{value:!0}),o);var D={};j(D,{run:()=>q});module.exports=L(D);var I=require("crypto"),e=require("../../../hooks/core/session-state"),S=require("../../../hooks/core/actions"),k=require("../../../hooks/core/activity"),O=require("../../../hooks/core/verification-lifecycle"),U=require("../../../lib/config"),E=require("../../../lib/recording-tools"),M=require("../../../hooks/core/scenario-tools"),g=require("../../../lib/logger"),$=require("../../../lib/stdin");const h={"MCP:bdt_":"browser-devtools","MCP:ndt_":"node-devtools","MCP:bedt_":"backend-devtools","MCP:adt_":"android-devtools"},W="browser-devtools";async function q(o,t){const c=t?.soft===!0;let i;try{i=JSON.parse((0,$.readStdin)())}catch(n){g.logger.debug(`failed to parse stdin: ${n}`);const x={permission:"allow"};process.stdout.write(JSON.stringify(x)),process.exit(0);return}const r=i.conversation_id??"default",s=`${o}/.ironbee/sessions/${r}`;(0,g.setLogFile)(`${s}/session.log`);const b=`${s}/actions.jsonl`,p=(0,M.isScenarioTool)(i.tool_name),P=(0,e.getActiveVerificationId)(s);if(!P&&!c&&!p){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).
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,E.recordingToolsForBareTool)(v):null;if(!c&&!p&&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.
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:b,source:"pre_tool_use"});let d=P;c&&!d&&!p&&(d=(await(0,O.startVerification)({sessionId:r,sessionDir:s,actionsFile:b,recordingEnabled:!1})).verificationId);const A=(0,e.getActiveTraceId)(s),_=(0,e.getActiveActivityId)(s),y=(0,S.resolveProjectName)(o),C=[`prj:${y}`,`sid:${r}`];_&&C.push(`aid:${_}`),d&&C.push(`vid:${d}`);const N=`ironbee=${C.join(";")}`,l=(0,U.loadConfig)(o),T={...i.tool_input??{}},a={projectName:y,sessionId:r,activityId:_,verificationId:d,traceId:A,traceState:N,toolCallId:(0,I.randomUUID)()};i.tool_use_id&&(a.toolUseId=i.tool_use_id),a.mcpServer=(()=>{for(const n of Object.keys(h))if(m.startsWith(n))return h[n];return W})();const w=(0,e.getUserEmail)(s);w&&(a.userEmail=w),l.collector?.url&&(a.collectorUrl=l.collector.url),l.collector?.oauthToken?a.collectorOAuthToken=l.collector.oauthToken:l.collector?.apiKey&&(a.collectorApiKey=l.collector.apiKey),T._metadata=a;const V={permission:"allow",updated_input:T};process.stdout.write(JSON.stringify(V)),process.exit(0)}R(q,"run");0&&(module.exports={run});
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 S=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var c=(n,s)=>a(n,"name",{value:s,configurable:!0});var _=(n,s)=>{for(var i in s)a(n,i,{get:s[i],enumerable:!0})},$=(n,s,i,e)=>{if(s&&typeof s=="object"||typeof s=="function")for(let o of y(s))!w.call(n,o)&&o!==i&&a(n,o,{get:()=>s[o],enumerable:!(e=S(s,o))||e.enumerable});return n};var b=n=>$(a({},"__esModule",{value:!0}),n);var E={};_(E,{run:()=>A});module.exports=b(E);var t=require("../../../hooks/core/actions"),p=require("../../../hooks/core/activity"),u=require("../../../hooks/core/session-state"),r=require("../../../lib/logger"),m=require("../../../lib/stdin"),l=require("../../../queue");async function A(n){let s;try{s=JSON.parse((0,m.readStdin)())}catch(g){r.logger.debug(`failed to parse stdin: ${g}`),process.exit(0)}const i=s.conversation_id??"default",e=`${n}/.ironbee/sessions/${i}`,o=`${e}/actions.jsonl`;(0,r.setLogFile)(`${e}/session.log`),await(0,u.closeOpenCycles)(e,o,"session_end"),await(0,p.endActivity)({sessionDir:e,actionsFile:o});const d=Date.now(),f={...(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,f),await(0,l.flushSynchronously)(n,i),r.logger.debug(`session-end: ${i}`),process.exit(0)}c(A,"run");0&&(module.exports={run});
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 a=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var E=Object.prototype.hasOwnProperty;var l=(s,i)=>a(s,"name",{value:i,configurable:!0});var I=(s,i)=>{for(var t in i)a(s,t,{get:i[t],enumerable:!0})},_=(s,i,t,n)=>{if(i&&typeof i=="object"||typeof i=="function")for(let e of O(i))!E.call(s,e)&&e!==t&&a(s,e,{get:()=>i[e],enumerable:!(n=y(i,e))||n.enumerable});return s};var w=s=>_(a({},"__esModule",{value:!0}),s);var $={};I($,{run:()=>k});module.exports=w($);var o=require("../../../hooks/core/actions"),u=require("../../../hooks/core/session-state"),d=require("../../../lib/config"),r=require("../../../lib/logger"),c=require("../../../lib/output"),g=require("../../../lib/stdin"),m=require("../../../lib/telemetry");async function k(s){let i;try{i=JSON.parse((0,g.readStdin)())}catch(v){r.logger.debug(`failed to parse stdin: ${v}`),(0,c.writeAndExit)(JSON.stringify({}),0);return}const t=i.conversation_id??"default",n=`${s}/.ironbee/sessions/${t}/actions.jsonl`;(0,r.setLogFile)(`${s}/.ironbee/sessions/${t}/session.log`);const e=`${s}/.ironbee/sessions/${t}`;(0,u.setUserEmail)(e,i.user_email??void 0);const S={...(0,o.baseFields)(n),type:"session_start",timestamp:Date.now(),session_id:t,client:"cursor",source:"startup"};await(0,o.appendAction)(n,S),await(0,u.reconcileSessionState)(e,n,o.appendAction);const f=(0,d.getVerificationEnabled)((0,d.loadConfig)(s));if(await(0,m.trackSessionStart)("cursor",t,f,s),r.logger.debug(`session-start: ${t}`),!f){(0,c.writeAndExit)(JSON.stringify({}),0);return}const p=JSON.stringify({session_id:t,status:"pass",checks:["form submits successfully","new item appears in list"]}),b=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
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 '${p}' | ironbee hook submit-verdict
10
+ echo '${b}' | ironbee hook submit-verdict
11
11
 
12
12
  On fail (issues is required):
13
- echo '${b}' | ironbee hook submit-verdict
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,c.writeAndExit)(JSON.stringify(h),0)}l(k,"run");0&&(module.exports={run});
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 N=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var c=(o,t)=>d(o,"name",{value:t,configurable:!0});var v=(o,t)=>{for(var r in t)d(o,r,{get:t[r],enumerable:!0})},C=(o,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of h(t))!I.call(o,n)&&n!==r&&d(o,n,{get:()=>t[n],enumerable:!(i=N(t,n))||i.enumerable});return o};var P=o=>C(d({},"__esModule",{value:!0}),o);var x={};v(x,{run:()=>L});module.exports=P(x);var b=require("../../../hooks/core/actions"),T=require("../../../hooks/core/activity"),g=require("../../../hooks/core/session-state"),E=require("../../../lib/config"),e=require("../../../lib/logger"),p=require("../../../lib/output"),w=require("../../../lib/stdin"),l=require("../../../queue"),f=require("../util");const S="bdt_",J="ndt_",F="bedt_";async function L(o){let t;try{t=JSON.parse((0,w.readStdin)())}catch(u){e.logger.debug(`failed to parse stdin: ${u}`),(0,p.writeAndExit)(JSON.stringify({}),0);return}const r=t.conversation_id??"default",i=`${o}/.ironbee/sessions/${r}`,n=`${i}/actions.jsonl`;(0,e.setLogFile)(`${i}/session.log`),(0,g.getActiveActivityId)(i)===void 0&&await(0,T.startActivity)({sessionDir:i,actionsFile:n,source:"pre_tool_use"});const _=t.tool_name??"unknown",O=Date.now(),$=t.tool_input&&typeof t.tool_input=="object"&&!Array.isArray(t.tool_input)?{...t.tool_input,_metadata:void 0}:t.tool_input,k=(0,g.getActiveActivityId)(i),s=(0,f.classifyTool)(_,t.tool_input);if(s.tool_type==="mcp"&&(s.tool_name.startsWith(S)||s.tool_name.startsWith(J)||s.tool_name.startsWith(F))){e.logger.debug(`track-action-monitor: skipped devtools tool ${_}`),(0,p.writeAndExit)(JSON.stringify({}),0);return}const m=typeof t.error_message=="string"&&t.error_message.length>0?t.error_message:void 0;let a;if(m){const u=[];t.failure_type&&u.push(t.failure_type),t.is_interrupt&&u.push("interrupted"),a=`${u.length>0?`${u.join(",")}: `:""}${m}`}const A={...(0,b.baseFields)(n),type:"tool_call",timestamp:O,tool_name:s.tool_name,tool_type:s.tool_type,tool_use_id:t.tool_use_id,tool_input:(0,f.extractCursorToolInput)(_,$),tool_input_size:y(t.tool_input),tool_response:a?void 0:t.tool_output,tool_response_size:y(a?void 0:t.tool_output),activity_id:k,duration:typeof t.duration=="number"?t.duration:null,mcp_server:s.mcp_server,error:a};R(o,r,A),e.logger.debug(`track-action-monitor: ${_}${a?" (failed)":""}`),(0,p.writeAndExit)(JSON.stringify({}),0)}c(L,"run");function R(o,t,r){if(!(0,E.isJobQueueEnabled)(o))return;const i={...r};delete i.tool_response;try{(0,l.submit)(o,t,l.SEND_EVENT_TYPE,i)}catch(n){if(n instanceof l.JobTooLargeError){e.logger.debug(`track-action-monitor: wire event too large for ${r.tool_name}; dropping`);return}e.logger.debug(`track-action-monitor: failed to submit ${r.tool_name}: ${n instanceof Error?n.message:n}`)}}c(R,"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
+ "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 y=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames;var j=Object.prototype.hasOwnProperty;var g=(o,t)=>y(o,"name",{value:t,configurable:!0});var Q=(o,t)=>{for(var l in t)y(o,l,{get:t[l],enumerable:!0})},Y=(o,t,l,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of K(t))!j.call(o,r)&&r!==l&&y(o,r,{get:()=>t[r],enumerable:!(i=U(t,r))||i.enumerable});return o};var q=o=>Y(y({},"__esModule",{value:!0}),o);var it={};Q(it,{run:()=>nt});module.exports=q(it);var p=require("../../../hooks/core/actions"),T=require("../../../hooks/core/nested-tools"),c=require("../../../hooks/core/session-state"),L=require("../../../hooks/core/verification-context"),E=require("../../../lib/config"),s=require("../../../lib/logger"),k=require("../../../lib/recording-tools"),F=require("../../../lib/output"),P=require("../../../lib/stdin"),f=require("../../../queue"),b=require("../util");const S="bdt_",$="ndt_",x="bedt_",D="adt_",G="browser-devtools",H="node-devtools",Z="backend-devtools",tt="android-devtools";function ot(o){return o.startsWith(x)?Z:o.startsWith(D)?tt:o.startsWith(S)?G:o.startsWith($)?H:null}g(ot,"resolveServerByPrefix");async function nt(o){let t;try{t=JSON.parse((0,P.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=`${o}/.ironbee/sessions/${l}`,r=`${i}/actions.jsonl`;(0,s.setLogFile)(`${i}/session.log`);const v=t.tool_name??"unknown",R=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,A=(0,c.getActiveActivityId)(i),O=(0,c.getActiveVerificationId)(i),C=(0,c.getActiveTraceId)(i),e=(0,b.classifyTool)(v,t.tool_input),W=e.tool_type==="mcp"&&e.tool_name.startsWith(S),B=e.tool_type==="mcp"&&e.tool_name.startsWith($),J=e.tool_type==="mcp"&&e.tool_name.startsWith(x),M=e.tool_type==="mcp"&&e.tool_name.startsWith(D),m=W||B||J||M,a=e.tool_type==="mcp"?ot(e.tool_name)??e.mcp_server:e.mcp_server,z=m?w:(0,b.extractCursorToolInput)(v,w),I=typeof t.error_message=="string"&&t.error_message.length>0?t.error_message:void 0;let u;if(I){const n=[];t.failure_type&&n.push(t.failure_type),t.is_interrupt&&n.push("interrupted"),u=`${n.length>0?`${n.join(",")}: `:""}${I}`}const h={...(0,p.baseFields)(r),type:"tool_call",timestamp:R,tool_name:e.tool_name,tool_type:e.tool_type,tool_use_id:t.tool_use_id,tool_input:z,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:A,verification_id:O,trace_id:C,duration:typeof t.duration=="number"?t.duration:null,mcp_server:a,error:u};if(m){await(0,p.appendAction)(r,h);const n=(0,k.recordingToolsForServer)(a);n!==null&&(e.tool_name===n.startTool?((0,c.setRecordingActive)(i,!0),s.logger.debug(`track-action: recording started (${n.cycle})`)):e.tool_name===n.stopTool&&((0,c.setRecordingActive)(i,!1),s.logger.debug(`track-action: recording stopped (${n.cycle})`)))}else et(o,l,h);if(s.logger.debug(`track-action: ${v}${u?" (failed)":""}`),m&&a!==null&&e.tool_name===(0,T.executeToolBareName)(a)&&!u){const n=(0,T.extractNestedToolCalls)(t.tool_input,a),_=(0,k.recordingToolsForServer)(a);for(const d of n){_!==null&&(d.name===_.startTool?((0,c.setRecordingActive)(i,!0),s.logger.debug(`track-action (nested): recording started (${_.cycle})`)):d.name===_.stopTool&&((0,c.setRecordingActive)(i,!1),s.logger.debug(`track-action (nested): recording stopped (${_.cycle})`)));const X={...(0,p.baseFields)(r),type:"tool_call",timestamp:d.startTime??R,tool_name:d.name,tool_type:"mcp",tool_input:d.args,activity_id:A,verification_id:O,trace_id:C,duration:d.duration??null,mcp_server:a,nested:!0,parent_tool_use_id:t.tool_use_id};await(0,p.appendAction)(r,X),s.logger.debug(`track-action (nested): ${d.name}`)}}const N={};if(m)try{const n=(0,L.buildVerificationContextOnceForCycle)({projectDir:o,sessionId:l,sessionDir:i,activeVerificationId:O,config:(0,E.loadConfig)(o)});n.length>0&&(N.additional_context=n)}catch(n){s.logger.debug(`track-action: verification-context injection skipped: ${n instanceof Error?n.message:n}`)}(0,F.writeAndExit)(JSON.stringify(N),0)}g(nt,"run");function et(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(et,"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
+ "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 r=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var m=(o,t)=>r(o,"name",{value:t,configurable:!0});var I=(o,t)=>{for(var s in t)r(o,s,{get:t[s],enumerable:!0})},_=(o,t,s,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of y(t))!C.call(o,n)&&n!==s&&r(o,n,{get:()=>t[n],enumerable:!(e=w(t,n))||e.enumerable});return o};var v=o=>_(r({},"__esModule",{value:!0}),o);var b={};I(b,{run:()=>$});module.exports=v(b);var p=require("../../../hooks/core/verify-gate"),d=require("../../../hooks/core/activity"),a=require("../../../lib/config"),u=require("../../../lib/logger"),f=require("../../../lib/output"),k=require("../../../lib/stdin"),g=require("../../../queue");async function $(o){let t;try{t=JSON.parse((0,k.readStdin)())}catch(S){u.logger.debug(`failed to parse stdin: ${S}`),(0,f.writeAndExit)(JSON.stringify({}),0);return}const s=t.conversation_id??"default";(0,u.setLogFile)(`${o}/.ironbee/sessions/${s}/session.log`);const e=`${o}/.ironbee/sessions/${s}`,n=`${e}/actions.jsonl`,l=(0,a.loadConfig)(o),i=await(0,p.runVerifyGate)({sessionId:s,sessionDir:e,actionsFile:n,verdictFile:`${e}/verdict.json`,maxRetries:(0,a.getMaxRetries)(l),config:l,projectDir:o}),c={};i.action==="allow"&&await(0,d.endActivity)({sessionDir:e,actionsFile:n}),i.action==="block"&&i.message&&(c.followup_message=i.message),(0,g.flushInBackground)(o,s),(0,g.flushStragglersInBackground)(o,s),(0,f.writeAndExit)(JSON.stringify(c),0)}m($,"run");0&&(module.exports={run});
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