@ironbee-ai/cli 0.30.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/analytics/claude/emit.js +1 -1
  3. package/dist/analytics/claude/state.js +1 -1
  4. package/dist/analytics/codex/events-emit.js +2 -2
  5. package/dist/analytics/codex/subagent-transcripts.js +3 -3
  6. package/dist/clients/claude/agents/ironbee-scenario.md +4 -1
  7. package/dist/clients/claude/agents/ironbee-verifier.md +21 -3
  8. package/dist/clients/claude/hooks/activity-end.js +1 -1
  9. package/dist/clients/claude/hooks/activity-start.js +1 -1
  10. package/dist/clients/claude/hooks/clear-verdict.js +1 -1
  11. package/dist/clients/claude/hooks/require-verdict.js +2 -2
  12. package/dist/clients/claude/hooks/require-verification.js +4 -4
  13. package/dist/clients/claude/hooks/session-end.js +1 -1
  14. package/dist/clients/claude/hooks/session-start.js +4 -4
  15. package/dist/clients/claude/hooks/session-status.js +2 -2
  16. package/dist/clients/claude/hooks/subagent-start.js +1 -1
  17. package/dist/clients/claude/hooks/subagent-stop.js +1 -1
  18. package/dist/clients/claude/hooks/track-action-monitor.js +1 -1
  19. package/dist/clients/claude/hooks/track-action.js +1 -1
  20. package/dist/clients/claude/hooks/verify-gate.js +4 -4
  21. package/dist/clients/claude/index.js +4 -4
  22. package/dist/clients/claude/platforms/scenario.android.md +1 -0
  23. package/dist/clients/claude/platforms/scenario.terminal.md +26 -0
  24. package/dist/clients/claude/platforms/skill.android.md +4 -0
  25. package/dist/clients/claude/platforms/skill.browser.md +1 -1
  26. package/dist/clients/claude/platforms/skill.terminal.md +62 -0
  27. package/dist/clients/claude/process-analytics.js +1 -1
  28. package/dist/clients/claude/statusline-toggle.js +2 -2
  29. package/dist/clients/codex/agents/ironbee-scenario.md +3 -0
  30. package/dist/clients/codex/agents/ironbee-verifier.md +20 -2
  31. package/dist/clients/codex/commands/ironbee-manage-scenario/SKILL.main.md +3 -0
  32. package/dist/clients/codex/commands/ironbee-search-scenario/SKILL.main.md +3 -0
  33. package/dist/clients/codex/commands/ironbee-sync-scenario/SKILL.main.md +3 -0
  34. package/dist/clients/codex/commands/ironbee-verify/SKILL.main.md +3 -0
  35. package/dist/clients/codex/hooks/activity-end.js +1 -1
  36. package/dist/clients/codex/hooks/activity-start.js +1 -1
  37. package/dist/clients/codex/hooks/clear-verdict.js +3 -3
  38. package/dist/clients/codex/hooks/require-verdict.js +2 -2
  39. package/dist/clients/codex/hooks/require-verification.js +3 -3
  40. package/dist/clients/codex/hooks/session-start.js +3 -3
  41. package/dist/clients/codex/hooks/subagent-start.js +1 -1
  42. package/dist/clients/codex/hooks/subagent-stop.js +1 -1
  43. package/dist/clients/codex/hooks/track-action-monitor.js +1 -1
  44. package/dist/clients/codex/hooks/track-action-pre.js +1 -1
  45. package/dist/clients/codex/hooks/track-action.js +1 -1
  46. package/dist/clients/codex/hooks/verify-gate.js +1 -1
  47. package/dist/clients/codex/index.js +2 -2
  48. package/dist/clients/codex/platforms/command-verify.android.md +1 -0
  49. package/dist/clients/codex/platforms/command-verify.terminal.md +61 -0
  50. package/dist/clients/codex/platforms/rule.android.md +2 -1
  51. package/dist/clients/codex/platforms/rule.terminal.md +31 -0
  52. package/dist/clients/codex/platforms/scenario.android.md +1 -0
  53. package/dist/clients/codex/platforms/scenario.terminal.md +36 -0
  54. package/dist/clients/codex/platforms/skill.android.md +4 -0
  55. package/dist/clients/codex/platforms/skill.browser.md +1 -1
  56. package/dist/clients/codex/platforms/skill.terminal.md +57 -0
  57. package/dist/clients/codex/process-analytics.js +2 -2
  58. package/dist/clients/codex/rules/ironbee-verification.main.md +3 -0
  59. package/dist/clients/codex/skills/ironbee-verification.main.md +3 -0
  60. package/dist/clients/codex/thread-map.js +1 -1
  61. package/dist/clients/codex/util.js +44 -31
  62. package/dist/clients/cursor/commands/ironbee-manage-scenario/SKILL.md +3 -0
  63. package/dist/clients/cursor/commands/ironbee-search-scenario/SKILL.md +3 -0
  64. package/dist/clients/cursor/commands/ironbee-sync-scenario/SKILL.md +3 -0
  65. package/dist/clients/cursor/commands/ironbee-verify/SKILL.md +3 -0
  66. package/dist/clients/cursor/hooks/activity-end.js +1 -1
  67. package/dist/clients/cursor/hooks/activity-start.js +1 -1
  68. package/dist/clients/cursor/hooks/clear-verdict.js +1 -1
  69. package/dist/clients/cursor/hooks/require-verdict.js +2 -2
  70. package/dist/clients/cursor/hooks/require-verification.js +3 -3
  71. package/dist/clients/cursor/hooks/session-end.js +1 -1
  72. package/dist/clients/cursor/hooks/session-start.js +4 -4
  73. package/dist/clients/cursor/hooks/track-action-monitor.js +1 -1
  74. package/dist/clients/cursor/hooks/track-action.js +1 -1
  75. package/dist/clients/cursor/hooks/verify-gate.js +1 -1
  76. package/dist/clients/cursor/index.js +1 -1
  77. package/dist/clients/cursor/platforms/command-verify.android.md +1 -0
  78. package/dist/clients/cursor/platforms/command-verify.terminal.md +61 -0
  79. package/dist/clients/cursor/platforms/rule.android.md +2 -1
  80. package/dist/clients/cursor/platforms/rule.terminal.md +31 -0
  81. package/dist/clients/cursor/platforms/scenario.android.md +1 -0
  82. package/dist/clients/cursor/platforms/scenario.terminal.md +29 -0
  83. package/dist/clients/cursor/platforms/skill.android.md +4 -0
  84. package/dist/clients/cursor/platforms/skill.browser.md +1 -1
  85. package/dist/clients/cursor/platforms/skill.terminal.md +54 -0
  86. package/dist/clients/cursor/rules/ironbee-verification.mdc +3 -0
  87. package/dist/clients/cursor/skills/ironbee-verification.md +9 -0
  88. package/dist/commands/config.js +2 -2
  89. package/dist/commands/hook.js +10 -10
  90. package/dist/commands/import.js +3 -3
  91. package/dist/commands/install.js +1 -1
  92. package/dist/commands/process-job-file.js +1 -1
  93. package/dist/commands/queue.js +16 -16
  94. package/dist/commands/scenario.js +1 -1
  95. package/dist/commands/status.js +1 -1
  96. package/dist/commands/terminal.js +1 -0
  97. package/dist/commands/uninstall.js +1 -1
  98. package/dist/commands/verify.js +2 -2
  99. package/dist/hooks/core/actions.js +7 -7
  100. package/dist/hooks/core/session-state.js +1 -1
  101. package/dist/hooks/core/verification-context.js +19 -15
  102. package/dist/hooks/core/verify-gate.js +25 -20
  103. package/dist/import/claude/events/tool-call.js +1 -1
  104. package/dist/import/codex/events/tool-call.js +1 -1
  105. package/dist/import/marker.js +2 -2
  106. package/dist/import/skip.js +1 -1
  107. package/dist/index.js +1 -1
  108. package/dist/lib/config.js +1 -1
  109. package/dist/lib/install-version.js +1 -1
  110. package/dist/lib/platform-section.js +5 -4
  111. package/dist/lib/runtime-paths.js +1 -0
  112. package/dist/lib/scenario-staleness.js +1 -1
  113. package/dist/otel/claude/daemon/process.js +1 -1
  114. package/dist/otel/claude/daemon/reprocess.js +1 -1
  115. package/dist/otel/claude/daemon/response-usage.js +2 -2
  116. package/dist/queue/drain.js +1 -1
  117. package/dist/queue/flush.js +1 -1
  118. package/dist/queue/paths.js +1 -1
  119. package/dist/queue/process-file.js +2 -2
  120. package/dist/queue/spawn.js +1 -1
  121. package/dist/tui/config/schema.js +1 -1
  122. package/dist/tui/platforms/area.js +2 -2
  123. package/dist/tui/queue/read.js +4 -4
  124. package/dist/tui/sessions/read.js +2 -2
  125. package/package.json +1 -1
