@ironbee-ai/cli 0.29.0 → 0.31.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 +191 -0
  7. package/dist/clients/claude/agents/ironbee-verifier.md +22 -5
  8. package/dist/clients/claude/commands/ironbee-manage-scenario.md +36 -0
  9. package/dist/clients/claude/commands/ironbee-search-scenario.md +22 -0
  10. package/dist/clients/claude/commands/ironbee-sync-scenario.md +31 -0
  11. package/dist/clients/claude/commands/ironbee-verify.md +13 -12
  12. package/dist/clients/claude/hooks/activity-end.js +1 -1
  13. package/dist/clients/claude/hooks/activity-start.js +1 -1
  14. package/dist/clients/claude/hooks/clear-verdict.js +1 -1
  15. package/dist/clients/claude/hooks/require-verdict.js +2 -2
  16. package/dist/clients/claude/hooks/require-verification.js +3 -3
  17. package/dist/clients/claude/hooks/session-end.js +1 -1
  18. package/dist/clients/claude/hooks/session-start.js +4 -4
  19. package/dist/clients/claude/hooks/session-status.js +2 -2
  20. package/dist/clients/claude/hooks/subagent-start.js +1 -1
  21. package/dist/clients/claude/hooks/subagent-stop.js +1 -1
  22. package/dist/clients/claude/hooks/track-action-monitor.js +1 -1
  23. package/dist/clients/claude/hooks/track-action.js +1 -1
  24. package/dist/clients/claude/hooks/verify-gate.js +4 -4
  25. package/dist/clients/claude/index.js +4 -4
  26. package/dist/clients/claude/platforms/scenario.android.md +32 -0
  27. package/dist/clients/claude/platforms/scenario.backend.md +26 -0
  28. package/dist/clients/claude/platforms/scenario.browser.md +41 -0
  29. package/dist/clients/claude/platforms/scenario.node.md +27 -0
  30. package/dist/clients/claude/platforms/skill.android.md +4 -0
  31. package/dist/clients/claude/process-analytics.js +1 -1
  32. package/dist/clients/claude/statusline-toggle.js +2 -2
  33. package/dist/clients/claude/trust.js +1 -0
  34. package/dist/clients/codex/agents/ironbee-scenario.md +179 -0
  35. package/dist/clients/codex/agents/ironbee-verifier.md +22 -5
  36. package/dist/clients/codex/commands/ironbee-manage-scenario/SKILL.main.md +102 -0
  37. package/dist/clients/codex/commands/ironbee-manage-scenario/SKILL.md +38 -0
  38. package/dist/clients/codex/commands/ironbee-search-scenario/SKILL.main.md +37 -0
  39. package/dist/clients/codex/commands/ironbee-search-scenario/SKILL.md +23 -0
  40. package/dist/clients/codex/commands/ironbee-sync-scenario/SKILL.main.md +55 -0
  41. package/dist/clients/codex/commands/ironbee-sync-scenario/SKILL.md +33 -0
  42. package/dist/clients/codex/commands/ironbee-verify/SKILL.main.md +12 -3
  43. package/dist/clients/codex/commands/ironbee-verify/SKILL.md +4 -3
  44. package/dist/clients/codex/hooks/activity-end.js +1 -1
  45. package/dist/clients/codex/hooks/activity-start.js +1 -1
  46. package/dist/clients/codex/hooks/clear-verdict.js +3 -3
  47. package/dist/clients/codex/hooks/require-verdict.js +2 -2
  48. package/dist/clients/codex/hooks/require-verification.js +3 -3
  49. package/dist/clients/codex/hooks/session-start.js +3 -3
  50. package/dist/clients/codex/hooks/subagent-start.js +1 -1
  51. package/dist/clients/codex/hooks/subagent-stop.js +1 -1
  52. package/dist/clients/codex/hooks/track-action-monitor.js +1 -1
  53. package/dist/clients/codex/hooks/track-action-pre.js +1 -1
  54. package/dist/clients/codex/hooks/track-action.js +1 -1
  55. package/dist/clients/codex/hooks/verify-gate.js +1 -1
  56. package/dist/clients/codex/index.js +2 -2
  57. package/dist/clients/codex/platforms/command-verify.android.md +1 -0
  58. package/dist/clients/codex/platforms/rule.android.md +2 -1
  59. package/dist/clients/codex/platforms/scenario.android.md +32 -0
  60. package/dist/clients/codex/platforms/scenario.backend.md +26 -0
  61. package/dist/clients/codex/platforms/scenario.browser.md +40 -0
  62. package/dist/clients/codex/platforms/scenario.node.md +27 -0
  63. package/dist/clients/codex/platforms/skill.android.md +4 -0
  64. package/dist/clients/codex/process-analytics.js +2 -2
  65. package/dist/clients/codex/thread-map.js +1 -1
  66. package/dist/clients/codex/util.js +44 -31
  67. package/dist/clients/cursor/commands/ironbee-manage-scenario/SKILL.md +100 -0
  68. package/dist/clients/cursor/commands/ironbee-search-scenario/SKILL.md +34 -0
  69. package/dist/clients/cursor/commands/ironbee-sync-scenario/SKILL.md +54 -0
  70. package/dist/clients/cursor/commands/ironbee-verify/SKILL.md +2 -1
  71. package/dist/clients/cursor/hooks/activity-end.js +1 -1
  72. package/dist/clients/cursor/hooks/activity-start.js +1 -1
  73. package/dist/clients/cursor/hooks/clear-verdict.js +1 -1
  74. package/dist/clients/cursor/hooks/require-verdict.js +2 -2
  75. package/dist/clients/cursor/hooks/require-verification.js +3 -3
  76. package/dist/clients/cursor/hooks/session-end.js +1 -1
  77. package/dist/clients/cursor/hooks/session-start.js +4 -4
  78. package/dist/clients/cursor/hooks/track-action-monitor.js +1 -1
  79. package/dist/clients/cursor/hooks/track-action.js +1 -1
  80. package/dist/clients/cursor/hooks/verify-gate.js +1 -1
  81. package/dist/clients/cursor/index.js +1 -1
  82. package/dist/clients/cursor/platforms/command-verify.android.md +1 -0
  83. package/dist/clients/cursor/platforms/rule.android.md +2 -1
  84. package/dist/clients/cursor/platforms/scenario.android.md +32 -0
  85. package/dist/clients/cursor/platforms/scenario.backend.md +26 -0
  86. package/dist/clients/cursor/platforms/scenario.browser.md +40 -0
  87. package/dist/clients/cursor/platforms/scenario.node.md +27 -0
  88. package/dist/clients/cursor/platforms/skill.android.md +4 -0
  89. package/dist/commands/config.js +1 -1
  90. package/dist/commands/hook.js +10 -10
  91. package/dist/commands/import.js +3 -3
  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 -0
  95. package/dist/commands/status.js +1 -1
  96. package/dist/commands/uninstall.js +1 -1
  97. package/dist/commands/verify.js +2 -2
  98. package/dist/hooks/core/actions.js +7 -7
  99. package/dist/hooks/core/nested-tools.js +1 -1
  100. package/dist/hooks/core/scenario-tools.js +1 -0
  101. package/dist/hooks/core/session-state.js +1 -1
  102. package/dist/hooks/core/verification-context.js +8 -8
  103. package/dist/import/marker.js +2 -2
  104. package/dist/import/skip.js +1 -1
  105. package/dist/index.js +1 -1
  106. package/dist/lib/config.js +1 -1
  107. package/dist/lib/git.js +1 -1
  108. package/dist/lib/install-version.js +1 -1
  109. package/dist/lib/platform-section.js +3 -3
  110. package/dist/lib/runtime-paths.js +1 -0
  111. package/dist/lib/scenario-staleness.js +1 -0
  112. package/dist/otel/claude/daemon/process.js +1 -1
  113. package/dist/otel/claude/daemon/reprocess.js +1 -1
  114. package/dist/otel/claude/daemon/response-usage.js +2 -2
  115. package/dist/queue/drain.js +1 -1
  116. package/dist/queue/flush.js +1 -1
  117. package/dist/queue/paths.js +1 -1
  118. package/dist/queue/process-file.js +2 -2
  119. package/dist/queue/spawn.js +1 -1
  120. package/dist/tui/config/schema.js +1 -1
  121. package/dist/tui/queue/read.js +4 -4
  122. package/dist/tui/scenarios/area.js +2 -0
  123. package/dist/tui/sessions/read.js +2 -2
  124. package/dist/tui/shell/registry.js +1 -1
  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:()=>C,canonicalizeCodexToolName:()=>$,classifyCodexTool:()=>V,codexAgentTomlPath:()=>rn,codexConfigTomlPath:()=>T,codexHooksJsonPath:()=>cn,decodeJwtPayload:()=>A,ensureFeaturesHooksTrue:()=>Z,ensureMultiAgentV2SpawnMetadataExposed:()=>Q,extractBashBinary:()=>j,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 C(n){return z[n]??n}o(C,"canonicalizeCodexServerName");function $(n){if(!H.some(e=>n.startsWith(e)))return n;const t=n.split("_");return t.length<=3?n:`${t[0]}_${t[1]}_${t.slice(2).join("-")}`}o($,"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:C(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=C(i),a=s.slice(r+2);return{tool_type:"mcp",tool_name:$(a),mcp_server:u}}}const t=S(n);if(t!==null&&!n.startsWith(h))return{tool_type:"mcp",tool_name:$(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"?j(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 j(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(j,"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 O(n){const e=n.trim().match(/^\[([^[\]]+)\]$/);return e===null?null:e[1]}o(O,"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 v(n){const t=[...n];for(;t.length>0&&t[t.length-1].trim()==="";)t.pop();return t}o(v,"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"},F=["bdt_","ndt_","bedt_","adt_"];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"]];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=v(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=v(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=v(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=O(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=O(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});
@@ -0,0 +1,100 @@
1
+ ---
2
+ name: ironbee-manage-scenario
3
+ description: "Add, update, or delete a reusable IronBee verification scenario. Authors the script in the devtools format and saves it to the right platform's store (or finds and updates/deletes an existing one) using the scenario-* MCP tools."
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # IronBee — Manage scenario
8
+
9
+ Add / update / delete a reusable verification **scenario** using the devtools `scenario-*` MCP
10
+ tools directly. A scenario is a named, parameterizable script (`callTool('<tool>', {...})` JS) that
11
+ drives ONE platform's tools. This is NOT a verification cycle — it submits no verdict and does not
12
+ gate completion.
13
+
14
+ ## Steps
15
+ 1. **Resolve intent.** Content to save (inline text or a file path you read) → add/update. A target
16
+ only described → delete.
17
+ 2. **Add vs update (never duplicate).** Before adding, `*_scenario-search` / `*_scenario-list` to
18
+ check for a same-name / clearly-the-same scenario on the target platform; if it exists → update
19
+ it instead of creating a duplicate.
20
+ 3. **Pick the platform** from what the scenario does (see the platform sections for which platform fits) and author the script (see "Script
21
+ format"). Call `*_scenario-add` / `*_scenario-update` on **that platform's** server. A high-level
22
+ scenario spanning platforms → split into one sub-scenario per platform, linked by `ironbee.group`
23
+ + `ironbee.order` metadata.
24
+ 4. **Delete is destructive — always confirm.** Resolve the target, show the matched
25
+ **name + description + platform**, and ask the user before deleting. Multiple / low-score
26
+ candidates → list them and ask which. An **update resolved by fuzzy description** also confirms
27
+ (the script is overwritten); an exact-name update proceeds without confirm.
28
+ 5. **Scope**: pass `scope: "project"` (default) unless the user asked for `global`.
29
+
30
+ ## Live authoring (default for add / update) — build it against the running app
31
+
32
+ Don't author a runtime scenario from source guesses (source rarely matches the running system exactly). By **default, drive the app to
33
+ understand it — exactly what you'd do when verifying** (exercise the relevant flow through this platform's tools, whatever it takes) — author from what you actually observe, then validate by running it. Do this
34
+ entirely through the `*_scenario-*` tools (run discovery via `*_scenario-run`, don't call the platform
35
+ tools directly: that keeps it gate-orthogonal — no `verification_id`, can't false-block a later edit).
36
+
37
+ 1. **`draft` → skip:** if the request begins with `draft` (or says "source only"), author from source,
38
+ save, note *"not live-validated — run it to verify"*. Done.
39
+ 2. **Start the app only if it isn't already running** (track whether YOU started it). Can't start it
40
+ (missing env/DB/secrets, broken build) → **source-only draft + say so**, don't fail.
41
+ 3. **Understand it by running probe scenarios:** `*_scenario-add` the draft **under the FINAL scenario
42
+ name** (step 4 then iterates that SAME entry via `*_scenario-update` — do NOT spawn a separate
43
+ `*-probe` / throwaway scenario in the store) and `*_scenario-run` it to exercise the relevant flow —
44
+ whatever it takes to learn how the real system behaves — and read the returned snapshots/results.
45
+ 4. **Author the full flow** from what you observed → `*_scenario-update`. Make it a **verification flow**,
46
+ not a superficial run: exercise the cycle's evidence tools, capture their output with
47
+ `returnOutput: true`, and assert / return the expected outcomes — so running it later via
48
+ `/ironbee-verify scenario:<name>` can judge it and satisfy the gate.
49
+ 5. **Validate:** `*_scenario-run` end-to-end; fix the **SCRIPT** + update until it runs cleanly, and
50
+ **assert the real terminal outcome — not an optimistic intermediate signal**. Same app/env
51
+ considerations as any verification run (use a test/staging target for flows with real side effects).
52
+ 6. **Teardown — leave a clean store:** `*_scenario-delete` ANY temporary / probe / throwaway scenario you
53
+ added this session (anything named `*-probe`, a draft you decided not to keep, an exploratory copy);
54
+ the store must end with ONLY the finished deliverable scenario(s), never a leftover probe. THEN stop
55
+ ONLY the app / processes you started.
56
+
57
+ > **A genuine defect is a STOP, not a workaround.** If validating shows the flow can't legitimately
58
+ > succeed — a real bug makes the expected outcome unreachable (an error, a failed state, wrong
59
+ > resulting data) — do NOT engineer the scenario around it: don't cherry-pick inputs / args / data that
60
+ > dodge the bug, and don't weaken the assertion to an optimistic intermediate signal instead of the
61
+ > real terminal outcome. That yields a green scenario that masks a broken flow and produces a FALSE
62
+ > PASS when it's later run to verify. Instead STOP and report the defect to the user **in your summary,
63
+ > not inside the scenario** — keep the saved scenario a clean verification flow (it asserts the real
64
+ > outcome and will simply fail until the bug is fixed; that's it doing its job). Do NOT bake bug /
65
+ > defect commentary into the scenario's `description` or metadata; `liveValidated: false` is the only
66
+ > signal needed when you couldn't get a passing run — or leave the scenario unsaved. ("Fix until it
67
+ > passes" means fixing the SCRIPT, never working around the app.)
68
+
69
+ ## Script format
70
+ JS run in the devtools sandbox (async — top-level `await`/`return` work); reads params from `args`:
71
+
72
+ ```js
73
+ const { baseUrl } = args; // declared via argsSchema
74
+ const result = await callTool('<bare-tool-name>', { /* tool input */ });
75
+ return { ok: true };
76
+ ```
77
+
78
+ Discover the available `callTool` tool names for a platform from your connected MCP schemas — don't
79
+ guess. Document the expected `args` in the `description` + the `argsSchema` metadata.
80
+
81
+ ## Metadata conventions (stamp on add/update)
82
+ - `argsSchema` — declared params, e.g. `{ "baseUrl": "string" }`. **Mandatory for parametric scenarios.**
83
+ - `ironbee.coveredPaths` — source paths exercised (array), when derivable.
84
+ - `ironbee.group` / `ironbee.order` — for a cross-platform split.
85
+ - `*_scenario-update` does a **shallow replace** of metadata — to change one key, re-send the FULL
86
+ metadata object (read it first, merge, write back).
87
+
88
+ The platform sections below list each enabled cycle's server, tool prefix, and store dir.
89
+
90
+ <!--IRONBEE:PLATFORM:browser-->
91
+ <!--/IRONBEE:PLATFORM:browser-->
92
+
93
+ <!--IRONBEE:PLATFORM:node-->
94
+ <!--/IRONBEE:PLATFORM:node-->
95
+
96
+ <!--IRONBEE:PLATFORM:backend-->
97
+ <!--/IRONBEE:PLATFORM:backend-->
98
+
99
+ <!--IRONBEE:PLATFORM:android-->
100
+ <!--/IRONBEE:PLATFORM:android-->
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: ironbee-search-scenario
3
+ description: "Find reusable IronBee verification scenarios by name, description, or metadata across every enabled platform's store, using the scenario-search / scenario-list MCP tools."
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # IronBee — Search scenarios
8
+
9
+ Find saved verification **scenarios** using the devtools scenario tools directly. Read-only.
10
+
11
+ ## Steps
12
+ 1. **Pick the surface:**
13
+ - **`*_scenario-search`** (fuzzy, ranked over name + description) — discovery ("find login
14
+ scenarios").
15
+ - **`*_scenario-list` with `metadataMatch`** — precise structural lookup ("which scenarios cover
16
+ `src/auth/login.ts`"). Metadata is NOT indexed by `scenario-search`, so path/tag lookups use
17
+ `scenario-list`.
18
+ 2. **Search every enabled platform's server** (each platform is a separate server with its own
19
+ store) and union the results.
20
+ 3. **Report** name + description + platform + (for fuzzy search) relevance score; surface scope.
21
+
22
+ The platform sections below list each enabled cycle's server, tool prefix, and store dir.
23
+
24
+ <!--IRONBEE:PLATFORM:browser-->
25
+ <!--/IRONBEE:PLATFORM:browser-->
26
+
27
+ <!--IRONBEE:PLATFORM:node-->
28
+ <!--/IRONBEE:PLATFORM:node-->
29
+
30
+ <!--IRONBEE:PLATFORM:backend-->
31
+ <!--/IRONBEE:PLATFORM:backend-->
32
+
33
+ <!--IRONBEE:PLATFORM:android-->
34
+ <!--/IRONBEE:PLATFORM:android-->
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: ironbee-sync-scenario
3
+ description: "Re-validate saved IronBee verification scenarios against the current code and repair MECHANICAL drift, using the scenario-* MCP tools directly. A leading `check` token = dry-run (report drift, no repair). Never auto-changes what a scenario verifies."
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # IronBee — Sync scenario(s)
8
+
9
+ Re-validate + repair saved verification **scenarios** using the devtools `*_scenario-*` MCP tools
10
+ directly. This is NOT a verification cycle — no verdict, no gate.
11
+
12
+ > Argument: `$ARGUMENTS`
13
+
14
+ ## Steps
15
+ 1. **Resolve mode + target**: strip a leading `check` token (→ dry-run) and a leading `force` token
16
+ (→ include ALL scenarios, not just stale); remainder = `all` (stale ones; with `force`, every one)
17
+ or a name / description (one). Empty → `all`. **Print the target list + count before running.**
18
+ Run targets that share an `ironbee.group` in ascending `ironbee.order` (a flow split across platforms).
19
+ 2. **For each target scenario** (resolve via `*_scenario-search` / `*_scenario-list`; `all` = the stale
20
+ ones — covered files changed since their `ironbee.commit`, or authored as drafts) **run it**
21
+ (`*_scenario-run`, against the live app — start it if needed, tear down what you started) and classify:
22
+ - **passes** → still current; (non-check) `*_scenario-update` to stamp `ironbee.commit` → HEAD
23
+ (read via `git rev-parse HEAD`) + `ironbee.liveValidated: true`. `*_scenario-update`
24
+ shallow-replaces metadata — read current metadata and re-send it MERGED with these two keys
25
+ (don't drop `coveredPaths` / `group` / `argsSchema`).
26
+ - **mechanical DRIFT** (the way to reach / drive the flow changed, not the expected outcome) →
27
+ repair the SCRIPT mechanics only, `*_scenario-update`, re-run until green, then stamp.
28
+ - **real DEFECT** (the expected outcome is unreachable — the app broke) → **STOP, report, do NOT
29
+ touch the scenario.**
30
+ - **expectation CHANGED** (a deliberate behavior / spec change) → do NOT auto-edit the assertion;
31
+ ask the user.
32
+ - **`check` mode** → only run + report drift; never repair / update.
33
+ - **Classify safely** (repair is the only branch that edits a scenario, so a defect mistaken for
34
+ drift masks a regression): before repairing, self-check whether the fix changes *how* the flow
35
+ is driven (drift — OK to repair) or *what* it asserts (never drift — a defect → STOP, or a
36
+ deliberate change → ask). A failure while reaching / driving the flow leans drift; a failure at
37
+ the terminal assertion leans defect. **Uncertain → treat as a defect and STOP.**
38
+ 3. **Report** per scenario: repaired / still-fresh / defect-reported / needs decision.
39
+
40
+ **Hard rule: repair MECHANICS, never the ASSERTION / expected outcome** — silently relaxing an
41
+ assertion to make a stale scenario pass would mask a regression. (To just *detect* staleness without
42
+ running anything, use `ironbee scenario status`.)
43
+
44
+ <!--IRONBEE:PLATFORM:browser-->
45
+ <!--/IRONBEE:PLATFORM:browser-->
46
+
47
+ <!--IRONBEE:PLATFORM:node-->
48
+ <!--/IRONBEE:PLATFORM:node-->
49
+
50
+ <!--IRONBEE:PLATFORM:backend-->
51
+ <!--/IRONBEE:PLATFORM:backend-->
52
+
53
+ <!--IRONBEE:PLATFORM:android-->
54
+ <!--/IRONBEE:PLATFORM:android-->
@@ -22,7 +22,8 @@ The FIRST whitespace-delimited token of whatever the user provided alongside thi
22
22
 
23
23
  A custom verification scenario may be supplied when this command is invoked — either as **inline text** or as a **path to a file** (any location, any format; it is read at run time). The scenario is whatever the user provided alongside invoking this command, after stripping a leading `fix` / `report` mode token (see **Mode**).
24
24
 
25
- - **If a scenario is supplied, it is authoritative**: verify exactly what it describes. Drive each active cycle's tools to exercise precisely the flows, states, and endpoints it namesthis **replaces** the default "exercise the changed pages/endpoints" guidance.
25
+ - **If the scenario part starts with `scenario:`** (after the mode token), everything after `scenario:` (to the end) is a **SAVED scenario reference** — an exact name OR a semantic description. Resolve it across enabled platforms (`*_scenario-search` for the description + an exact-name `*_scenario-list` match), pick the single strong match (ambiguous → ask which; none → say so and fall back to the default flow), then **run it in ONE `*_scenario-run` call** (no manual re-discovery) and **judge its result (functional) + any returned visual evidence (e.g. screenshots)**. The scenario's nested tool calls satisfy each active cycle's required tools (as long as it exercises them). No exact name needede.g. `scenario: the full purchase flow`. **On PASS, keep it fresh:** `*_scenario-update` its `ironbee.commit` → HEAD (`git rev-parse HEAD`) + `liveValidated: true` (re-send the full metadata merged); on FAIL / defect, don't stamp.
26
+ - **If a scenario is supplied (free text), it is authoritative**: verify exactly what it describes. Drive each active cycle's tools to exercise precisely the flows, states, and endpoints it names — this **replaces** the default "exercise the changed pages/endpoints" guidance.
26
27
  - **If the scenario is (or points to) a file path**, read that file with your file-read tool and treat its contents as the scenario. Do not assume a fixed location or format — read whatever path was given.
27
28
  - **If the path does not resolve to an existing file**, stop and report `scenario file not found: <path>`, then ask how to proceed — do not verify the literal path string or guess a target.
28
29
  - **If no scenario is supplied**, fall back to the default flow: exercise the changed pages/endpoints per the active platform sections below.
@@ -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 l=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var x=Object.prototype.hasOwnProperty;var h=(o,t)=>l(o,"name",{value:t,configurable:!0});var k=(o,t)=>{for(var i in t)l(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&&l(o,s,{get:()=>t[s],enumerable:!(e=P(t,s))||e.enumerable});return o};var E=o=>I(l({},"__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 u={permission:"allow"};process.stdout.write(JSON.stringify(u)),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) 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),u=(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&&u){const _={file_existed:m};if(u&&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 V=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var B=Object.prototype.hasOwnProperty;var w=(o,t)=>f(o,"name",{value:t,configurable:!0});var F=(o,t)=>{for(var c in t)f(o,c,{get:t[c],enumerable:!0})},K=(o,t,c,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of x(t))!B.call(o,r)&&r!==c&&f(o,r,{get:()=>t[r],enumerable:!(s=V(t,r))||s.enumerable});return o};var j=o=>K(f({},"__esModule",{value:!0}),o);var W={};F(W,{run:()=>L});module.exports=j(W);var h=require("crypto"),e=require("../../../hooks/core/session-state"),I=require("../../../hooks/core/actions"),k=require("../../../hooks/core/activity"),O=require("../../../hooks/core/verification-lifecycle"),S=require("../../../lib/config"),U=require("../../../lib/recording-tools"),g=require("../../../lib/logger"),E=require("../../../lib/stdin");const R={"MCP:bdt_":"browser-devtools","MCP:ndt_":"node-devtools","MCP:bedt_":"backend-devtools","MCP:adt_":"android-devtools"},J="browser-devtools";async function L(o,t){const c=t?.soft===!0;let s;try{s=JSON.parse((0,E.readStdin)())}catch(n){g.logger.debug(`failed to parse stdin: ${n}`);const N={permission:"allow"};process.stdout.write(JSON.stringify(N)),process.exit(0);return}const r=s.conversation_id??"default",i=`${o}/.ironbee/sessions/${r}`;(0,g.setLogFile)(`${i}/session.log`);const C=`${i}/actions.jsonl`,P=(0,e.getActiveVerificationId)(i);if(!P&&!c){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"),O=require("../../../hooks/core/verification-lifecycle"),U=require("../../../lib/config"),E=require("../../../lib/recording-tools"),M=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"},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,M.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).
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 p=s.tool_name??"",m=p.startsWith("MCP:")?p.slice(4):"",u=m?(0,U.recordingToolsForBareTool)(m):null;if(!c&&u!==null&&(0,e.isRecordingRequired)(i)&&!(0,e.isRecordingActive)(i)&&m!==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.`};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&&!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:i,actionsFile:C,source:"pre_tool_use"});let a=P;c&&!a&&(a=(await(0,O.startVerification)({sessionId:r,sessionDir:i,actionsFile:C,recordingEnabled:!1})).verificationId);const M=(0,e.getActiveTraceId)(i),v=(0,e.getActiveActivityId)(i),b=(0,I.resolveProjectName)(o),_=[`prj:${b}`,`sid:${r}`];v&&_.push(`aid:${v}`),a&&_.push(`vid:${a}`);const $=`ironbee=${_.join(";")}`,l=(0,S.loadConfig)(o),y={...s.tool_input??{}},d={projectName:b,sessionId:r,activityId:v,verificationId:a,traceId:M,traceState:$,toolCallId:(0,h.randomUUID)()};s.tool_use_id&&(d.toolUseId=s.tool_use_id),d.mcpServer=(()=>{for(const n of Object.keys(R))if(p.startsWith(n))return R[n];return J})();const T=(0,e.getUserEmail)(i);T&&(d.userEmail=T),l.collector?.url&&(d.collectorUrl=l.collector.url),l.collector?.oauthToken?d.collectorOAuthToken=l.collector.oauthToken:l.collector?.apiKey&&(d.collectorApiKey=l.collector.apiKey),y._metadata=d;const A={permission:"allow",updated_input:y};process.stdout.write(JSON.stringify(A)),process.exit(0)}w(L,"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,O.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(";")}`,l=(0,U.loadConfig)(o),T={...i.tool_input??{}},a={projectName:y,sessionId:r,activityId:_,verificationId:d,traceId:$,traceState:V,toolCallId:(0,S.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 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 h=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var p=(t,o)=>d(t,"name",{value:o,configurable:!0});var C=(t,o)=>{for(var r in o)d(t,r,{get:o[r],enumerable:!0})},S=(t,o,r,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let n of v(o))!I.call(t,n)&&n!==r&&d(t,n,{get:()=>o[n],enumerable:!(i=h(o,n))||i.enumerable});return t};var P=t=>S(d({},"__esModule",{value:!0}),t);var x={};C(x,{run:()=>L});module.exports=P(x);var b=require("../../../hooks/core/actions"),T=require("../../../hooks/core/activity"),m=require("../../../hooks/core/session-state"),E=require("../../../lib/config"),e=require("../../../lib/logger"),c=require("../../../lib/output"),w=require("../../../lib/stdin"),l=require("../../../queue"),f=require("../util"),O=require("../../../lib/runtime-paths");const D="bdt_",J="ndt_",F="bedt_";async function L(t){let o;try{o=JSON.parse((0,w.readStdin)())}catch(u){e.logger.debug(`failed to parse stdin: ${u}`),(0,c.writeAndExit)(JSON.stringify({}),0);return}const r=o.conversation_id??"default",i=(0,O.sessionDir)(t,r),n=`${i}/actions.jsonl`;(0,e.setLogFile)(`${i}/session.log`),(0,m.getActiveActivityId)(i)===void 0&&await(0,T.startActivity)({sessionDir:i,actionsFile:n,source:"pre_tool_use"});const _=o.tool_name??"unknown",k=Date.now(),A=o.tool_input&&typeof o.tool_input=="object"&&!Array.isArray(o.tool_input)?{...o.tool_input,_metadata:void 0}:o.tool_input,N=(0,m.getActiveActivityId)(i),s=(0,f.classifyTool)(_,o.tool_input);if(s.tool_type==="mcp"&&(s.tool_name.startsWith(D)||s.tool_name.startsWith(J)||s.tool_name.startsWith(F))){e.logger.debug(`track-action-monitor: skipped devtools tool ${_}`),(0,c.writeAndExit)(JSON.stringify({}),0);return}const g=typeof o.error_message=="string"&&o.error_message.length>0?o.error_message:void 0;let a;if(g){const u=[];o.failure_type&&u.push(o.failure_type),o.is_interrupt&&u.push("interrupted"),a=`${u.length>0?`${u.join(",")}: `:""}${g}`}const $={...(0,b.baseFields)(n),type:"tool_call",timestamp:k,tool_name:s.tool_name,tool_type:s.tool_type,tool_use_id:o.tool_use_id,tool_input:(0,f.extractCursorToolInput)(_,A),tool_input_size:y(o.tool_input),tool_response:a?void 0:o.tool_output,tool_response_size:y(a?void 0:o.tool_output),activity_id:N,duration:typeof o.duration=="number"?o.duration:null,mcp_server:s.mcp_server,error:a};R(t,r,$),e.logger.debug(`track-action-monitor: ${_}${a?" (failed)":""}`),(0,c.writeAndExit)(JSON.stringify({}),0)}p(L,"run");function R(t,o,r){if(!(0,E.isJobQueueEnabled)(t))return;const i={...r};delete i.tool_response;try{(0,l.submit)(t,o,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}`)}}p(R,"submitEvent");function y(t){if(t==null)return 0;try{const o=typeof t=="string"?t:JSON.stringify(t);return o===void 0?0:Buffer.byteLength(o,"utf-8")}catch{return 0}}p(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 _=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 d;if(I){const n=[];t.failure_type&&n.push(t.failure_type),t.is_interrupt&&n.push("interrupted"),d=`${n.length>0?`${n.join(",")}: `:""}${I}`}const h={...(0,_.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:d?void 0:t.tool_output,tool_response_size:V(d?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:d};if(m){await(0,_.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}${d?" (failed)":""}`),m&&a!==null&&e.tool_name===(0,T.executeToolBareName)(a)&&!d){const n=(0,T.extractNestedToolCalls)(t.tool_input,a),u=(0,k.recordingToolsForServer)(a);for(const p of n){u!==null&&(p.name===u.startTool?((0,c.setRecordingActive)(i,!0),s.logger.debug(`track-action (nested): recording started (${u.cycle})`)):p.name===u.stopTool&&((0,c.setRecordingActive)(i,!1),s.logger.debug(`track-action (nested): recording stopped (${u.cycle})`)));const X={...(0,_.baseFields)(r),type:"tool_call",timestamp:R,tool_name:p.name,tool_type:"mcp",tool_input:p.args,activity_id:A,verification_id:O,trace_id:C,duration:null,mcp_server:a};await(0,_.appendAction)(r,X),s.logger.debug(`track-action (nested): ${p.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 y=Object.defineProperty;var K=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var Q=Object.prototype.hasOwnProperty;var g=(o,t)=>y(o,"name",{value:t,configurable:!0});var Y=(o,t)=>{for(var l in t)y(o,l,{get:t[l],enumerable:!0})},q=(o,t,l,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of j(t))!Q.call(o,r)&&r!==l&&y(o,r,{get:()=>t[r],enumerable:!(i=K(t,r))||i.enumerable});return o};var G=o=>q(y({},"__esModule",{value:!0}),o);var rt={};Y(rt,{run:()=>et});module.exports=G(rt);var p=require("../../../hooks/core/actions"),T=require("../../../hooks/core/nested-tools"),a=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"),W=require("../../../lib/runtime-paths");const N="bdt_",$="ndt_",x="bedt_",D="adt_",H="browser-devtools",Z="node-devtools",tt="backend-devtools",ot="android-devtools";function nt(o){return o.startsWith(x)?tt:o.startsWith(D)?ot:o.startsWith(N)?H:o.startsWith($)?Z:null}g(nt,"resolveServerByPrefix");async function et(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=(0,W.sessionDir)(o,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,a.getActiveActivityId)(i),O=(0,a.getActiveVerificationId)(i),C=(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($),M=e.tool_type==="mcp"&&e.tool_name.startsWith(x),z=e.tool_type==="mcp"&&e.tool_name.startsWith(D),m=B||J||M||z,c=e.tool_type==="mcp"?nt(e.tool_name)??e.mcp_server:e.mcp_server,X=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 S={...(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:X,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:c,error:u};if(m){await(0,p.appendAction)(r,S);const n=(0,k.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 it(o,l,S);if(s.logger.debug(`track-action: ${v}${u?" (failed)":""}`),m&&c!==null&&e.tool_name===(0,T.executeToolBareName)(c)&&!u){const n=(0,T.extractNestedToolCalls)(t.tool_input,c),_=(0,k.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 U={...(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:c,nested:!0,parent_tool_use_id:t.tool_use_id};await(0,p.appendAction)(r,U),s.logger.debug(`track-action (nested): ${d.name}`)}}const h={};if(m)try{const n=(0,L.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,F.writeAndExit)(JSON.stringify(h),0)}g(et,"run");function it(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(it,"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});