@@ -1 +1 @@
1
- "use strict";var s=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var u=Object.prototype.hasOwnProperty;var a=(n,t)=>s(n,"name",{value:t,configurable:!0});var _=(n,t)=>{for(var o in t)s(n,o,{get:t[o],enumerable:!0})},x=(n,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of f(t))!u.call(n,e)&&e!==o&&s(n,e,{get:()=>t[e],enumerable:!(r=m(t,e))||r.enumerable});return n};var h=n=>x(s({},"__esModule",{value:!0}),n);var b={};_(b,{run:()=>S});module.exports=h(b);var i=require("../../../lib/logger"),p=require("../../../lib/stdin"),d=require("../util"),g=require("../thread-map"),c=require("../../../analytics/codex/subagent-transcripts");async function S(n){const t=(0,d.parseCodexHookStdin)((0,p.readStdin)()),o=t.session_id??"",r=t.agent_id??"";if(!r){process.exit(0);return}o&&(0,i.setLogFile)(`${n}/.ironbee/sessions/${o}/session.log`),(0,g.pruneThreadMapping)(n,r);const e=t.agent_transcript_path??"";o&&e&&(0,c.recordSubagentTranscript)(n,o,{agent_id:r,agent_type:t.agent_type,transcript_path:e,ts:Date.now()}),i.logger.debug(`subagent-stop: pruned thread ${r}; recorded transcript=${e||"(none)"}`),process.exit(0)}a(S,"run");0&&(module.exports={run});
1
+ "use strict";var i=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var a=(n,t)=>i(n,"name",{value:t,configurable:!0});var x=(n,t)=>{for(var o in t)i(n,o,{get:t[o],enumerable:!0})},h=(n,t,o,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of u(t))!_.call(n,r)&&r!==o&&i(n,r,{get:()=>t[r],enumerable:!(e=f(t,r))||e.enumerable});return n};var S=n=>h(i({},"__esModule",{value:!0}),n);var k={};x(k,{run:()=>b});module.exports=S(k);var s=require("../../../lib/logger"),p=require("../../../lib/stdin"),d=require("../util"),g=require("../thread-map"),c=require("../../../analytics/codex/subagent-transcripts"),m=require("../../../lib/runtime-paths");async function b(n){const t=(0,d.parseCodexHookStdin)((0,p.readStdin)()),o=t.session_id??"",e=t.agent_id??"";if(!e){process.exit(0);return}o&&(0,s.setLogFile)((0,m.sessionLogFile)(n,o)),(0,g.pruneThreadMapping)(n,e);const r=t.agent_transcript_path??"";o&&r&&(0,c.recordSubagentTranscript)(n,o,{agent_id:e,agent_type:t.agent_type,transcript_path:r,ts:Date.now()}),s.logger.debug(`subagent-stop: pruned thread ${e}; recorded transcript=${r||"(none)"}`),process.exit(0)}a(b,"run");0&&(module.exports={run});
@@ -1 +1 @@
1
- "use strict";var f=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var m=(o,t)=>f(o,"name",{value:t,configurable:!0});var B=(o,t)=>{for(var e in t)f(o,e,{get:t[e],enumerable:!0})},L=(o,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of J(t))!F.call(o,r)&&r!==e&&f(o,r,{get:()=>t[r],enumerable:!(n=$(t,r))||n.enumerable});return o};var M=o=>L(f({},"__esModule",{value:!0}),o);var P={};B(P,{run:()=>z});module.exports=M(P);var k=require("../../../hooks/core/actions"),C=require("../../../import/ids"),h=require("../../../hooks/core/activity"),S=require("../../../hooks/core/session-state"),v=require("../../../hooks/core/tool-use-stash"),I=require("../../../lib/config"),s=require("../../../lib/logger"),y=require("../../../lib/output"),N=require("../../../lib/stdin"),l=require("../../../queue"),i=require("../util");function O(o){if(o==null)return{isError:!1};if(typeof o=="object"&&o!==null){const t=o;if(t.isError===!0||t.is_error===!0){const e=t.error??t.message??t.errorMessage;return{isError:!0,errorText:typeof e=="string"?e:JSON.stringify(t).slice(0,500)}}}if(typeof o=="string"){const t=o;if(/(?:^|\n)Process exited with code [1-9]/.test(t)||/^Exit code:\s*[1-9]/m.test(t)||/apply_patch verification failed/i.test(t)||/failed to find expected lines/i.test(t)||/^\s*Error\b/.test(t)||/(?:^|\n)\[Request interrupted by user\]/.test(t)||/modified since (?:last )?read|stale read/i.test(t)||/file (?:is )?too large|exceeds/i.test(t)||/file not found|No such file or directory|does not exist/i.test(t))return{isError:!0,errorText:t.slice(0,500)}}return{isError:!1}}m(O,"detectFailureMonitor");function w(o){if(o==null)return 0;if(typeof o=="string")try{return Buffer.byteLength(o,"utf8")}catch{return 0}try{return Buffer.byteLength(JSON.stringify(o),"utf8")}catch{return 0}}m(w,"safeStringifyBytes");async function z(o){const t=(0,i.parseCodexHookStdin)((0,N.readStdin)()),e=t.session_id??"default",n=`${o}/.ironbee/sessions/${e}`,r=`${n}/actions.jsonl`;if((0,s.setLogFile)(`${n}/session.log`),await(0,h.startActivity)({sessionDir:n,actionsFile:r,source:"pre_tool_use"}),!(0,I.isJobQueueEnabled)(o)){(0,y.writeAndExit)(JSON.stringify({}),0);return}const u=t.tool_name??"",d=t.tool_use_id??"",_=t.tool_input,T=t.tool_response,g=(0,i.classifyCodexTool)(u),x=(0,S.getActiveActivityId)(n),A=(0,i.extractCodexToolInput)(u,_),b=(0,v.consumeToolUseData)(e,d);let E=null;if(b?.start_ns)try{E=Number((process.hrtime.bigint()-BigInt(b.start_ns))/1000000n)}catch(c){s.logger.debug(`derive duration failed: ${c}`)}const p=O(T),a={...(0,k.baseFields)(r),type:"tool_call",timestamp:Date.now(),tool_type:g.tool_type,tool_name:g.tool_name||(0,i.normalizeCodexToolName)(u),mcp_server:g.mcp_server,tool_input:A,tool_input_size:w(_),tool_response_size:p.isError?0:w(T),duration:E};x&&(a.activity_id=x),d&&(a.tool_use_id=d),d.length>0&&(a.id=(0,C.deriveToolCallEventIdFromToolUseId)(e,d)),p.isError&&(a.error=p.errorText);try{(0,l.submit)(o,e,l.SEND_EVENT_TYPE,a)}catch(c){c instanceof l.JobTooLargeError?s.logger.debug(`track-action-monitor: wire event too large for tool_call ${u}; dropping`):s.logger.debug(`queue submit failed for tool_call ${u}: ${c}`)}(0,y.writeAndExit)(JSON.stringify({}),0)}m(z,"run");0&&(module.exports={run});
1
+ "use strict";var c=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var B=Object.prototype.hasOwnProperty;var m=(o,t)=>c(o,"name",{value:t,configurable:!0});var D=(o,t)=>{for(var e in t)c(o,e,{get:t[e],enumerable:!0})},L=(o,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of F(t))!B.call(o,r)&&r!==e&&c(o,r,{get:()=>t[r],enumerable:!(n=$(t,r))||n.enumerable});return o};var M=o=>L(c({},"__esModule",{value:!0}),o);var P={};D(P,{run:()=>z});module.exports=M(P);var k=require("../../../hooks/core/actions"),C=require("../../../import/ids"),S=require("../../../hooks/core/activity"),h=require("../../../hooks/core/session-state"),v=require("../../../hooks/core/tool-use-stash"),I=require("../../../lib/config"),s=require("../../../lib/logger"),y=require("../../../lib/output"),N=require("../../../lib/stdin"),l=require("../../../queue"),A=require("../../../lib/runtime-paths"),i=require("../util");function O(o){if(o==null)return{isError:!1};if(typeof o=="object"&&o!==null){const t=o;if(t.isError===!0||t.is_error===!0){const e=t.error??t.message??t.errorMessage;return{isError:!0,errorText:typeof e=="string"?e:JSON.stringify(t).slice(0,500)}}}if(typeof o=="string"){const t=o;if(/(?:^|\n)Process exited with code [1-9]/.test(t)||/^Exit code:\s*[1-9]/m.test(t)||/apply_patch verification failed/i.test(t)||/failed to find expected lines/i.test(t)||/^\s*Error\b/.test(t)||/(?:^|\n)\[Request interrupted by user\]/.test(t)||/modified since (?:last )?read|stale read/i.test(t)||/file (?:is )?too large|exceeds/i.test(t)||/file not found|No such file or directory|does not exist/i.test(t))return{isError:!0,errorText:t.slice(0,500)}}return{isError:!1}}m(O,"detectFailureMonitor");function w(o){if(o==null)return 0;if(typeof o=="string")try{return Buffer.byteLength(o,"utf8")}catch{return 0}try{return Buffer.byteLength(JSON.stringify(o),"utf8")}catch{return 0}}m(w,"safeStringifyBytes");async function z(o){const t=(0,i.parseCodexHookStdin)((0,N.readStdin)()),e=t.session_id??"default",n=(0,A.sessionDir)(o,e),r=`${n}/actions.jsonl`;if((0,s.setLogFile)(`${n}/session.log`),await(0,S.startActivity)({sessionDir:n,actionsFile:r,source:"pre_tool_use"}),!(0,I.isJobQueueEnabled)(o)){(0,y.writeAndExit)(JSON.stringify({}),0);return}const u=t.tool_name??"",a=t.tool_use_id??"",_=t.tool_input,T=t.tool_response,g=(0,i.classifyCodexTool)(u),x=(0,h.getActiveActivityId)(n),J=(0,i.extractCodexToolInput)(u,_),b=(0,v.consumeToolUseData)(e,a);let E=null;if(b?.start_ns)try{E=Number((process.hrtime.bigint()-BigInt(b.start_ns))/1000000n)}catch(f){s.logger.debug(`derive duration failed: ${f}`)}const p=O(T),d={...(0,k.baseFields)(r),type:"tool_call",timestamp:Date.now(),tool_type:g.tool_type,tool_name:g.tool_name||(0,i.normalizeCodexToolName)(u),mcp_server:g.mcp_server,tool_input:J,tool_input_size:w(_),tool_response_size:p.isError?0:w(T),duration:E};x&&(d.activity_id=x),a&&(d.tool_use_id=a),a.length>0&&(d.id=(0,C.deriveToolCallEventIdFromToolUseId)(e,a)),p.isError&&(d.error=p.errorText);try{(0,l.submit)(o,e,l.SEND_EVENT_TYPE,d)}catch(f){f instanceof l.JobTooLargeError?s.logger.debug(`track-action-monitor: wire event too large for tool_call ${u}; dropping`):s.logger.debug(`queue submit failed for tool_call ${u}: ${f}`)}(0,y.writeAndExit)(JSON.stringify({}),0)}m(z,"run");0&&(module.exports={run});
@@ -1 +1 @@
1
- "use strict";var r=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var f=Object.prototype.hasOwnProperty;var a=(o,t)=>r(o,"name",{value:t,configurable:!0});var x=(o,t)=>{for(var s in t)r(o,s,{get:t[s],enumerable:!0})},u=(o,t,s,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of m(t))!f.call(o,e)&&e!==s&&r(o,e,{get:()=>t[e],enumerable:!(i=c(t,e))||i.enumerable});return o};var l=o=>u(r({},"__esModule",{value:!0}),o);var _={};x(_,{run:()=>S});module.exports=l(_);var n=require("../../../lib/logger"),d=require("../../../lib/stdin"),p=require("../../../hooks/core/tool-use-stash"),g=require("../util");async function S(o){const t=(0,g.parseCodexHookStdin)((0,d.readStdin)()),s=t.session_id??"",i=t.tool_use_id??"";if(!s||!i){process.exit(0);return}(0,n.setLogFile)(`${o}/.ironbee/sessions/${s}/session.log`);const e={start_ns:process.hrtime.bigint().toString()};(0,p.stashToolUseData)(s,i,e),n.logger.debug(`track-action-pre: stashed start_ns for ${i}`),process.exit(0)}a(S,"run");0&&(module.exports={run});
1
+ "use strict";var i=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var x=Object.prototype.hasOwnProperty;var a=(o,t)=>i(o,"name",{value:t,configurable:!0});var u=(o,t)=>{for(var s in t)i(o,s,{get:t[s],enumerable:!0})},l=(o,t,s,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of f(t))!x.call(o,e)&&e!==s&&i(o,e,{get:()=>t[e],enumerable:!(r=c(t,e))||r.enumerable});return o};var S=o=>l(i({},"__esModule",{value:!0}),o);var C={};u(C,{run:()=>_});module.exports=S(C);var n=require("../../../lib/logger"),p=require("../../../lib/stdin"),d=require("../../../hooks/core/tool-use-stash"),m=require("../util"),g=require("../../../lib/runtime-paths");async function _(o){const t=(0,m.parseCodexHookStdin)((0,p.readStdin)()),s=t.session_id??"",r=t.tool_use_id??"";if(!s||!r){process.exit(0);return}(0,n.setLogFile)((0,g.sessionLogFile)(o,s));const e={start_ns:process.hrtime.bigint().toString()};(0,d.stashToolUseData)(s,r,e),n.logger.debug(`track-action-pre: stashed start_ns for ${r}`),process.exit(0)}a(_,"run");0&&(module.exports={run});
@@ -1 +1 @@
1
- "use strict";var N=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var b=(t,e)=>N(t,"name",{value:e,configurable:!0});var X=(t,e)=>{for(var o in e)N(t,o,{get:e[o],enumerable:!0})},Z=(t,e,o,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of K(e))!W.call(t,i)&&i!==o&&N(t,i,{get:()=>e[i],enumerable:!(n=G(e,i))||n.enumerable});return t};var ee=t=>Z(N({},"__esModule",{value:!0}),t);var ie={};X(ie,{run:()=>re});module.exports=ee(ie);var T=require("../../../hooks/core/actions"),v=require("../../../hooks/core/nested-tools"),R=require("../../../import/ids"),r=require("../../../hooks/core/session-state"),L=require("../../../hooks/core/tool-use-stash"),P=require("../../../lib/config"),a=require("../../../lib/logger"),h=require("../../../lib/output"),U=require("../../../lib/recording-tools"),q=require("../../../lib/stdin"),x=require("../../../queue"),d=require("../util");function A(t){if(t==null)return 0;if(typeof t=="string")try{return Buffer.byteLength(t,"utf8")}catch{return 0}try{return Buffer.byteLength(JSON.stringify(t),"utf8")}catch{return 0}}b(A,"safeStringifyBytes");function te(t){if(t==null)return{isError:!1,errorText:void 0};if(typeof t=="object"&&t!==null){const e=t;if(e.isError===!0||e.is_error===!0){const o=e.error??e.message??e.errorMessage;return{isError:!0,errorText:typeof o=="string"?o:JSON.stringify(e).slice(0,500)}}}if(typeof t=="string"){const e=t;if(/(?:^|\n)Process exited with code [1-9]/.test(e)||/^Exit code:\s*[1-9]/m.test(e)||/apply_patch verification failed/i.test(e)||/failed to find expected lines/i.test(e)||/^\s*Error\b/.test(e)||/(?:^|\n)\[Request interrupted by user\]/.test(e)||/modified since (?:last )?read|stale read/i.test(e)||/file (?:is )?too large|exceeds/i.test(e)||/file not found|No such file or directory|does not exist/i.test(e))return{isError:!0,errorText:e.slice(0,500)}}return{isError:!1,errorText:void 0}}b(te,"detectFailure");function oe(t){if(t===null||typeof t!="object")return;const e=t._metadata;if(e===null||typeof e!="object")return;const o=e.toolCallId;if(typeof o=="string"&&/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(o))return o}b(oe,"extractMetadataToolCallId");function ne(t,e){const o=(0,L.consumeToolUseData)(t,e);if(!o?.start_ns)return null;try{const n=process.hrtime.bigint()-BigInt(o.start_ns);return Number(n/1000000n)}catch(n){return a.logger.debug(`failed to derive duration from stash: ${n}`),null}}b(ne,"deriveDurationMs");async function re(t){const e=(0,d.parseCodexHookStdin)((0,q.readStdin)()),o=e.session_id??"default",n=`${t}/.ironbee/sessions/${o}`,i=`${n}/actions.jsonl`;(0,a.setLogFile)(`${n}/session.log`);const y=e.tool_name??"",s=e.tool_use_id??"",g=e.tool_input,$=g&&typeof g=="object"?{...g,_metadata:void 0}:void 0,C=e.tool_response,l=(0,d.extractCodexMcpServer)(y),z=l==="browser-devtools"||l==="node-devtools"||l==="backend-devtools"||l==="android-devtools",F=ne(o,s),c=(0,d.classifyCodexTool)(y),J=z&&(0,v.isNestedToolContainer)(c.tool_name,l),D=J?(0,v.extractNestedToolCallsFromResponse)(C,l):null,u=D!==null?{isError:!1,errorText:void 0}:te(C);if(z){const w=c.tool_name,f=(0,U.recordingToolsForServer)(l);f!==null&&(w===f.startTool?(0,r.setRecordingActive)(n,!0):w===f.stopTool&&(0,r.setRecordingActive)(n,!1));const E=(0,r.getActiveActivityId)(n),m={...(0,T.baseFields)(i),type:"tool_call",timestamp:Date.now(),tool_type:c.tool_type,tool_name:c.tool_name,mcp_server:c.mcp_server??l,tool_input:$,tool_input_size:A($),tool_response:u.isError?void 0:C,tool_response_size:u.isError?0:A(C),duration:F};E&&(m.activity_id=E);const B=oe(g);B!==void 0?m.id=B:s.length>0&&(m.id=(0,R.deriveToolCallEventIdFromToolUseId)(o,s)),s&&(m.tool_use_id=s);const k=(0,r.getActiveVerificationId)(n);k&&(m.verification_id=k);const I=(0,r.getActiveTraceId)(n);if(I&&(m.trace_id=I),u.isError&&(m.error=u.errorText),await(0,T.appendAction)(i,m),J&&!u.isError){const Y=D??(0,v.extractNestedToolCalls)($??g,l);for(const _ of Y){f!==null&&(_.name===f.startTool?((0,r.setRecordingActive)(n,!0),a.logger.debug(`track-action (nested): recording started (${f.cycle})`)):_.name===f.stopTool&&((0,r.setRecordingActive)(n,!1),a.logger.debug(`track-action (nested): recording stopped (${f.cycle})`)));const S={...(0,T.baseFields)(i),type:"tool_call",timestamp:_.startTime??Date.now(),tool_name:_.name,tool_type:"mcp",tool_input:_.args,duration:_.duration??null,mcp_server:l,nested:!0,...s?{parent_tool_use_id:s}:{}};E&&(S.activity_id=E),k&&(S.verification_id=k),I&&(S.trace_id=I),await(0,T.appendAction)(i,S),a.logger.debug(`track-action (nested): ${_.name}`)}}(0,h.writeAndExit)(JSON.stringify({}),0);return}if(!(0,P.isJobQueueEnabled)(t)){(0,h.writeAndExit)(JSON.stringify({}),0);return}const M=(0,r.getActiveActivityId)(n),H=(0,d.extractCodexToolInput)(y,g),V=A(g),Q=u.isError?0:A(C),p={...(0,T.baseFields)(i),type:"tool_call",timestamp:Date.now(),tool_type:c.tool_type,tool_name:c.tool_name||(0,d.normalizeCodexToolName)(y),mcp_server:c.mcp_server,tool_input:H,tool_input_size:V,tool_response_size:Q,duration:F};M&&(p.activity_id=M),s.length>0&&(p.id=(0,R.deriveToolCallEventIdFromToolUseId)(o,s)),s&&(p.tool_use_id=s);const O=(0,r.getActiveVerificationId)(n);O&&(p.verification_id=O);const j=(0,r.getActiveTraceId)(n);j&&(p.trace_id=j),u.isError&&(p.error=u.errorText);try{(0,x.submit)(t,o,x.SEND_EVENT_TYPE,p)}catch(w){w instanceof x.JobTooLargeError?a.logger.debug(`track-action: wire event too large for tool_call ${y}; dropping`):a.logger.debug(`queue submit failed for tool_call ${y}: ${w}`)}(0,h.writeAndExit)(JSON.stringify({}),0)}b(re,"run");0&&(module.exports={run});
1
+ "use strict";var N=Object.defineProperty;var K=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var X=Object.prototype.hasOwnProperty;var b=(t,e)=>N(t,"name",{value:e,configurable:!0});var Z=(t,e)=>{for(var o in e)N(t,o,{get:e[o],enumerable:!0})},ee=(t,e,o,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of W(e))!X.call(t,i)&&i!==o&&N(t,i,{get:()=>e[i],enumerable:!(n=K(e,i))||n.enumerable});return t};var te=t=>ee(N({},"__esModule",{value:!0}),t);var se={};Z(se,{run:()=>ie});module.exports=te(se);var T=require("../../../hooks/core/actions"),v=require("../../../hooks/core/nested-tools"),$=require("../../../import/ids"),L=require("../../../lib/runtime-paths"),r=require("../../../hooks/core/session-state"),P=require("../../../hooks/core/tool-use-stash"),U=require("../../../lib/config"),a=require("../../../lib/logger"),h=require("../../../lib/output"),q=require("../../../lib/recording-tools"),H=require("../../../lib/stdin"),x=require("../../../queue"),d=require("../util");function A(t){if(t==null)return 0;if(typeof t=="string")try{return Buffer.byteLength(t,"utf8")}catch{return 0}try{return Buffer.byteLength(JSON.stringify(t),"utf8")}catch{return 0}}b(A,"safeStringifyBytes");function oe(t){if(t==null)return{isError:!1,errorText:void 0};if(typeof t=="object"&&t!==null){const e=t;if(e.isError===!0||e.is_error===!0){const o=e.error??e.message??e.errorMessage;return{isError:!0,errorText:typeof o=="string"?o:JSON.stringify(e).slice(0,500)}}}if(typeof t=="string"){const e=t;if(/(?:^|\n)Process exited with code [1-9]/.test(e)||/^Exit code:\s*[1-9]/m.test(e)||/apply_patch verification failed/i.test(e)||/failed to find expected lines/i.test(e)||/^\s*Error\b/.test(e)||/(?:^|\n)\[Request interrupted by user\]/.test(e)||/modified since (?:last )?read|stale read/i.test(e)||/file (?:is )?too large|exceeds/i.test(e)||/file not found|No such file or directory|does not exist/i.test(e))return{isError:!0,errorText:e.slice(0,500)}}return{isError:!1,errorText:void 0}}b(oe,"detectFailure");function ne(t){if(t===null||typeof t!="object")return;const e=t._metadata;if(e===null||typeof e!="object")return;const o=e.toolCallId;if(typeof o=="string"&&/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(o))return o}b(ne,"extractMetadataToolCallId");function re(t,e){const o=(0,P.consumeToolUseData)(t,e);if(!o?.start_ns)return null;try{const n=process.hrtime.bigint()-BigInt(o.start_ns);return Number(n/1000000n)}catch(n){return a.logger.debug(`failed to derive duration from stash: ${n}`),null}}b(re,"deriveDurationMs");async function ie(t){const e=(0,d.parseCodexHookStdin)((0,H.readStdin)()),o=e.session_id??"default",n=(0,L.sessionDir)(t,o),i=`${n}/actions.jsonl`;(0,a.setLogFile)(`${n}/session.log`);const y=e.tool_name??"",s=e.tool_use_id??"",g=e.tool_input,R=g&&typeof g=="object"?{...g,_metadata:void 0}:void 0,C=e.tool_response,l=(0,d.extractCodexMcpServer)(y),D=l==="browser-devtools"||l==="node-devtools"||l==="backend-devtools"||l==="android-devtools"||l==="terminal-devtools",z=re(o,s),c=(0,d.classifyCodexTool)(y),F=D&&(0,v.isNestedToolContainer)(c.tool_name,l),J=F?(0,v.extractNestedToolCallsFromResponse)(C,l):null,f=J!==null?{isError:!1,errorText:void 0}:oe(C);if(D){const w=c.tool_name,u=(0,q.recordingToolsForServer)(l);u!==null&&(w===u.startTool?(0,r.setRecordingActive)(n,!0):w===u.stopTool&&(0,r.setRecordingActive)(n,!1));const E=(0,r.getActiveActivityId)(n),m={...(0,T.baseFields)(i),type:"tool_call",timestamp:Date.now(),tool_type:c.tool_type,tool_name:c.tool_name,mcp_server:c.mcp_server??l,tool_input:R,tool_input_size:A(R),tool_response:f.isError?void 0:C,tool_response_size:f.isError?0:A(C),duration:z};E&&(m.activity_id=E);const B=ne(g);B!==void 0?m.id=B:s.length>0&&(m.id=(0,$.deriveToolCallEventIdFromToolUseId)(o,s)),s&&(m.tool_use_id=s);const k=(0,r.getActiveVerificationId)(n);k&&(m.verification_id=k);const S=(0,r.getActiveTraceId)(n);if(S&&(m.trace_id=S),f.isError&&(m.error=f.errorText),await(0,T.appendAction)(i,m),F&&!f.isError){const G=J??(0,v.extractNestedToolCalls)(R??g,l);for(const _ of G){u!==null&&(_.name===u.startTool?((0,r.setRecordingActive)(n,!0),a.logger.debug(`track-action (nested): recording started (${u.cycle})`)):_.name===u.stopTool&&((0,r.setRecordingActive)(n,!1),a.logger.debug(`track-action (nested): recording stopped (${u.cycle})`)));const I={...(0,T.baseFields)(i),type:"tool_call",timestamp:_.startTime??Date.now(),tool_name:_.name,tool_type:"mcp",tool_input:_.args,duration:_.duration??null,mcp_server:l,nested:!0,...s?{parent_tool_use_id:s}:{}};E&&(I.activity_id=E),k&&(I.verification_id=k),S&&(I.trace_id=S),await(0,T.appendAction)(i,I),a.logger.debug(`track-action (nested): ${_.name}`)}}(0,h.writeAndExit)(JSON.stringify({}),0);return}if(!(0,U.isJobQueueEnabled)(t)){(0,h.writeAndExit)(JSON.stringify({}),0);return}const M=(0,r.getActiveActivityId)(n),V=(0,d.extractCodexToolInput)(y,g),Q=A(g),Y=f.isError?0:A(C),p={...(0,T.baseFields)(i),type:"tool_call",timestamp:Date.now(),tool_type:c.tool_type,tool_name:c.tool_name||(0,d.normalizeCodexToolName)(y),mcp_server:c.mcp_server,tool_input:V,tool_input_size:Q,tool_response_size:Y,duration:z};M&&(p.activity_id=M),s.length>0&&(p.id=(0,$.deriveToolCallEventIdFromToolUseId)(o,s)),s&&(p.tool_use_id=s);const O=(0,r.getActiveVerificationId)(n);O&&(p.verification_id=O);const j=(0,r.getActiveTraceId)(n);j&&(p.trace_id=j),f.isError&&(p.error=f.errorText);try{(0,x.submit)(t,o,x.SEND_EVENT_TYPE,p)}catch(w){w instanceof x.JobTooLargeError?a.logger.debug(`track-action: wire event too large for tool_call ${y}; dropping`):a.logger.debug(`queue submit failed for tool_call ${y}: ${w}`)}(0,h.writeAndExit)(JSON.stringify({}),0)}b(ie,"run");0&&(module.exports={run});
@@ -1 +1 @@
1
- "use strict";var c=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var x=Object.prototype.hasOwnProperty;var p=(e,i)=>c(e,"name",{value:i,configurable:!0});var C=(e,i)=>{for(var t in i)c(e,t,{get:i[t],enumerable:!0})},$=(e,i,t,s)=>{if(i&&typeof i=="object"||typeof i=="function")for(let n of h(i))!x.call(e,n)&&n!==t&&c(e,n,{get:()=>i[n],enumerable:!(s=I(i,n))||s.enumerable});return e};var E=e=>$(c({},"__esModule",{value:!0}),e);var _={};C(_,{run:()=>R});module.exports=E(_);var r=require("../../../hooks/core/actions"),y=require("../../../hooks/core/activity"),S=require("../../../hooks/core/verify-gate"),f=require("../../../lib/config"),a=require("../../../lib/logger"),m=require("../../../lib/output"),v=require("../../../lib/stdin"),l=require("../../../queue"),k=require("../../../analytics/codex/spawn"),u=require("../../../hooks/core/session-state"),w=require("../util");async function R(e){const i=(0,w.parseCodexHookStdin)((0,v.readStdin)()),t=i.session_id??"default";(0,a.setLogFile)(`${e}/.ironbee/sessions/${t}/session.log`);const s=`${e}/.ironbee/sessions/${t}`,n=`${s}/actions.jsonl`,g=(0,f.loadConfig)(e),d=await(0,S.runVerifyGate)({sessionId:t,sessionDir:s,actionsFile:n,verdictFile:`${s}/verdict.json`,maxRetries:(0,f.getMaxRetries)(g),config:g,projectDir:e}),b=(0,u.readState)(s)?.activeActivityId??"";if(d.action==="allow"?await(0,y.endActivity)({sessionDir:s,actionsFile:n}):!1){const o=Date.now(),A={...(0,r.baseFields)(n),id:(0,r.deterministicSessionEndId)(t),type:"session_end",timestamp:o,session_id:t,duration:(0,r.findDurationSinceLastAction)(n,"session_start",o),reason:"checkpoint"};await(0,r.appendAction)(n,A)}try{const o=(0,u.readState)(s);(0,k.spawnDetachedCodexAnalyticsWorker)({projectDir:e,sessionId:t,rolloutPath:i.transcript_path,userEmail:o?.userEmail??void 0,usageType:o?.usageType??void 0,usagePlan:o?.usagePlan??void 0,activityId:b})}catch(o){a.logger.debug(`codex analytics spawn failed: ${o instanceof Error?o.message:o}`)}if((0,l.flushInBackground)(e,t),(0,l.flushStragglersInBackground)(e,t),a.logger.debug(`verify-gate: ${d.action}`),d.action==="block"){(0,m.writeAndExit)(JSON.stringify({decision:"block",reason:d.message??"Verification required."}),0);return}(0,m.writeAndExit)(JSON.stringify({}),0)}p(R,"run");0&&(module.exports={run});
1
+ "use strict";var c=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var y=(e,i)=>c(e,"name",{value:i,configurable:!0});var E=(e,i)=>{for(var t in i)c(e,t,{get:i[t],enumerable:!0})},R=(e,i,t,s)=>{if(i&&typeof i=="object"||typeof i=="function")for(let n of C(i))!b.call(e,n)&&n!==t&&c(e,n,{get:()=>i[n],enumerable:!(s=x(i,n))||s.enumerable});return e};var F=e=>R(c({},"__esModule",{value:!0}),e);var B={};E(B,{run:()=>_});module.exports=F(B);var r=require("../../../hooks/core/actions"),S=require("../../../hooks/core/activity"),v=require("../../../hooks/core/verify-gate"),f=require("../../../lib/config"),a=require("../../../lib/logger"),u=require("../../../lib/output"),k=require("../../../lib/stdin"),m=require("../../../queue"),w=require("../../../analytics/codex/spawn"),g=require("../../../hooks/core/session-state"),A=require("../util"),l=require("../../../lib/runtime-paths");async function _(e){const i=(0,A.parseCodexHookStdin)((0,k.readStdin)()),t=i.session_id??"default";(0,a.setLogFile)((0,l.sessionLogFile)(e,t));const s=(0,l.sessionDir)(e,t),n=`${s}/actions.jsonl`,p=(0,f.loadConfig)(e),d=await(0,v.runVerifyGate)({sessionId:t,sessionDir:s,actionsFile:n,verdictFile:`${s}/verdict.json`,maxRetries:(0,f.getMaxRetries)(p),config:p,projectDir:e}),I=(0,g.readState)(s)?.activeActivityId??"";if(d.action==="allow"?await(0,S.endActivity)({sessionDir:s,actionsFile:n}):!1){const o=Date.now(),h={...(0,r.baseFields)(n),id:(0,r.deterministicSessionEndId)(t),type:"session_end",timestamp:o,session_id:t,duration:(0,r.findDurationSinceLastAction)(n,"session_start",o),reason:"checkpoint"};await(0,r.appendAction)(n,h)}try{const o=(0,g.readState)(s);(0,w.spawnDetachedCodexAnalyticsWorker)({projectDir:e,sessionId:t,rolloutPath:i.transcript_path,userEmail:o?.userEmail??void 0,usageType:o?.usageType??void 0,usagePlan:o?.usagePlan??void 0,activityId:I})}catch(o){a.logger.debug(`codex analytics spawn failed: ${o instanceof Error?o.message:o}`)}if((0,m.flushInBackground)(e,t),(0,m.flushStragglersInBackground)(e,t),a.logger.debug(`verify-gate: ${d.action}`),d.action==="block"){(0,u.writeAndExit)(JSON.stringify({decision:"block",reason:d.message??"Verification required."}),0);return}(0,u.writeAndExit)(JSON.stringify({}),0)}y(_,"run");0&&(module.exports={run});
@@ -1,3 +1,3 @@
1
- "use strict";var R=Object.defineProperty;var te=Object.getOwnPropertyDescriptor;var ie=Object.getOwnPropertyNames;var re=Object.prototype.hasOwnProperty;var S=(f,e)=>R(f,"name",{value:e,configurable:!0});var se=(f,e)=>{for(var o in e)R(f,o,{get:e[o],enumerable:!0})},ae=(f,e,o,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ie(e))!re.call(f,i)&&i!==o&&R(f,i,{get:()=>e[i],enumerable:!(r=te(e,i))||r.enumerable});return f};var le=f=>ae(R({},"__esModule",{value:!0}),f);var me={};se(me,{CodexClient:()=>ge});module.exports=le(me);var s=require("fs"),g=require("path"),K=require("../../lib/gitignore"),p=require("../../lib/logger"),l=require("../../lib/output"),B=require("../../lib/fs-prune"),d=require("../../lib/config"),C=require("../../lib/platform-section"),n=require("./util"),H=require("./thread-map"),U=require("./hooks/verify-gate"),q=require("./hooks/activity-end"),D=require("./hooks/session-start"),X=require("./hooks/activity-start"),W=require("./hooks/require-verification"),Y=require("./hooks/require-verdict"),z=require("./hooks/clear-verdict"),Q=require("./hooks/track-action"),Z=require("./hooks/track-action-monitor"),j=require("./hooks/track-action-pre"),ee=require("./hooks/subagent-start"),oe=require("./hooks/subagent-stop");const E="browser-devtools",A="node-devtools",_="backend-devtools",I="android-devtools",ce="ironbee",$="ironbee-verifier",V=30,N="Verifies recent code changes through real browser/runtime/backend tools and submits the IronBee verdict. Spawn this custom agent (by agent_type) after editing code to run the verification cycle out-of-band \u2014 it drives the devtools tools, judges the result, and records the verdict in the shared session. It does NOT edit code.",x="ironbee-scenario",L=["ironbee-manage-scenario","ironbee-search-scenario","ironbee-sync-scenario"],J="Manages and searches reusable IronBee verification scenarios via the devtools scenario tools. Spawn this custom agent (by agent_type) from the scenario slash commands to author/update/delete saved scenarios and find them by name/description/metadata. NOT a verification cycle (running a saved scenario to verify is done via $ironbee-verify scenario:<name>).";function P(f){return(0,g.join)(__dirname,"..",f,"platforms")}S(P,"platformsDirFor");function y(f){return l.pc.dim(f)}S(y,"codexColor");function F(f){return f.hooks.some(e=>e.command.includes(ce))}S(F,"isIronBeeHookGroup");function de(f){const e=Object.keys(f);return e.length===0?!0:e.length===1&&e[0]==="hooks"?Object.keys(f.hooks??{}).length===0:!1}S(de,"isCodexHooksEmpty");class ge{constructor(){this.name="codex";this.supportsVerifierModel=!0}static{S(this,"CodexClient")}detect(e){return(0,s.existsSync)((0,g.join)(e,".agents","skills","ironbee-verify"))}resolveProjectDir(){return process.env.CODEX_PROJECT_DIR??process.env.IRONBEE_PROJECT_DIR??process.cwd()}install(e,o){const r=o??(0,d.loadConfig)(e),i=(0,d.getVerificationMode)(r),t=i!=="monitor",a=(0,d.getCodexVerifierMode)(r);this.cleanupArtifacts(e);const m=(0,n.codexHooksJsonPath)(e);if(this.mergeHooksConfig(m,i,a),this.mergeConfigToml(e,r,t,a),t&&(i==="enforce"&&this.writeAgentsMdBlock(e,r,a),this.writeSkills(e,i==="enforce",r,a),(0,C.syncPlatformSectionsToConfig)(e,P)),(0,K.ensureIronBeeGitignored)(e),console.log(` ${l.pc.dim("\u2192")} ${y("[codex]")} hooks ${l.pc.dim("\u2192")} ${l.pc.dim(m)}`),console.log(` ${l.pc.dim("\u2192")} ${y("[codex]")} config ${l.pc.dim("\u2192")} ${l.pc.dim((0,n.codexConfigTomlPath)(e))}`),t){const b=a==="main-agent"?`${l.pc.yellow("main-agent")} (the main agent drives the devtools tools directly)`:`${l.pc.bold("sub-agent")} (delegated to the ironbee-verifier custom agent)`;console.log(` ${l.pc.dim("\u2192")} ${y("[codex]")} verify ${l.pc.dim("\u2192")} ${b}`)}i==="enforce"?(console.log(` ${l.pc.dim("\u2192")} ${y("[codex]")} agents ${l.pc.dim("\u2192")} ${l.pc.dim((0,g.join)(e,"AGENTS.md"))}`),console.log(` ${l.pc.dim("\u2192")} ${y("[codex]")} skill ${l.pc.dim("\u2192")} ${l.pc.dim((0,g.join)(e,".agents","skills","ironbee-verification","SKILL.md"))}`),console.log(` ${l.pc.dim("\u2192")} ${y("[codex]")} command ${l.pc.dim("\u2192")} ${l.pc.dim((0,g.join)(e,".agents","skills","ironbee-verify","SKILL.md"))}`)):i==="assist"?(console.log(` ${l.pc.dim("\u2192")} ${y("[codex]")} ${l.pc.yellow("assist mode")} (verification.auto: false) \u2014 manual $ironbee-verify only, no enforcement`),console.log(` ${l.pc.dim("\u2192")} ${y("[codex]")} command ${l.pc.dim("\u2192")} ${l.pc.dim((0,g.join)(e,".agents","skills","ironbee-verify","SKILL.md"))}`)):console.log(` ${l.pc.dim("\u2192")} ${y("[codex]")} ${l.pc.yellow("monitoring-only mode")} (verification.enable: false)`),console.log(),console.log(` ${l.pc.yellow("\u26A0")} ${l.pc.yellow("Codex requires one-time TUI setup:")}`),console.log(` ${l.pc.yellow("1.")} Run ${l.pc.bold("/hooks")} in a fresh Codex session to review and trust IronBee hooks`),console.log(` ${l.pc.yellow("2.")} Restart any open Codex sessions to pick up new hook config`)}uninstall(e){this.cleanupArtifacts(e),(0,s.existsSync)((0,n.codexHooksJsonPath)(e))||this.removeFeaturesHooksFlag(e),(0,B.pruneEmptyDirs)((0,g.join)(e,".codex"));const o=(0,H.codexThreadMapPath)(e);if((0,s.existsSync)(o))try{(0,s.unlinkSync)(o)}catch(r){p.logger.debug(`failed to remove codex thread map: ${r}`)}console.log(` ${l.pc.dim("\u2192")} ${y("[codex]")} removed hooks, MCP entries, AGENTS.md block, and skills`)}removeFeaturesHooksFlag(e){const o=(0,n.codexConfigTomlPath)(e);if((0,s.existsSync)(o))try{const r=(0,s.readFileSync)(o,"utf-8"),i=(0,n.removeFeaturesHooks)(r);i.trim().length===0?(0,s.unlinkSync)(o):i!==r&&(0,s.writeFileSync)(o,i)}catch(r){p.logger.debug(`failed to strip [features] hooks from config.toml: ${r}`)}}cleanupArtifacts(e){this.migrateAwayFromUserLevel();const o=(0,n.codexHooksJsonPath)(e);this.removeIronBeeHooks(o),this.maybeDeleteEmptyHooks(o),this.removeIronBeeMcpServers(e),this.removeVerifierAgentToml(e),this.removeScenarioAgentToml(e);const r=(0,g.join)(e,"AGENTS.md");if((0,s.existsSync)(r))try{const t=(0,s.readFileSync)(r,"utf-8"),a=(0,n.stripAgentsMdBlock)(t);a===null?(0,s.unlinkSync)(r):a!==t&&(0,s.writeFileSync)(r,a)}catch(t){p.logger.debug(`failed to strip AGENTS.md block: ${t}`)}const i=(0,g.join)(e,".agents","skills");this.removeDir((0,g.join)(i,"ironbee-verification")),this.removeDir((0,g.join)(i,"ironbee-verify"));for(const t of L)this.removeDir((0,g.join)(i,t));this.removeDir((0,g.join)(i,"ironbee-run-scenario")),(0,B.pruneEmptyDirs)((0,g.join)(e,".agents"))}async runVerifyGate(e){await(0,U.run)(e)}async runActivityEnd(e){await(0,q.run)(e)}async runSessionStart(e){await(0,D.run)(e)}async runActivityStart(e){await(0,X.run)(e)}async runRequireVerification(e,o){await(0,W.run)(e,o)}async runRequireVerdict(e,o){await(0,Y.run)(e,o)}async runClearVerdict(e){await(0,z.run)(e)}async runTrackAction(e){await(0,Q.run)(e)}async runTrackActionMonitor(e){await(0,Z.run)(e)}async runTrackActionPre(e){await(0,j.run)(e)}async runSubagentStart(e){await(0,ee.run)(e)}async runSubagentStop(e){await(0,oe.run)(e)}resolveAgentSessionId(e,o){const r=process.env.CODEX_THREAD_ID;if(typeof r=="string"&&r.length>0&&o)return(0,H.lookupThreadSession)(o,r)}async runSessionEnd(e){p.logger.debug("session-end: no-op on Codex (no SessionEnd hook event)")}mergeHooksConfig(e,o,r){const i=o!=="monitor",t=o==="assist"?" --soft":"";(0,s.mkdirSync)((0,g.dirname)(e),{recursive:!0});let a={hooks:{}};if((0,s.existsSync)(e))try{a=JSON.parse((0,s.readFileSync)(e,"utf-8")),a.hooks||(a.hooks={})}catch(v){p.logger.debug(`failed to parse ${e}: ${v}`),a={hooks:{}}}for(const v of Object.keys(a.hooks)){const c=a.hooks[v].filter(h=>!F(h));c.length===0?delete a.hooks[v]:a.hooks[v]=c}const m=S((v,c,h)=>{a.hooks[v]||(a.hooks[v]=[]),a.hooks[v].push({matcher:c,hooks:[{type:"command",command:h}]})},"addGroup");m("SessionStart",".*","ironbee hook session-start --client codex"),m("UserPromptSubmit",".*","ironbee hook activity-start --client codex"),m("PreToolUse",".*","ironbee hook track-action-pre --client codex"),i&&(m("PreToolUse","^mcp__(browser|node|backend|android)[-_]devtools__.*",`ironbee hook require-verification --client codex${t}`),m("PreToolUse","^apply_patch$",`ironbee hook require-verdict --client codex${t}`),m("PostToolUse","^apply_patch$","ironbee hook clear-verdict --client codex"),r==="sub-agent"&&m("SubagentStart",".*","ironbee hook subagent-start --client codex")),m("SubagentStop",".*","ironbee hook subagent-stop --client codex"),m("PostToolUse",".*",i?"ironbee hook track-action --client codex":"ironbee hook track-action-monitor --client codex"),m("Stop",".*",o==="enforce"?"ironbee hook verify-gate --client codex":"ironbee hook activity-end --client codex"),(0,s.writeFileSync)(e,JSON.stringify(a,null,2))}removeIronBeeHooks(e){if((0,s.existsSync)(e))try{const o=(0,s.readFileSync)(e,"utf-8"),r=JSON.parse(o);if(!r.hooks)return;let i=!1;for(const t of Object.keys(r.hooks)){const a=r.hooks[t].filter(m=>!F(m));a.length!==r.hooks[t].length&&(i=!0),a.length===0?delete r.hooks[t]:r.hooks[t]=a}i&&(0,s.writeFileSync)(e,JSON.stringify(r,null,2))}catch(o){p.logger.debug(`failed to strip IronBee hooks from ${e}: ${o}`)}}maybeDeleteEmptyHooks(e){if((0,s.existsSync)(e))try{const o=JSON.parse((0,s.readFileSync)(e,"utf-8"));de(o)&&(0,s.unlinkSync)(e)}catch(o){p.logger.debug(`failed to inspect ${e} for emptiness: ${o}`)}}mergeConfigToml(e,o,r,i){(0,s.mkdirSync)((0,g.join)(e,".codex"),{recursive:!0});let t=(0,n.readCodexConfigToml)(e);if(t=(0,n.ensureFeaturesHooksTrue)(t),t=(0,n.removeMcpServer)(t,E),t=(0,n.removeMcpServer)(t,A),t=(0,n.removeMcpServer)(t,_),t=(0,n.removeMcpServer)(t,I),r&&i==="main-agent"){t=this.upsertSessionMcpServers(t,e,o),t=(0,n.removeAgentsTable)(t,$),t=(0,n.removeAgentsTable)(t,x),t=(0,n.removeMultiAgentV2SpawnMetadata)(t),this.removeVerifierAgentToml(e),this.removeScenarioAgentToml(e),(0,n.writeCodexConfigToml)(e,t);return}if(r){const a=(0,d.getVerificationModel)(o,"codex"),m=(0,s.existsSync)((0,n.userCodexConfigTomlPath)())?(0,s.readFileSync)((0,n.userCodexConfigTomlPath)(),"utf-8"):"",b=(0,n.extractTomlTopLevelModel)(t)===null&&(0,n.extractTomlTopLevelModel)(m)===null;a===void 0&&b&&console.log(` ${l.pc.dim("\u2192")} ${y("[codex]")} ${l.pc.yellow("\u26A0 no model for the verifier")} \u2014 the ${l.pc.bold("ironbee-verifier")} sub-agent inherits the session model, but neither this project's .codex/config.toml nor ~/.codex/config.toml has a top-level ${l.pc.bold("model")}, so it may fail to spawn ("could not resolve the child model"). Fix: set ${l.pc.bold("model")} in ~/.codex/config.toml, or set ${l.pc.bold("verification.model")} in your ironbee config.`),this.writeVerifierAgentToml(e,o,a),t=(0,n.upsertAgentsTable)(t,$,[`description = ${JSON.stringify(N)}`,`config_file = ${JSON.stringify(`agents/${$}.toml`)}`]),t=(0,n.ensureMultiAgentV2SpawnMetadataExposed)(t),this.writeScenarioAgentToml(e,o,a),t=(0,n.upsertAgentsTable)(t,x,[`description = ${JSON.stringify(J)}`,`config_file = ${JSON.stringify(`agents/${x}.toml`)}`])}else t=(0,n.removeAgentsTable)(t,$),t=(0,n.removeAgentsTable)(t,x),t=(0,n.removeMultiAgentV2SpawnMetadata)(t),this.removeVerifierAgentToml(e),this.removeScenarioAgentToml(e);(0,n.writeCodexConfigToml)(e,t)}writeVerifierAgentToml(e,o,r){this.writeCustomAgentToml(e,o,r,$,N,"skill","read-only")}writeScenarioAgentToml(e,o,r){this.writeCustomAgentToml(e,o,r,x,J,"scenario","read-only")}writeCustomAgentToml(e,o,r,i,t,a,m){const b=(0,g.join)(__dirname,"agents",`${i}.md`);let u;try{u=(0,s.readFileSync)(b,"utf-8")}catch(k){p.logger.debug(`failed to read agent source ${b}: ${k}`);return}const v=P("codex");for(const k of d.ALL_CYCLES){const w=(0,d.isCycleEnabled)(o,k)?ne=>{const O=(0,g.join)(v,(0,C.fragmentFilename)(a,k,ne));return(0,s.existsSync)(O)?(0,s.readFileSync)(O,"utf-8").trimEnd():null}:null;u=(0,C.applyPlatformSection)(u,k,w,`${i}.toml`)}const c=[];c.push(`name = ${JSON.stringify(i)}`),c.push(`description = ${JSON.stringify(t)}`),c.push(`sandbox_mode = ${JSON.stringify(m)}`),r&&c.push(`model = ${JSON.stringify(r)}`),c.push("developer_instructions = '''"),c.push(u.replace(/'''/g,"```").trimEnd()),c.push("'''");const h=S((k,T,w)=>{k&&(c.push(""),c.push(`[mcp_servers.${T}]`),c.push(...G(w)),c.push(`startup_timeout_sec = ${V}`),c.push("required = true"),c.push('default_tools_approval_mode = "approve"'))},"addCycle");h((0,d.isCycleEnabled)(o,"browser"),E,(0,d.getMcpServerEntry)(e)),h((0,d.isCycleEnabled)(o,"node"),A,(0,d.getNodeDevToolsMcpEntry)(e)),h((0,d.isCycleEnabled)(o,"backend"),_,(0,d.getBackendDevToolsMcpEntry)(e)),h((0,d.isCycleEnabled)(o,"android"),I,(0,d.getAndroidDevToolsMcpEntry)(e));const M=(0,n.codexAgentTomlPath)(e,i);(0,s.mkdirSync)((0,g.dirname)(M),{recursive:!0}),(0,s.writeFileSync)(M,c.join(`
1
+ "use strict";var P=Object.defineProperty;var se=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames;var le=Object.prototype.hasOwnProperty;var S=(f,e)=>P(f,"name",{value:e,configurable:!0});var ce=(f,e)=>{for(var o in e)P(f,o,{get:e[o],enumerable:!0})},de=(f,e,o,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ae(e))!le.call(f,i)&&i!==o&&P(f,i,{get:()=>e[i],enumerable:!(r=se(e,i))||r.enumerable});return f};var ge=f=>de(P({},"__esModule",{value:!0}),f);var ve={};ce(ve,{CodexClient:()=>fe});module.exports=ge(ve);var s=require("fs"),m=require("path"),q=require("../../lib/gitignore"),b=require("../../lib/logger"),c=require("../../lib/output"),N=require("../../lib/fs-prune"),l=require("../../lib/config"),C=require("../../lib/platform-section"),n=require("./util"),B=require("./thread-map"),W=require("../../lib/runtime-paths"),X=require("./hooks/verify-gate"),D=require("./hooks/activity-end"),Y=require("./hooks/session-start"),z=require("./hooks/activity-start"),Q=require("./hooks/require-verification"),Z=require("./hooks/require-verdict"),j=require("./hooks/clear-verdict"),ee=require("./hooks/track-action"),oe=require("./hooks/track-action-monitor"),ne=require("./hooks/track-action-pre"),te=require("./hooks/subagent-start"),ie=require("./hooks/subagent-stop");const O="~/.ironbee/projects",w="browser-devtools",A="node-devtools",_="backend-devtools",I="android-devtools",R="terminal-devtools",me="ironbee",$="ironbee-verifier",L=30,J="Verifies recent code changes through real browser/runtime/backend tools and submits the IronBee verdict. Spawn this custom agent (by agent_type) after editing code to run the verification cycle out-of-band \u2014 it drives the devtools tools, judges the result, and records the verdict in the shared session. It does NOT edit code.",x="ironbee-scenario",F=["ironbee-manage-scenario","ironbee-search-scenario","ironbee-sync-scenario"],G="Manages and searches reusable IronBee verification scenarios via the devtools scenario tools. Spawn this custom agent (by agent_type) from the scenario slash commands to author/update/delete saved scenarios and find them by name/description/metadata. NOT a verification cycle (running a saved scenario to verify is done via $ironbee-verify scenario:<name>).";function H(f){return(0,m.join)(__dirname,"..",f,"platforms")}S(H,"platformsDirFor");function y(f){return c.pc.dim(f)}S(y,"codexColor");function K(f){return f.hooks.some(e=>e.command.includes(me))}S(K,"isIronBeeHookGroup");function ue(f){const e=Object.keys(f);return e.length===0?!0:e.length===1&&e[0]==="hooks"?Object.keys(f.hooks??{}).length===0:!1}S(ue,"isCodexHooksEmpty");class fe{constructor(){this.name="codex";this.supportsVerifierModel=!0}static{S(this,"CodexClient")}detect(e){return(0,s.existsSync)((0,m.join)(e,".agents","skills","ironbee-verify"))}resolveProjectDir(){return process.env.CODEX_PROJECT_DIR??process.env.IRONBEE_PROJECT_DIR??process.cwd()}install(e,o){const r=o??(0,l.loadConfig)(e),i=(0,l.getVerificationMode)(r),t=i!=="monitor",a=(0,l.getCodexVerifierMode)(r);this.cleanupArtifacts(e);const g=(0,n.codexHooksJsonPath)(e);if(this.mergeHooksConfig(g,i,a),this.mergeConfigToml(e,r,t,a),t&&(i==="enforce"&&this.writeAgentsMdBlock(e,r,a),this.writeSkills(e,i==="enforce",r,a),(0,C.syncPlatformSectionsToConfig)(e,H)),(0,q.ensureIronBeeGitignored)(e),console.log(` ${c.pc.dim("\u2192")} ${y("[codex]")} hooks ${c.pc.dim("\u2192")} ${c.pc.dim(g)}`),console.log(` ${c.pc.dim("\u2192")} ${y("[codex]")} config ${c.pc.dim("\u2192")} ${c.pc.dim((0,n.codexConfigTomlPath)(e))}`),t){const h=a==="main-agent"?`${c.pc.yellow("main-agent")} (the main agent drives the devtools tools directly)`:`${c.pc.bold("sub-agent")} (delegated to the ironbee-verifier custom agent)`;console.log(` ${c.pc.dim("\u2192")} ${y("[codex]")} verify ${c.pc.dim("\u2192")} ${h}`)}i==="enforce"?(console.log(` ${c.pc.dim("\u2192")} ${y("[codex]")} agents ${c.pc.dim("\u2192")} ${c.pc.dim((0,m.join)(e,"AGENTS.md"))}`),console.log(` ${c.pc.dim("\u2192")} ${y("[codex]")} skill ${c.pc.dim("\u2192")} ${c.pc.dim((0,m.join)(e,".agents","skills","ironbee-verification","SKILL.md"))}`),console.log(` ${c.pc.dim("\u2192")} ${y("[codex]")} command ${c.pc.dim("\u2192")} ${c.pc.dim((0,m.join)(e,".agents","skills","ironbee-verify","SKILL.md"))}`)):i==="assist"?(console.log(` ${c.pc.dim("\u2192")} ${y("[codex]")} ${c.pc.yellow("assist mode")} (verification.auto: false) \u2014 manual $ironbee-verify only, no enforcement`),console.log(` ${c.pc.dim("\u2192")} ${y("[codex]")} command ${c.pc.dim("\u2192")} ${c.pc.dim((0,m.join)(e,".agents","skills","ironbee-verify","SKILL.md"))}`)):console.log(` ${c.pc.dim("\u2192")} ${y("[codex]")} ${c.pc.yellow("monitoring-only mode")} (verification.enable: false)`),console.log(),console.log(` ${c.pc.yellow("\u26A0")} ${c.pc.yellow("Codex requires one-time TUI setup:")}`),console.log(` ${c.pc.yellow("1.")} Run ${c.pc.bold("/hooks")} in a fresh Codex session to review and trust IronBee hooks`),console.log(` ${c.pc.yellow("2.")} Restart any open Codex sessions to pick up new hook config`)}uninstall(e){this.cleanupArtifacts(e),(0,s.existsSync)((0,n.codexHooksJsonPath)(e))||this.removeFeaturesHooksFlag(e),(0,N.pruneEmptyDirs)((0,m.join)(e,".codex"));const o=(0,B.codexThreadMapPath)(e);if((0,s.existsSync)(o))try{(0,s.unlinkSync)(o)}catch(r){b.logger.debug(`failed to remove codex thread map: ${r}`)}console.log(` ${c.pc.dim("\u2192")} ${y("[codex]")} removed hooks, MCP entries, AGENTS.md block, and skills`)}removeFeaturesHooksFlag(e){const o=(0,n.codexConfigTomlPath)(e);if((0,s.existsSync)(o))try{const r=(0,s.readFileSync)(o,"utf-8");let i=(0,n.removeFeaturesHooks)(r);i=(0,n.removeSandboxWritableRoot)(i,O),i.trim().length===0?(0,s.unlinkSync)(o):i!==r&&(0,s.writeFileSync)(o,i)}catch(r){b.logger.debug(`failed to strip [features] hooks from config.toml: ${r}`)}}cleanupArtifacts(e){this.migrateAwayFromUserLevel();const o=(0,n.codexHooksJsonPath)(e);this.removeIronBeeHooks(o),this.maybeDeleteEmptyHooks(o),this.removeIronBeeMcpServers(e),this.removeVerifierAgentToml(e),this.removeScenarioAgentToml(e);const r=(0,m.join)(e,"AGENTS.md");if((0,s.existsSync)(r))try{const t=(0,s.readFileSync)(r,"utf-8"),a=(0,n.stripAgentsMdBlock)(t);a===null?(0,s.unlinkSync)(r):a!==t&&(0,s.writeFileSync)(r,a)}catch(t){b.logger.debug(`failed to strip AGENTS.md block: ${t}`)}const i=(0,m.join)(e,".agents","skills");this.removeDir((0,m.join)(i,"ironbee-verification")),this.removeDir((0,m.join)(i,"ironbee-verify"));for(const t of F)this.removeDir((0,m.join)(i,t));this.removeDir((0,m.join)(i,"ironbee-run-scenario")),(0,N.pruneEmptyDirs)((0,m.join)(e,".agents"))}async runVerifyGate(e){await(0,X.run)(e)}async runActivityEnd(e){await(0,D.run)(e)}async runSessionStart(e){await(0,Y.run)(e)}async runActivityStart(e){await(0,z.run)(e)}async runRequireVerification(e,o){await(0,Q.run)(e,o)}async runRequireVerdict(e,o){await(0,Z.run)(e,o)}async runClearVerdict(e){await(0,j.run)(e)}async runTrackAction(e){await(0,ee.run)(e)}async runTrackActionMonitor(e){await(0,oe.run)(e)}async runTrackActionPre(e){await(0,ne.run)(e)}async runSubagentStart(e){await(0,te.run)(e)}async runSubagentStop(e){await(0,ie.run)(e)}resolveAgentSessionId(e,o){const r=process.env.CODEX_THREAD_ID;if(typeof r=="string"&&r.length>0&&o)return(0,B.lookupThreadSession)(o,r)}async runSessionEnd(e){b.logger.debug("session-end: no-op on Codex (no SessionEnd hook event)")}mergeHooksConfig(e,o,r){const i=o!=="monitor",t=o==="assist"?" --soft":"";(0,s.mkdirSync)((0,m.dirname)(e),{recursive:!0});let a={hooks:{}};if((0,s.existsSync)(e))try{a=JSON.parse((0,s.readFileSync)(e,"utf-8")),a.hooks||(a.hooks={})}catch(v){b.logger.debug(`failed to parse ${e}: ${v}`),a={hooks:{}}}for(const v of Object.keys(a.hooks)){const d=a.hooks[v].filter(p=>!K(p));d.length===0?delete a.hooks[v]:a.hooks[v]=d}const g=S((v,d,p)=>{a.hooks[v]||(a.hooks[v]=[]),a.hooks[v].push({matcher:d,hooks:[{type:"command",command:p}]})},"addGroup");g("SessionStart",".*","ironbee hook session-start --client codex"),g("UserPromptSubmit",".*","ironbee hook activity-start --client codex"),g("PreToolUse",".*","ironbee hook track-action-pre --client codex"),i&&(g("PreToolUse","^mcp__(browser|node|backend|android|terminal)[-_]devtools__.*",`ironbee hook require-verification --client codex${t}`),g("PreToolUse","^apply_patch$",`ironbee hook require-verdict --client codex${t}`),g("PostToolUse","^apply_patch$","ironbee hook clear-verdict --client codex"),r==="sub-agent"&&g("SubagentStart",".*","ironbee hook subagent-start --client codex")),g("SubagentStop",".*","ironbee hook subagent-stop --client codex"),g("PostToolUse",".*",i?"ironbee hook track-action --client codex":"ironbee hook track-action-monitor --client codex"),g("Stop",".*",o==="enforce"?"ironbee hook verify-gate --client codex":"ironbee hook activity-end --client codex"),(0,s.writeFileSync)(e,JSON.stringify(a,null,2))}removeIronBeeHooks(e){if((0,s.existsSync)(e))try{const o=(0,s.readFileSync)(e,"utf-8"),r=JSON.parse(o);if(!r.hooks)return;let i=!1;for(const t of Object.keys(r.hooks)){const a=r.hooks[t].filter(g=>!K(g));a.length!==r.hooks[t].length&&(i=!0),a.length===0?delete r.hooks[t]:r.hooks[t]=a}i&&(0,s.writeFileSync)(e,JSON.stringify(r,null,2))}catch(o){b.logger.debug(`failed to strip IronBee hooks from ${e}: ${o}`)}}maybeDeleteEmptyHooks(e){if((0,s.existsSync)(e))try{const o=JSON.parse((0,s.readFileSync)(e,"utf-8"));ue(o)&&(0,s.unlinkSync)(e)}catch(o){b.logger.debug(`failed to inspect ${e} for emptiness: ${o}`)}}mergeConfigToml(e,o,r,i){(0,s.mkdirSync)((0,m.join)(e,".codex"),{recursive:!0});let t=(0,n.readCodexConfigToml)(e);if(t=(0,n.ensureFeaturesHooksTrue)(t),t=r&&(0,W.resolveRuntimeLocation)(e)==="external"?(0,n.ensureSandboxWritableRoot)(t,O):(0,n.removeSandboxWritableRoot)(t,O),t=(0,n.removeMcpServer)(t,w),t=(0,n.removeMcpServer)(t,A),t=(0,n.removeMcpServer)(t,_),t=(0,n.removeMcpServer)(t,I),t=(0,n.removeMcpServer)(t,R),r&&i==="main-agent"){t=this.upsertSessionMcpServers(t,e,o),t=(0,n.removeAgentsTable)(t,$),t=(0,n.removeAgentsTable)(t,x),t=(0,n.removeMultiAgentV2SpawnMetadata)(t),this.removeVerifierAgentToml(e),this.removeScenarioAgentToml(e),(0,n.writeCodexConfigToml)(e,t);return}if(r){const g=(0,l.getVerificationModel)(o,"codex"),h=(0,s.existsSync)((0,n.userCodexConfigTomlPath)())?(0,s.readFileSync)((0,n.userCodexConfigTomlPath)(),"utf-8"):"",u=(0,n.extractTomlTopLevelModel)(t)===null&&(0,n.extractTomlTopLevelModel)(h)===null;g===void 0&&u&&console.log(` ${c.pc.dim("\u2192")} ${y("[codex]")} ${c.pc.yellow("\u26A0 no model for the verifier")} \u2014 the ${c.pc.bold("ironbee-verifier")} sub-agent inherits the session model, but neither this project's .codex/config.toml nor ~/.codex/config.toml has a top-level ${c.pc.bold("model")}, so it may fail to spawn ("could not resolve the child model"). Fix: set ${c.pc.bold("model")} in ~/.codex/config.toml, or set ${c.pc.bold("verification.model")} in your ironbee config.`),this.writeVerifierAgentToml(e,o,g),t=(0,n.upsertAgentsTable)(t,$,[`description = ${JSON.stringify(J)}`,`config_file = ${JSON.stringify(`agents/${$}.toml`)}`]),t=(0,n.ensureMultiAgentV2SpawnMetadataExposed)(t),this.writeScenarioAgentToml(e,o,g),t=(0,n.upsertAgentsTable)(t,x,[`description = ${JSON.stringify(G)}`,`config_file = ${JSON.stringify(`agents/${x}.toml`)}`])}else t=(0,n.removeAgentsTable)(t,$),t=(0,n.removeAgentsTable)(t,x),t=(0,n.removeMultiAgentV2SpawnMetadata)(t),this.removeVerifierAgentToml(e),this.removeScenarioAgentToml(e);(0,n.writeCodexConfigToml)(e,t)}writeVerifierAgentToml(e,o,r){this.writeCustomAgentToml(e,o,r,$,J,"skill","read-only")}writeScenarioAgentToml(e,o,r){this.writeCustomAgentToml(e,o,r,x,G,"scenario","read-only")}writeCustomAgentToml(e,o,r,i,t,a,g){const h=(0,m.join)(__dirname,"agents",`${i}.md`);let u;try{u=(0,s.readFileSync)(h,"utf-8")}catch(k){b.logger.debug(`failed to read agent source ${h}: ${k}`);return}const v=H("codex");for(const k of l.ALL_CYCLES){const E=(0,l.isCycleEnabled)(o,k)?re=>{const V=(0,m.join)(v,(0,C.fragmentFilename)(a,k,re));return(0,s.existsSync)(V)?(0,s.readFileSync)(V,"utf-8").trimEnd():null}:null;u=(0,C.applyPlatformSection)(u,k,E,`${i}.toml`)}const d=[];d.push(`name = ${JSON.stringify(i)}`),d.push(`description = ${JSON.stringify(t)}`),d.push(`sandbox_mode = ${JSON.stringify(g)}`),r&&d.push(`model = ${JSON.stringify(r)}`),d.push("developer_instructions = '''"),d.push(u.replace(/'''/g,"```").trimEnd()),d.push("'''");const p=S((k,T,E)=>{k&&(d.push(""),d.push(`[mcp_servers.${T}]`),d.push(...U(E)),d.push(`startup_timeout_sec = ${L}`),d.push("required = true"),d.push('default_tools_approval_mode = "approve"'))},"addCycle");p((0,l.isCycleEnabled)(o,"browser"),w,(0,l.getMcpServerEntry)(e)),p((0,l.isCycleEnabled)(o,"node"),A,(0,l.getNodeDevToolsMcpEntry)(e)),p((0,l.isCycleEnabled)(o,"backend"),_,(0,l.getBackendDevToolsMcpEntry)(e)),p((0,l.isCycleEnabled)(o,"android"),I,(0,l.getAndroidDevToolsMcpEntry)(e)),p((0,l.isCycleEnabled)(o,"terminal"),R,(0,l.getTerminalDevToolsMcpEntry)(e));const M=(0,n.codexAgentTomlPath)(e,i);(0,s.mkdirSync)((0,m.dirname)(M),{recursive:!0}),(0,s.writeFileSync)(M,d.join(`
2
2
  `)+`
3
- `)}upsertSessionMcpServers(e,o,r){let i=e;const t=S((a,m,b)=>{if(!a)return;const u=[...G(b),`startup_timeout_sec = ${V}`,'default_tools_approval_mode = "approve"'];i=(0,n.upsertMcpServer)(i,m,u)},"addCycle");return t((0,d.isCycleEnabled)(r,"browser"),E,(0,d.getMcpServerEntry)(o)),t((0,d.isCycleEnabled)(r,"node"),A,(0,d.getNodeDevToolsMcpEntry)(o)),t((0,d.isCycleEnabled)(r,"backend"),_,(0,d.getBackendDevToolsMcpEntry)(o)),t((0,d.isCycleEnabled)(r,"android"),I,(0,d.getAndroidDevToolsMcpEntry)(o)),i}removeVerifierAgentToml(e){const o=(0,n.codexAgentTomlPath)(e,$);if((0,s.existsSync)(o))try{(0,s.unlinkSync)(o)}catch(r){p.logger.debug(`failed to remove verifier agent toml: ${r}`)}}removeScenarioAgentToml(e){const o=(0,n.codexAgentTomlPath)(e,x);if((0,s.existsSync)(o))try{(0,s.unlinkSync)(o)}catch(r){p.logger.debug(`failed to remove scenario agent toml: ${r}`)}}removeIronBeeMcpServers(e){let o=(0,n.readCodexConfigToml)(e);o&&(o=(0,n.removeMcpServer)(o,E),o=(0,n.removeMcpServer)(o,A),o=(0,n.removeMcpServer)(o,_),o=(0,n.removeMcpServer)(o,I),o=(0,n.removeAgentsTable)(o,$),o=(0,n.removeAgentsTable)(o,x),o=(0,n.removeMultiAgentV2SpawnMetadata)(o),(0,n.writeCodexConfigToml)(e,o))}migrateAwayFromUserLevel(){const e=(0,n.userCodexHooksJsonPath)();this.removeIronBeeHooks(e),this.maybeDeleteEmptyHooks(e);const o=(0,n.userCodexConfigTomlPath)();if((0,s.existsSync)(o))try{let i=(0,s.readFileSync)(o,"utf-8");const t=i;i=(0,n.removeMcpServer)(i,E),i=(0,n.removeMcpServer)(i,A),i=(0,n.removeMcpServer)(i,_),i=(0,n.removeMcpServer)(i,I),i=(0,n.removeAgentsTable)(i,$),i=(0,n.removeMultiAgentV2SpawnMetadata)(i),i!==t&&(0,s.writeFileSync)(o,i)}catch(i){p.logger.debug(`migrate: failed to clean user-level config.toml: ${i}`)}const r=(0,n.userCodexAgentTomlPath)($);if((0,s.existsSync)(r))try{(0,s.unlinkSync)(r)}catch(i){p.logger.debug(`migrate: failed to remove user-level verifier toml: ${i}`)}}writeAgentsMdBlock(e,o,r){const i=(0,g.join)(e,"AGENTS.md"),t=r==="main-agent"?"ironbee-verification.main.md":"ironbee-verification.md",a=(0,g.join)(__dirname,"rules",t);let m;try{m=(0,s.readFileSync)(a,"utf-8")}catch(c){p.logger.debug(`failed to read rule source ${a}: ${c}`);return}const b=P("codex");for(const c of d.ALL_CYCLES){const M=(0,d.isCycleEnabled)(o,c)?k=>{const T=(0,g.join)(b,(0,C.fragmentFilename)("rule",c,k));if(!(0,s.existsSync)(T)){const w=k.length>0?`${c}:${k}`:c;return p.logger.debug(`AGENTS.md platform-section ${w}: missing fragment ${T}, using placeholder`),null}return(0,s.readFileSync)(T,"utf-8").trimEnd()}:null;m=(0,C.applyPlatformSection)(m,c,M,"AGENTS.md")}const u=(0,s.existsSync)(i)?(0,s.readFileSync)(i,"utf-8"):"",v=(0,n.upsertAgentsMdBlock)(u,m);(0,s.writeFileSync)(i,v)}writeSkills(e,o,r,i){const t=(0,g.join)(e,".agents","skills"),a=i==="main-agent";if(o){const u=(0,g.join)(t,"ironbee-verification");(0,s.mkdirSync)(u,{recursive:!0});const v=(0,g.join)(__dirname,"skills",a?"ironbee-verification.main.md":"ironbee-verification.md");try{let c=(0,s.readFileSync)(v,"utf-8");a&&(c=this.spliceCycleFragments(c,"skill",r,"ironbee-verification/SKILL.md")),(0,s.writeFileSync)((0,g.join)(u,"SKILL.md"),c)}catch(c){p.logger.debug(`failed to copy skill ${v}: ${c}`)}}const m=(0,g.join)(t,"ironbee-verify");(0,s.mkdirSync)(m,{recursive:!0});const b=(0,g.join)(__dirname,"commands","ironbee-verify",a?"SKILL.main.md":"SKILL.md");try{let u=(0,s.readFileSync)(b,"utf-8");a&&(u=this.spliceCycleFragments(u,"command-verify",r,"ironbee-verify/SKILL.md")),(0,s.writeFileSync)((0,g.join)(m,"SKILL.md"),u)}catch(u){p.logger.debug(`failed to copy verify command ${b}: ${u}`)}for(const u of L){const v=(0,g.join)(t,u);(0,s.mkdirSync)(v,{recursive:!0});const c=(0,g.join)(__dirname,"commands",u,a?"SKILL.main.md":"SKILL.md");try{let h=(0,s.readFileSync)(c,"utf-8");a&&(h=this.spliceCycleFragments(h,"scenario",r,`${u}/SKILL.md`)),(0,s.writeFileSync)((0,g.join)(v,"SKILL.md"),h)}catch(h){p.logger.debug(`failed to copy scenario command ${c}: ${h}`)}}}spliceCycleFragments(e,o,r,i){const t=P("codex");let a=e;for(const m of d.ALL_CYCLES){const u=(0,d.isCycleEnabled)(r,m)?v=>{const c=(0,g.join)(t,(0,C.fragmentFilename)(o,m,v));return(0,s.existsSync)(c)?(0,s.readFileSync)(c,"utf-8").trimEnd():null}:null;a=(0,C.applyPlatformSection)(a,m,u,i)}return a}removeDir(e){if((0,s.existsSync)(e))try{(0,s.rmSync)(e,{recursive:!0,force:!0})}catch(o){p.logger.debug(`failed to remove ${e}: ${o}`)}}}function G(f){return(0,n.tomlBodyFromRecord)(f)}S(G,"mcpEntryToTomlBody");0&&(module.exports={CodexClient});
3
+ `)}upsertSessionMcpServers(e,o,r){let i=e;const t=S((a,g,h)=>{if(!a)return;const u=[...U(h),`startup_timeout_sec = ${L}`,'default_tools_approval_mode = "approve"'];i=(0,n.upsertMcpServer)(i,g,u)},"addCycle");return t((0,l.isCycleEnabled)(r,"browser"),w,(0,l.getMcpServerEntry)(o)),t((0,l.isCycleEnabled)(r,"node"),A,(0,l.getNodeDevToolsMcpEntry)(o)),t((0,l.isCycleEnabled)(r,"backend"),_,(0,l.getBackendDevToolsMcpEntry)(o)),t((0,l.isCycleEnabled)(r,"android"),I,(0,l.getAndroidDevToolsMcpEntry)(o)),t((0,l.isCycleEnabled)(r,"terminal"),R,(0,l.getTerminalDevToolsMcpEntry)(o)),i}removeVerifierAgentToml(e){const o=(0,n.codexAgentTomlPath)(e,$);if((0,s.existsSync)(o))try{(0,s.unlinkSync)(o)}catch(r){b.logger.debug(`failed to remove verifier agent toml: ${r}`)}}removeScenarioAgentToml(e){const o=(0,n.codexAgentTomlPath)(e,x);if((0,s.existsSync)(o))try{(0,s.unlinkSync)(o)}catch(r){b.logger.debug(`failed to remove scenario agent toml: ${r}`)}}removeIronBeeMcpServers(e){let o=(0,n.readCodexConfigToml)(e);o&&(o=(0,n.removeMcpServer)(o,w),o=(0,n.removeMcpServer)(o,A),o=(0,n.removeMcpServer)(o,_),o=(0,n.removeMcpServer)(o,I),o=(0,n.removeMcpServer)(o,R),o=(0,n.removeAgentsTable)(o,$),o=(0,n.removeAgentsTable)(o,x),o=(0,n.removeMultiAgentV2SpawnMetadata)(o),(0,n.writeCodexConfigToml)(e,o))}migrateAwayFromUserLevel(){const e=(0,n.userCodexHooksJsonPath)();this.removeIronBeeHooks(e),this.maybeDeleteEmptyHooks(e);const o=(0,n.userCodexConfigTomlPath)();if((0,s.existsSync)(o))try{let i=(0,s.readFileSync)(o,"utf-8");const t=i;i=(0,n.removeMcpServer)(i,w),i=(0,n.removeMcpServer)(i,A),i=(0,n.removeMcpServer)(i,_),i=(0,n.removeMcpServer)(i,I),i=(0,n.removeMcpServer)(i,R),i=(0,n.removeAgentsTable)(i,$),i=(0,n.removeMultiAgentV2SpawnMetadata)(i),i!==t&&(0,s.writeFileSync)(o,i)}catch(i){b.logger.debug(`migrate: failed to clean user-level config.toml: ${i}`)}const r=(0,n.userCodexAgentTomlPath)($);if((0,s.existsSync)(r))try{(0,s.unlinkSync)(r)}catch(i){b.logger.debug(`migrate: failed to remove user-level verifier toml: ${i}`)}}writeAgentsMdBlock(e,o,r){const i=(0,m.join)(e,"AGENTS.md"),t=r==="main-agent"?"ironbee-verification.main.md":"ironbee-verification.md",a=(0,m.join)(__dirname,"rules",t);let g;try{g=(0,s.readFileSync)(a,"utf-8")}catch(d){b.logger.debug(`failed to read rule source ${a}: ${d}`);return}const h=H("codex");for(const d of l.ALL_CYCLES){const M=(0,l.isCycleEnabled)(o,d)?k=>{const T=(0,m.join)(h,(0,C.fragmentFilename)("rule",d,k));if(!(0,s.existsSync)(T)){const E=k.length>0?`${d}:${k}`:d;return b.logger.debug(`AGENTS.md platform-section ${E}: missing fragment ${T}, using placeholder`),null}return(0,s.readFileSync)(T,"utf-8").trimEnd()}:null;g=(0,C.applyPlatformSection)(g,d,M,"AGENTS.md")}const u=(0,s.existsSync)(i)?(0,s.readFileSync)(i,"utf-8"):"",v=(0,n.upsertAgentsMdBlock)(u,g);(0,s.writeFileSync)(i,v)}writeSkills(e,o,r,i){const t=(0,m.join)(e,".agents","skills"),a=i==="main-agent";if(o){const u=(0,m.join)(t,"ironbee-verification");(0,s.mkdirSync)(u,{recursive:!0});const v=(0,m.join)(__dirname,"skills",a?"ironbee-verification.main.md":"ironbee-verification.md");try{let d=(0,s.readFileSync)(v,"utf-8");a&&(d=this.spliceCycleFragments(d,"skill",r,"ironbee-verification/SKILL.md")),(0,s.writeFileSync)((0,m.join)(u,"SKILL.md"),d)}catch(d){b.logger.debug(`failed to copy skill ${v}: ${d}`)}}const g=(0,m.join)(t,"ironbee-verify");(0,s.mkdirSync)(g,{recursive:!0});const h=(0,m.join)(__dirname,"commands","ironbee-verify",a?"SKILL.main.md":"SKILL.md");try{let u=(0,s.readFileSync)(h,"utf-8");a&&(u=this.spliceCycleFragments(u,"command-verify",r,"ironbee-verify/SKILL.md")),(0,s.writeFileSync)((0,m.join)(g,"SKILL.md"),u)}catch(u){b.logger.debug(`failed to copy verify command ${h}: ${u}`)}for(const u of F){const v=(0,m.join)(t,u);(0,s.mkdirSync)(v,{recursive:!0});const d=(0,m.join)(__dirname,"commands",u,a?"SKILL.main.md":"SKILL.md");try{let p=(0,s.readFileSync)(d,"utf-8");a&&(p=this.spliceCycleFragments(p,"scenario",r,`${u}/SKILL.md`)),(0,s.writeFileSync)((0,m.join)(v,"SKILL.md"),p)}catch(p){b.logger.debug(`failed to copy scenario command ${d}: ${p}`)}}}spliceCycleFragments(e,o,r,i){const t=H("codex");let a=e;for(const g of l.ALL_CYCLES){const u=(0,l.isCycleEnabled)(r,g)?v=>{const d=(0,m.join)(t,(0,C.fragmentFilename)(o,g,v));return(0,s.existsSync)(d)?(0,s.readFileSync)(d,"utf-8").trimEnd():null}:null;a=(0,C.applyPlatformSection)(a,g,u,i)}return a}removeDir(e){if((0,s.existsSync)(e))try{(0,s.rmSync)(e,{recursive:!0,force:!0})}catch(o){b.logger.debug(`failed to remove ${e}: ${o}`)}}}function U(f){return(0,n.tomlBodyFromRecord)(f)}S(U,"mcpEntryToTomlBody");0&&(module.exports={CodexClient});
@@ -18,6 +18,7 @@ If the project has android verification enabled (`ironbee android enable` once a
18
18
  4. **Pick an evidence path** for the changed code:
19
19
  - **Device-evidence** (proves the change is visible / functional): drive UI (`mcp__android-devtools__adt_interaction_tap` / `mcp__android-devtools__adt_interaction_input-text` / `mcp__android-devtools__adt_interaction_swipe`) → screenshot (`mcp__android-devtools__adt_content_take-screenshot`) → UI snapshot (`mcp__android-devtools__adt_a11y_take-ui-snapshot`). **STOP and visually analyze the screenshot** — readability, layout, cut-off content, expected state rendered; the snapshot reports structure, the screenshot shows what the user actually sees. Both are MANDATORY on this path.
20
20
  - **Log-evidence** (proves the changed code path executed): `mcp__android-devtools__adt_o11y_log-read` or `mcp__android-devtools__adt_o11y_log-follow`. Confirm expected log lines present AND no FATAL/crash from the app package.
21
+ - **Network-evidence** (proves a network/API change behaved correctly): `mcp__android-devtools__adt_o11y_get-http-requests` — forward-looking, so start capture, drive the app to trigger traffic, then read again; confirm the expected request(s)/status. Auxiliary (NOT gate evidence): `mcp__android-devtools__adt_o11y_new-trace-id` pins a correlation root; `mcp__android-devtools__adt_stub_*` mocks/intercepts responses for setup.
21
22
  5. **If recording was started, stop it now** — `mcp__android-devtools__adt_content_stop-recording`. submit-verdict rejects with `"recording is still active"` when this step is skipped.
22
23
  6. **Submit verdict** — platform-agnostic, just status + checks (+ issues/fixes).
23
24
 
@@ -0,0 +1,61 @@
1
+ <!-- Terminal verification is ENABLED for this project. -->
2
+
3
+ ## Terminal Mode (when `terminal.verifyPatterns` matches an edited file)
4
+
5
+ > **Precondition: the change must have terminal-observable behavior.** If the change is a web-only UI with no command-line / REPL / TUI surface, this section does NOT apply — `tdt_*` tools spawn a program attached to a PTY. Just do browser verification.
6
+
7
+ If the project has terminal verification enabled (`ironbee terminal enable` once at setup) and your edits touch matching paths, the Stop hook also enforces a terminal cycle. The same `verification-start` covers both cycles; one platform-agnostic verdict covers both.
8
+
9
+ ### Mode behavior (terminal cycle)
10
+ - **default** (no arg or `default`): exercise only the commands / code paths your diff touched.
11
+ - **full**: exercise every terminal-reachable code path from files matching `terminal.verifyPatterns`.
12
+ - `visual` / `functional`: browser-only modes; terminal cycle behaves as `default` when they are passed.
13
+
14
+ ### Steps (run within step 3 of the Universal steps above)
15
+ 1. **Pick an evidence path** for the changed code:
16
+ - **Run-evidence** (proves a non-interactive command works): run the affected command one-shot with `mcp__terminal-devtools__tdt_pty_run` — it spawns the command attached to a PTY, runs it to completion, and returns the FULL output plus exit code. Confirm the output shows the expected result AND the exit code matches expectation. Best for CLIs, build targets, scripts, and test runs.
17
+ - **Interactive-evidence** (proves a REPL / shell / TUI change works):
18
+ - Spawn the program: `mcp__terminal-devtools__tdt_pty_start` (returns a `paneId`).
19
+ - Drive input: `mcp__terminal-devtools__tdt_interaction_send-keys` (tmux key syntax — `Enter`, `C-c`, `Up`, `Tab`, …) and `mcp__terminal-devtools__tdt_interaction_send-text` (literal text).
20
+ - Synchronize before reading: `mcp__terminal-devtools__tdt_sync_wait-for` (block until the expected output appears — prefer over delays).
21
+ - Capture output: `mcp__terminal-devtools__tdt_content_capture` — `mode: stream` for line-oriented programs (REPLs, shells; incremental `since` cursor reads only new lines), `mode: screen` for full-screen TUIs. Confirm it shows the expected result.
22
+ - Stop the pane: `mcp__terminal-devtools__tdt_pty_stop`.
23
+ - Auxiliary (NOT gate evidence): `mcp__terminal-devtools__tdt_sync_wait-for-idle`, `mcp__terminal-devtools__tdt_content_get-cursor`, `mcp__terminal-devtools__tdt_pty_resize`, `mcp__terminal-devtools__tdt_pty_signal`, `mcp__terminal-devtools__tdt_pty_list`.
24
+ 2. **Submit verdict** — platform-agnostic, just status + checks (+ issues/fixes).
25
+
26
+ ### Verdict (platform-agnostic)
27
+ ```json
28
+ {
29
+ "session_id": "...",
30
+ "status": "pass",
31
+ "checks": ["`mycli build` exits 0 with the new summary line", "REPL `:help` lists the new command"]
32
+ }
33
+ ```
34
+
35
+ For a multi-cycle pass, both browser and terminal pass criteria must hold.
36
+
37
+ ---
38
+
39
+ ## Default Mode (terminal cycle)
40
+
41
+ Focus on the commands or code paths your diff touched — not the entire program.
42
+
43
+ ### 1. Study the changes
44
+ 1. Run `git diff --name-only` and `git diff --name-only HEAD~1`
45
+ 2. **Ignore `.ironbee/`, `.claude/`, `.cursor/`** — tool config, not application code
46
+ 3. **Read the full diff** for every terminal file in scope — note new commands, changed flags, new output lines, changed exit codes, new REPL/TUI behavior
47
+ 4. Before spawning, identify: which command / subcommand / REPL command / TUI screen is affected? What input exercises it? What output / exit code proves it works?
48
+
49
+ ### 2. Verify against the running program
50
+ - **Run-evidence**: run the affected command via `tdt_pty_run`; the output must show the expected result and the exit code must match expectation
51
+ - **Interactive-evidence**: spawn the program, drive the affected input flow (send-keys / send-text), wait for the expected output (`tdt_sync_wait-for`), and capture it (`tdt_content_capture`) — the capture must show the expected state after your change
52
+
53
+ ---
54
+
55
+ ## Full Mode (`$ironbee-verify full`, terminal cycle)
56
+
57
+ Verify every terminal-reachable code path from files matching `terminal.verifyPatterns`, not just the changed files. Do NOT run `git diff` or scope to recent changes.
58
+
59
+ - Exercise every command / subcommand / REPL command / TUI screen in scope
60
+ - Drive at least one happy-path flow AND one error-path flow per command (confirm both the success output/exit `0` and the expected failure output/non-zero exit)
61
+ - Capture output (run-evidence or interactive-evidence) for each path; no unexpected crashes or stack traces
@@ -21,8 +21,9 @@ These attach to the **Required steps** above — they don't replace any step. Nu
21
21
  - **Within step 3 (run flow):** also run the android flow: connect (`adt_device_connect`) → launch app (`adt_device_launch-app`) → pick ONE evidence path:
22
22
  - **Device-evidence**: drive UI (`adt_interaction_tap` / `adt_interaction_input-text` / `adt_interaction_swipe`) + screenshot (`adt_content_take-screenshot`) + UI snapshot (`adt_a11y_take-ui-snapshot`)
23
23
  - **Log-evidence**: read Logcat (`adt_o11y_log-read` or `adt_o11y_log-follow`) confirming expected output and no crashes
24
+ - **Network-evidence**: capture outgoing HTTP traffic (`adt_o11y_get-http-requests` — forward-looking: start capture, drive the app, read again) confirming the expected request(s)/status. Auxiliary setup only (NOT evidence): `adt_o11y_new-trace-id` (pin correlation), `adt_stub_*` (mock/intercept).
24
25
  - If `recording.enable` is on, the gate forces `adt_content_start-recording` BEFORE the android steps above and rejects the verdict if you don't call `adt_content_stop-recording` AFTER them. Always pair start/stop around the steps above.
25
- - **Within step 6 (submit verdict):** submit one platform-agnostic verdict with `status` + `checks` (+ `issues`/`fixes` as needed). Android-cycle pass criteria: device connected AND (UI-interaction + screenshot + UI snapshot taken) OR (Logcat read with no crashes).
26
+ - **Within step 6 (submit verdict):** submit one platform-agnostic verdict with `status` + `checks` (+ `issues`/`fixes` as needed). Android-cycle pass criteria: device connected AND (UI-interaction + screenshot + UI snapshot taken) OR (Logcat read with no crashes) OR (outgoing HTTP traffic captured and confirmed).
26
27
 
27
28
  ### Additional BANNED for android cycle
28
29
 
@@ -0,0 +1,31 @@
1
+ <!-- Terminal verification is ENABLED for this project. The Stop hook
2
+ enforces a terminal cycle whenever an edited file matches
3
+ `terminal.verifyPatterns`. -->
4
+
5
+ ## Terminal cycle
6
+
7
+ Terminal file changes IF the file matches `terminal.verifyPatterns` ALSO require verification through the **terminal-devtools** MCP server (prefix `tdt_`). Terminal-cycle verification means spawning the affected program attached to a PTY and confirming its behavior — either running the command one-shot and checking its output and exit code, OR driving an interactive session (REPL / shell / TUI) and capturing the rendered output.
8
+
9
+ Both cycles can be active simultaneously (e.g. you edit both a React component and a CLI command in the same task). One `verification-start` covers all active cycles; one platform-agnostic verdict covers them all; one retry counter applies globally.
10
+
11
+ ### ⚠️ `terminal-devtools` is ONLY for terminal-observable behavior
12
+
13
+ `terminal-devtools` drives CLIs, REPLs, shells, and TUIs through a PTY. It does NOT apply to web-only UI changes with no command-line surface. If the change produces no terminal-observable output (stdout / stderr / exit code / rendered TUI), do NOT call `tdt_*` tools — use the browser cycle for web-only projects.
14
+
15
+ **Misconfiguration recovery.** If you reach this state, the operator enabled the terminal cycle by mistake. The Stop hook will keep blocking with `incomplete_tools` for the terminal cycle. Don't attempt to spawn a PTY. Instead, stop and clearly report to the user: this change has no terminal-observable behavior; ask them to run `ironbee terminal disable` to unblock the gate.
16
+
17
+ ### Terminal-cycle additions to the main flow
18
+
19
+ These attach to the **Required steps** above — they don't replace any step. Numbering follows the main flow:
20
+
21
+ - **Within step 3 (run flow):** also run the terminal flow: pick ONE evidence path:
22
+ - **Run-evidence**: run the affected command one-shot (`tdt_pty_run`) and confirm its output AND exit code match expectation
23
+ - **Interactive-evidence**: spawn a pane (`tdt_pty_start`) → drive input (`tdt_interaction_send-keys` / `tdt_interaction_send-text`) → synchronize (`tdt_sync_wait-for`) → capture output (`tdt_content_capture`, `mode: stream` for REPLs/shells, `mode: screen` for TUIs) → stop the pane (`tdt_pty_stop`). Auxiliary only (NOT evidence): `tdt_sync_wait-for-idle`, `tdt_content_get-cursor`, `tdt_pty_resize` / `tdt_pty_signal` / `tdt_pty_list`.
24
+ - **Within step 6 (submit verdict):** submit one platform-agnostic verdict with `status` + `checks` (+ `issues`/`fixes` as needed). Terminal-cycle pass criteria: (command ran via `tdt_pty_run` with output + exit code confirmed) OR (pane spawned AND input driven AND output captured showing the expected result).
25
+
26
+ ### Additional BANNED for terminal cycle
27
+
28
+ - Calling `tdt_*` tools without first opening a verification cycle (`ironbee hook verification-start`).
29
+ - **Calling `tdt_*` tools when the change has NO terminal-observable behavior.** Use the browser cycle only for web-only projects.
30
+ - Claiming `status: pass` for a terminal cycle when no evidence path was exercised.
31
+ - Claiming `status: pass` on the run-evidence path without confirming the exit code, or on the interactive-evidence path without capturing output that shows the expected result.
@@ -24,6 +24,7 @@ verification, so its script must collect what the android cycle collects). In th
24
24
  - **Log-evidence path** — `adt_o11y_log-read` / `adt_o11y_log-follow` (with `returnOutput: true`)
25
25
  for the tag(s) relevant to the change; confirm expected lines appear AND no FATAL / crash (E/
26
26
  entries) for the app package.
27
+ - **Network-evidence path** — capture outgoing HTTP traffic with `adt_o11y_get-http-requests` (`returnOutput: true`): start capture, drive the app (`adt_interaction_*`) to trigger traffic, read again, and put the captured request(s)/status in your result. Optional setup helpers (NOT evidence): `adt_o11y_new-trace-id` to pin a correlation root, `adt_stub_*` to mock/intercept responses.
27
28
 
28
29
  `return` the evidence — UI-snapshot text, log lines, the screenshot `filePath`s — **plus explicit
29
30
  pass/fail assertions**. That returned result is what `$ironbee-verify scenario:<name>` reads to judge
@@ -0,0 +1,36 @@
1
+ ### terminal platform (enabled)
2
+ - **Use for**: CLI / REPL / shell / TUI scenarios driven through a PTY.
3
+ - **Server**: `terminal-devtools` · **scenario tools**: the `tdt_scenario-*` tools
4
+ (`tdt_scenario-add` / `-update` / `-delete` / `-list` / `-search` / `-run`).
5
+ - **Store**: project → `.ironbee/scenarios/tdt`, global → `~/.ironbee/scenarios/tdt` (the
6
+ server's `SCENARIOS_DIR`; you pass `scope`, the server resolves the path).
7
+ - Scenario **scripts** call this platform's tools via `callTool('<bare-tool>', {...})` — discover
8
+ the available `tdt_*` tool names from your connected MCP tool schemas; don't guess.
9
+
10
+ **What to test & how — capture the SAME evidence the verifier would** (a scenario runs FOR
11
+ verification, so its script must collect what the terminal cycle collects). In the script, pick an
12
+ **evidence path** for the changed code area:
13
+ 1. **Run-evidence path** — run the affected command one-shot with `tdt_pty_run` (with
14
+ `returnOutput: true`): it spawns the command attached to a PTY, runs it to completion, and returns
15
+ the FULL output plus exit code. Put the returned output AND exit code in your result; the verifier
16
+ reads them to judge whether the change behaved correctly. Best for non-interactive CLIs, build
17
+ targets, scripts, and test runs.
18
+ 2. **Interactive-evidence path** — drive a live session:
19
+ - Spawn the program: `tdt_pty_start` (returns a `paneId` you reference for the rest of the script).
20
+ - Drive input: `tdt_interaction_send-keys` (tmux key syntax — `Enter`, `C-c`, `Up`, `Tab`, …) and
21
+ `tdt_interaction_send-text` (literal text).
22
+ - **Synchronize before reading** — `tdt_sync_wait-for` to block until the expected output appears
23
+ (prefer over fixed delays).
24
+ - Capture output: `tdt_content_capture` (with `returnOutput: true`) — `mode: stream` for
25
+ line-oriented programs (REPLs, shells; incremental `since` cursor reads only new lines),
26
+ `mode: screen` for full-screen TUIs. Its captured text is what the verifier reads.
27
+ - Stop the pane: `tdt_pty_stop`.
28
+ - Optional helpers (NOT evidence): `tdt_sync_wait-for-idle` (wait until output settles),
29
+ `tdt_content_get-cursor` (read the stream cursor), `tdt_pty_resize` / `tdt_pty_signal` /
30
+ `tdt_pty_list`.
31
+
32
+ `return` the evidence — the captured output text, the exit code (run-evidence) — **plus explicit
33
+ pass/fail assertions**. That returned result is what `$ironbee-verify scenario:<name>` reads to judge
34
+ functional correctness (from the output text and exit code). **`terminal-devtools` has no
35
+ screenshots / video** — there is no visual artifact to capture; the captured text and exit code ARE
36
+ the evidence. **`terminal-devtools` is for terminal-observable behavior only.**
@@ -32,6 +32,9 @@ If you see only `ios/`, `web/`, or no mobile directories — the project does NO
32
32
  - **Log-evidence path** (device logs confirm the changed code path executed):
33
33
  - Read Logcat output for the tag(s) relevant to the changed code: `mcp__android-devtools__adt_o11y_log-read` or `mcp__android-devtools__adt_o11y_log-follow` (drain a follow with `mcp__android-devtools__adt_o11y_log-get-followed`, stop it with `mcp__android-devtools__adt_o11y_log-stop-follow`).
34
34
  - Confirm expected log lines appear AND no unexpected crashes (FATAL / E/ entries for the app package).
35
+ - **Network-evidence path** (captured HTTP traffic confirms a network/API-related change):
36
+ - Capture the app's outgoing HTTP(S) requests: `mcp__android-devtools__adt_o11y_get-http-requests` (Frida/OkHttp in-process — no proxy, no CA install; OkHttp-based stacks only — Retrofit / React Native / HttpURLConnection). **Capture is forward-looking**: call it once to start capture, drive the app to trigger traffic (`mcp__android-devtools__adt_interaction_*`), then call it again to read. Confirm the expected request(s) / response status appear.
37
+ - **Auxiliary (NOT evidence — setup/correlation only):** to pin one correlation root across the flow, optionally `mcp__android-devtools__adt_o11y_new-trace-id` first (it stamps `traceparent` on every captured request; inspect/clear via `mcp__android-devtools__adt_o11y_set-trace-context` / `mcp__android-devtools__adt_o11y_get-trace-context`). To set up test conditions, `mcp__android-devtools__adt_stub_mock-http-response` / `mcp__android-devtools__adt_stub_intercept-http-request` mock or mutate responses (list/clear with `mcp__android-devtools__adt_stub_list` / `mcp__android-devtools__adt_stub_clear`). `mcp__android-devtools__adt_figma_compare-screen-with-design` checks emulator-vs-Figma parity (optional, requires `FIGMA_ACCESS_TOKEN`). None of these count toward the gate — they shape the test, they don't inspect it.
35
38
 
36
39
  **Batch (speed):** connect + launch-app run standalone first (prerequisites). On the device-evidence path, batch the UI interactions + the UI snapshot into one `mcp__android-devtools__adt_execute`; the snapshot captures the state after the batched interactions, so to assert an intermediate state take a snapshot at that point too. The device-evidence screenshot is usually pixel-judged (a visual change) — take THAT one standalone with `includeBase64: true` so you can see it; batch it only when it's purely gate evidence. Log-evidence reads batch together too.
37
40
 
@@ -51,6 +54,7 @@ On fail, include `issues`. On pass after a previous fail, include `fixes`.
51
54
  Android-cycle pass criteria:
52
55
  - **Device-evidence**: at least one UI interaction tool fired AND a screenshot was taken AND a UI snapshot was taken AND both show the expected UI state/structure.
53
56
  - **Log-evidence**: Logcat was read AND the expected log lines are present AND no crash (FATAL / unhandled exception) from the app's package.
57
+ - **Network-evidence**: the app's outgoing HTTP traffic was captured AND the expected request(s) / response status confirm the change behaved correctly.
54
58
 
55
59
  ## Multi-cycle (browser + android simultaneously)
56
60
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  > **Recording (only when `recording.enable` is on in config):** the gate blocks every other browser tool until you first call `mcp__browser-devtools__bdt_content_start-recording`, and `submit-verdict` rejects with `"recording is still active"` unless you call `mcp__browser-devtools__bdt_content_stop-recording` after the steps below. **Treat start/stop as bookends around steps 1-5.** The same is enforced as step 6 of the Universal flow.
8
8
 
9
- 1. **Navigate**: `mcp__browser-devtools__bdt_navigation_go-to` — go to the affected page(s)
9
+ 1. **Navigate**: `mcp__browser-devtools__bdt_navigation_go-to` — go to the affected page(s) **AND any downstream page that renders or consumes what the change produces** — verify the change's effect where it's observed, not only the page the edited file owns
10
10
  2. **Interact**: actually exercise what changed — click buttons, fill forms, submit data, trigger workflows. Don't just look at the page.
11
11
  3. **Screenshot**: `mcp__browser-devtools__bdt_content_take-screenshot` — capture the final visual state
12
12
  4. **Accessibility**: `mcp__browser-devtools__bdt_a11y_take-aria-snapshot` — verify page structure
@@ -0,0 +1,57 @@
1
+ <!-- Terminal verification is ENABLED for this project. The Stop hook
2
+ enforces a terminal cycle whenever an edited file matches
3
+ `terminal.verifyPatterns`. -->
4
+
5
+ ## ⚠️ CRITICAL: when NOT to use terminal-devtools
6
+
7
+ **`terminal-devtools` is ONLY for programs with terminal-observable behavior** — CLIs, REPLs, shells, and full-screen TUIs that you can drive by spawning them attached to a PTY. Do **NOT** call `tdt_*` tools for changes that produce no terminal-observable behavior.
8
+
9
+ **How to tell whether the change has terminal-observable behavior:**
10
+ - A CLI entrypoint (`bin/` script, `package.json` `"bin"` field, a `main()` that parses argv, a `cobra`/`commander`/`click`/`clap` command tree)
11
+ - A REPL / interactive prompt the user types into
12
+ - A full-screen TUI (`blessed`, `ink`, `ratatui`, `bubbletea`, `ncurses`, …)
13
+ - A script / build target / shell command whose stdout, stderr, or exit code changed
14
+
15
+ If the change is a web-only UI with no command-line or terminal surface — that's the **browser cycle**, not this one. Do NOT call any `tdt_*` tools.
16
+
17
+ **Misconfiguration recovery.** If this cycle activated but the change has no terminal-observable behavior, the operator enabled the terminal cycle by mistake. The Stop hook will keep blocking with `incomplete_tools` until `maxRetries` is exhausted. Don't attempt to spawn a PTY. Stop and tell the user clearly: this change has no terminal-observable behavior; ask them to run `ironbee terminal disable` to unblock the gate.
18
+
19
+ ## Terminal flow
20
+
21
+ The terminal cycle drives CLIs / REPLs / TUIs by spawning them attached to a PTY (like tmux). Pick the evidence path that fits the changed code area:
22
+
23
+ 1. **Pick an evidence path** per changed code area:
24
+ - **Run-evidence path** (one-shot command confirms the change works):
25
+ - Run the affected command end-to-end: `mcp__terminal-devtools__tdt_pty_run` — it spawns the command attached to a PTY, runs it to completion, and returns the FULL output plus the exit code in one call. Best for non-interactive CLIs, build targets, scripts, and test runs.
26
+ - Confirm the returned output shows the expected result AND the exit code matches expectation (`0` for success; the expected non-zero code when failure is the change under test).
27
+ - **Interactive-evidence path** (driving a live session confirms an interactive change):
28
+ - Spawn the program attached to a PTY: `mcp__terminal-devtools__tdt_pty_start` — returns a `paneId` you reference for the rest of the flow. Best for REPLs, shells, and full-screen TUIs.
29
+ - Drive input to exercise the changed code: `mcp__terminal-devtools__tdt_interaction_send-keys` (tmux key syntax — `Enter`, `C-c`, `Up`, `Tab`, …) for control keys / navigation, `mcp__terminal-devtools__tdt_interaction_send-text` for literal text.
30
+ - **Synchronize before reading** — block until the expected output appears with `mcp__terminal-devtools__tdt_sync_wait-for` (prefer this over fixed delays).
31
+ - Capture the output: `mcp__terminal-devtools__tdt_content_capture` — use `mode: stream` for line-oriented programs (REPLs, shells; supports an incremental `since` cursor so you read only new lines), and `mode: screen` for full-screen TUIs (snapshots the rendered screen).
32
+ - Confirm the capture shows the expected result for the change.
33
+ - Stop the pane when done: `mcp__terminal-devtools__tdt_pty_stop`.
34
+ - **Auxiliary (NOT evidence — synchronization / housekeeping only):** `mcp__terminal-devtools__tdt_sync_wait-for-idle` (block until output settles), `mcp__terminal-devtools__tdt_content_get-cursor` (read the stream cursor position), `mcp__terminal-devtools__tdt_pty_resize` (resize the PTY), `mcp__terminal-devtools__tdt_pty_signal` (send a signal), `mcp__terminal-devtools__tdt_pty_list` (list active panes). None of these count toward the gate — they help you drive the session, they don't inspect the change.
35
+
36
+ **Batch (speed):** on the run-evidence path, a single `mcp__terminal-devtools__tdt_pty_run` already does the whole thing (spawn + run + capture + exit code), so there's nothing to batch. On the interactive-evidence path, `tdt_pty_start` runs standalone first (prerequisite); then batch a coherent sequence of `tdt_interaction_send-*` + `tdt_sync_wait-for` + `tdt_content_capture` into one `mcp__terminal-devtools__tdt_execute` — the capture reads the state after the batched input, so to assert an intermediate state add a `tdt_sync_wait-for` + capture at that point too.
37
+
38
+ ### Verdict fields
39
+ The verdict is platform-agnostic — submit only semantic judgment:
40
+
41
+ ```json
42
+ {
43
+ "session_id": "<sid>",
44
+ "status": "pass",
45
+ "checks": ["`mycli build` exits 0 and prints the new summary line", "REPL `:help` lists the new command"]
46
+ }
47
+ ```
48
+
49
+ On fail, include `issues`. On pass after a previous fail, include `fixes`.
50
+
51
+ Terminal-cycle pass criteria:
52
+ - **Run-evidence**: the affected command was run via `tdt_pty_run` AND its output AND exit code confirm the change behaved correctly.
53
+ - **Interactive-evidence**: a pane was spawned (`tdt_pty_start`) AND input was driven (`tdt_interaction_send-keys` / `tdt_interaction_send-text`) AND output was captured (`tdt_content_capture`) AND it shows the expected result.
54
+
55
+ ## Multi-cycle (browser + terminal simultaneously)
56
+
57
+ Both cycles can be active simultaneously. One `verification-start` covers all active cycles; one platform-agnostic verdict covers them all; one retry counter applies globally.
@@ -1,2 +1,2 @@
1
- "use strict";var a=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var f=Object.prototype.hasOwnProperty;var l=(e,i)=>a(e,"name",{value:i,configurable:!0});var y=(e,i)=>{for(var o in i)a(e,o,{get:i[o],enumerable:!0})},x=(e,i,o,n)=>{if(i&&typeof i=="object"||typeof i=="function")for(let s of g(i))!f.call(e,s)&&s!==o&&a(e,s,{get:()=>i[s],enumerable:!(n=m(i,s))||n.enumerable});return e};var h=e=>x(a({},"__esModule",{value:!0}),e);var v={};y(v,{codexProcessAnalyticsCommand:()=>C});module.exports=h(v);var c=require("commander"),r=require("fs"),t=require("../../lib/logger"),d=require("../../analytics/codex/events-emit"),u=require("../../analytics/codex/emit"),p=require("../../analytics/codex/transcript");const C=new c.Command("process-analytics").description("Internal worker \u2014 emit Codex api_request + session_status + session_analytics events for one Stop trigger").requiredOption("--project <dir>","project directory (where .ironbee/sessions/<sid>/ lives)").requiredOption("--session <id>","session id").option("--rollout-path <path>","rollout JSONL path (from Codex hook stdin); falls back to discovery walk").option("--user-email <email>","session user email (from state.json:userEmail)").option("--usage-type <type>","api | subscription (from state.json:usageType)").option("--usage-plan <plan>","subscription plan id (from state.json:usagePlan)").option("--activity-id <id>","current active activity id (for session_status correlation)").action(async e=>{(0,t.setLogFile)(`${e.project}/.ironbee/sessions/${e.session}/session.log`);const i=e.usageType==="api"||e.usageType==="subscription"?e.usageType:void 0;let o=e.rolloutPath;(o===void 0||!(0,r.existsSync)(o))&&(o=(0,p.findCodexRolloutPath)(e.session)??void 0);let n;if(o!==void 0&&(0,r.existsSync)(o))try{n=P(o)}catch(s){t.logger.debug(`codex process-analytics rollout parse failed: ${s instanceof Error?s.message:s}`)}await Promise.allSettled([(0,d.emitCodexAnalytics)({projectDir:e.project,sessionId:e.session,rolloutPath:o,preloadedLines:n,userEmail:e.userEmail,usageType:i,usagePlan:e.usagePlan,activityId:e.activityId??""}).catch(s=>{t.logger.debug(`codex process-analytics emit failed: ${s instanceof Error?s.message:s}`)}),(0,u.emitCodexSessionAnalytics)({projectDir:e.project,sessionId:e.session,rolloutPath:o,preloadedLines:n,userEmail:e.userEmail,usageType:i,usagePlan:e.usagePlan,isFinal:!1}).catch(s=>{t.logger.debug(`codex process-analytics session-emit failed: ${s instanceof Error?s.message:s}`)})]),t.logger.debug(`codex process-analytics: complete session=${e.session}`),process.exit(0)});function P(e){const i=(0,r.readFileSync)(e,"utf-8"),o=[];for(const n of i.split(`
2
- `))if(n.length!==0)try{o.push(JSON.parse(n))}catch{}return o}l(P,"parseRolloutLines");0&&(module.exports={codexProcessAnalyticsCommand});
1
+ "use strict";var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var l=(e,i)=>a(e,"name",{value:i,configurable:!0});var x=(e,i)=>{for(var o in i)a(e,o,{get:i[o],enumerable:!0})},h=(e,i,o,n)=>{if(i&&typeof i=="object"||typeof i=="function")for(let s of g(i))!y.call(e,s)&&s!==o&&a(e,s,{get:()=>i[s],enumerable:!(n=f(i,s))||n.enumerable});return e};var C=e=>h(a({},"__esModule",{value:!0}),e);var j={};x(j,{codexProcessAnalyticsCommand:()=>P});module.exports=C(j);var c=require("commander"),r=require("fs"),t=require("../../lib/logger"),d=require("../../analytics/codex/events-emit"),u=require("../../analytics/codex/emit"),p=require("../../analytics/codex/transcript"),m=require("../../lib/runtime-paths");const P=new c.Command("process-analytics").description("Internal worker \u2014 emit Codex api_request + session_status + session_analytics events for one Stop trigger").requiredOption("--project <dir>","project directory (where .ironbee/sessions/<sid>/ lives)").requiredOption("--session <id>","session id").option("--rollout-path <path>","rollout JSONL path (from Codex hook stdin); falls back to discovery walk").option("--user-email <email>","session user email (from state.json:userEmail)").option("--usage-type <type>","api | subscription (from state.json:usageType)").option("--usage-plan <plan>","subscription plan id (from state.json:usagePlan)").option("--activity-id <id>","current active activity id (for session_status correlation)").action(async e=>{(0,t.setLogFile)((0,m.sessionLogFile)(e.project,e.session));const i=e.usageType==="api"||e.usageType==="subscription"?e.usageType:void 0;let o=e.rolloutPath;(o===void 0||!(0,r.existsSync)(o))&&(o=(0,p.findCodexRolloutPath)(e.session)??void 0);let n;if(o!==void 0&&(0,r.existsSync)(o))try{n=v(o)}catch(s){t.logger.debug(`codex process-analytics rollout parse failed: ${s instanceof Error?s.message:s}`)}await Promise.allSettled([(0,d.emitCodexAnalytics)({projectDir:e.project,sessionId:e.session,rolloutPath:o,preloadedLines:n,userEmail:e.userEmail,usageType:i,usagePlan:e.usagePlan,activityId:e.activityId??""}).catch(s=>{t.logger.debug(`codex process-analytics emit failed: ${s instanceof Error?s.message:s}`)}),(0,u.emitCodexSessionAnalytics)({projectDir:e.project,sessionId:e.session,rolloutPath:o,preloadedLines:n,userEmail:e.userEmail,usageType:i,usagePlan:e.usagePlan,isFinal:!1}).catch(s=>{t.logger.debug(`codex process-analytics session-emit failed: ${s instanceof Error?s.message:s}`)})]),t.logger.debug(`codex process-analytics: complete session=${e.session}`),process.exit(0)});function v(e){const i=(0,r.readFileSync)(e,"utf-8"),o=[];for(const n of i.split(`
2
+ `))if(n.length!==0)try{o.push(JSON.parse(n))}catch{}return o}l(v,"parseRolloutLines");0&&(module.exports={codexProcessAnalyticsCommand});
@@ -31,6 +31,9 @@ Every `apply_patch` clears the verdict, requiring re-verification. The Stop gate
31
31
  <!--IRONBEE:PLATFORM:android-->
32
32
  <!--/IRONBEE:PLATFORM:android-->
33
33
 
34
+ <!--IRONBEE:PLATFORM:terminal-->
35
+ <!--/IRONBEE:PLATFORM:terminal-->
36
+
34
37
  ## BANNED
35
38
 
36
39
  - Reporting a task complete without verifying your changes through the real tools.
@@ -98,6 +98,9 @@ the dominant cost. Drive the tools in as few turns as you can:
98
98
  <!--IRONBEE:PLATFORM:android-->
99
99
  <!--/IRONBEE:PLATFORM:android-->
100
100
 
101
+ <!--IRONBEE:PLATFORM:terminal-->
102
+ <!--/IRONBEE:PLATFORM:terminal-->
103
+
101
104
  ## Important
102
105
  - **Always submit a verdict after every verification attempt** — both pass AND fail.
103
106
  - Submit verdicts via `ironbee hook submit-verdict`, never write `verdict.json` directly.
@@ -1 +1 @@
1
- "use strict";var d=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var T=Object.prototype.hasOwnProperty;var a=(n,e)=>d(n,"name",{value:e,configurable:!0});var y=(n,e)=>{for(var r in e)d(n,r,{get:e[r],enumerable:!0})},l=(n,e,r,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of m(e))!T.call(n,t)&&t!==r&&d(n,t,{get:()=>e[t],enumerable:!(i=g(e,t))||i.enumerable});return n};var E=n=>l(d({},"__esModule",{value:!0}),n);var w={};y(w,{codexThreadMapPath:()=>c,lookupThreadSession:()=>x,pruneThreadMapping:()=>v,writeThreadMapping:()=>F});module.exports=E(w);var s=require("fs"),u=require("path"),p=require("../../lib/logger");const M=256,b=1440*60*1e3;function c(n){return(0,u.join)(n,".ironbee","codex-threads.json")}a(c,"codexThreadMapPath");function h(n){try{const e=(0,s.readFileSync)(n,"utf-8"),r=JSON.parse(e);if(r&&typeof r=="object"&&r.version===1){const i=r;if(i.threads&&typeof i.threads=="object")return i}}catch{}return{version:1,threads:{}}}a(h,"readMap");function S(n,e){const r=Object.entries(n).filter(([,t])=>e-t.ts<b).sort((t,o)=>o[1].ts-t[1].ts).slice(0,M),i={};for(const[t,o]of r)i[t]=o;return i}a(S,"pruneStale");function f(n,e){(0,s.mkdirSync)((0,u.dirname)(n),{recursive:!0});const r=`${n}.${process.pid}.tmp`;(0,s.writeFileSync)(r,JSON.stringify(e),"utf-8"),(0,s.renameSync)(r,n)}a(f,"writeMapAtomic");function F(n,e,r,i=Date.now()){if(!(!e||!r))try{const t=c(n),o=h(t);o.threads[e]={session_id:r,ts:i},o.threads=S(o.threads,i),f(t,o)}catch(t){p.logger.debug(`codex thread-map write failed: ${t instanceof Error?t.message:String(t)}`)}}a(F,"writeThreadMapping");function x(n,e){if(!e)return;const r=c(n);return(0,s.existsSync)(r)?h(r).threads[e]?.session_id:void 0}a(x,"lookupThreadSession");function v(n,e){if(e)try{const r=c(n);if(!(0,s.existsSync)(r))return;const i=h(r);i.threads[e]!==void 0&&(delete i.threads[e],f(r,i))}catch(r){p.logger.debug(`codex thread-map prune failed: ${r instanceof Error?r.message:String(r)}`)}}a(v,"pruneThreadMapping");0&&(module.exports={codexThreadMapPath,lookupThreadSession,pruneThreadMapping,writeThreadMapping});
1
+ "use strict";var d=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var a=(t,e)=>d(t,"name",{value:e,configurable:!0});var l=(t,e)=>{for(var r in e)d(t,r,{get:e[r],enumerable:!0})},E=(t,e,r,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of T(e))!y.call(t,n)&&n!==r&&d(t,n,{get:()=>e[n],enumerable:!(i=m(e,n))||i.enumerable});return t};var M=t=>E(d({},"__esModule",{value:!0}),t);var k={};l(k,{codexThreadMapPath:()=>c,lookupThreadSession:()=>v,pruneThreadMapping:()=>w,writeThreadMapping:()=>x});module.exports=M(k);var s=require("fs"),u=require("path"),p=require("../../lib/logger"),g=require("../../lib/runtime-paths");const S=256,b=1440*60*1e3;function c(t){return(0,u.join)((0,g.runtimeDir)(t),"codex-threads.json")}a(c,"codexThreadMapPath");function h(t){try{const e=(0,s.readFileSync)(t,"utf-8"),r=JSON.parse(e);if(r&&typeof r=="object"&&r.version===1){const i=r;if(i.threads&&typeof i.threads=="object")return i}}catch{}return{version:1,threads:{}}}a(h,"readMap");function F(t,e){const r=Object.entries(t).filter(([,n])=>e-n.ts<b).sort((n,o)=>o[1].ts-n[1].ts).slice(0,S),i={};for(const[n,o]of r)i[n]=o;return i}a(F,"pruneStale");function f(t,e){(0,s.mkdirSync)((0,u.dirname)(t),{recursive:!0});const r=`${t}.${process.pid}.tmp`;(0,s.writeFileSync)(r,JSON.stringify(e),"utf-8"),(0,s.renameSync)(r,t)}a(f,"writeMapAtomic");function x(t,e,r,i=Date.now()){if(!(!e||!r))try{const n=c(t),o=h(n);o.threads[e]={session_id:r,ts:i},o.threads=F(o.threads,i),f(n,o)}catch(n){p.logger.debug(`codex thread-map write failed: ${n instanceof Error?n.message:String(n)}`)}}a(x,"writeThreadMapping");function v(t,e){if(!e)return;const r=c(t);return(0,s.existsSync)(r)?h(r).threads[e]?.session_id:void 0}a(v,"lookupThreadSession");function w(t,e){if(e)try{const r=c(t);if(!(0,s.existsSync)(r))return;const i=h(r);i.threads[e]!==void 0&&(delete i.threads[e],f(r,i))}catch(r){p.logger.debug(`codex thread-map prune failed: ${r instanceof Error?r.message:String(r)}`)}}a(w,"pruneThreadMapping");0&&(module.exports={codexThreadMapPath,lookupThreadSession,pruneThreadMapping,writeThreadMapping});