@ironbee-ai/cli 0.31.0 → 0.33.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 (73) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/clients/base.js +1 -1
  3. package/dist/clients/claude/agents/ironbee-scenario.md +40 -11
  4. package/dist/clients/claude/agents/ironbee-verifier.md +40 -4
  5. package/dist/clients/claude/commands/ironbee-manage-scenario.md +2 -1
  6. package/dist/clients/claude/hooks/require-verdict.js +2 -2
  7. package/dist/clients/claude/hooks/require-verification.js +3 -3
  8. package/dist/clients/claude/hooks/track-action-monitor.js +1 -1
  9. package/dist/clients/claude/hooks/track-action.js +1 -1
  10. package/dist/clients/claude/index.js +4 -4
  11. package/dist/clients/claude/platforms/scenario.terminal.md +26 -0
  12. package/dist/clients/claude/platforms/skill.browser.md +1 -1
  13. package/dist/clients/claude/platforms/skill.terminal.md +62 -0
  14. package/dist/clients/codex/agents/ironbee-scenario.md +39 -10
  15. package/dist/clients/codex/agents/ironbee-verifier.md +39 -3
  16. package/dist/clients/codex/commands/ironbee-manage-scenario/SKILL.main.md +21 -6
  17. package/dist/clients/codex/commands/ironbee-manage-scenario/SKILL.md +2 -1
  18. package/dist/clients/codex/commands/ironbee-search-scenario/SKILL.main.md +3 -0
  19. package/dist/clients/codex/commands/ironbee-sync-scenario/SKILL.main.md +4 -1
  20. package/dist/clients/codex/commands/ironbee-verify/SKILL.main.md +4 -0
  21. package/dist/clients/codex/hooks/require-verification.js +1 -1
  22. package/dist/clients/codex/hooks/track-action.js +1 -1
  23. package/dist/clients/codex/index.js +2 -2
  24. package/dist/clients/codex/platforms/command-verify.terminal.md +61 -0
  25. package/dist/clients/codex/platforms/rule.terminal.md +31 -0
  26. package/dist/clients/codex/platforms/scenario.terminal.md +36 -0
  27. package/dist/clients/codex/platforms/skill.browser.md +1 -1
  28. package/dist/clients/codex/platforms/skill.terminal.md +57 -0
  29. package/dist/clients/codex/rules/ironbee-verification.main.md +3 -0
  30. package/dist/clients/codex/skills/ironbee-verification.main.md +14 -0
  31. package/dist/clients/codex/util.js +1 -1
  32. package/dist/clients/cursor/commands/ironbee-manage-scenario/SKILL.md +21 -6
  33. package/dist/clients/cursor/commands/ironbee-search-scenario/SKILL.md +3 -0
  34. package/dist/clients/cursor/commands/ironbee-sync-scenario/SKILL.md +4 -1
  35. package/dist/clients/cursor/commands/ironbee-verify/SKILL.md +4 -0
  36. package/dist/clients/cursor/hooks/require-verdict.js +2 -2
  37. package/dist/clients/cursor/hooks/require-verification.js +3 -3
  38. package/dist/clients/cursor/hooks/track-action-monitor.js +1 -1
  39. package/dist/clients/cursor/hooks/track-action.js +1 -1
  40. package/dist/clients/cursor/index.js +1 -1
  41. package/dist/clients/cursor/platforms/command-verify.terminal.md +61 -0
  42. package/dist/clients/cursor/platforms/rule.terminal.md +31 -0
  43. package/dist/clients/cursor/platforms/scenario.terminal.md +29 -0
  44. package/dist/clients/cursor/platforms/skill.browser.md +1 -1
  45. package/dist/clients/cursor/platforms/skill.terminal.md +54 -0
  46. package/dist/clients/cursor/rules/ironbee-verification.mdc +3 -0
  47. package/dist/clients/cursor/skills/ironbee-verification.md +14 -0
  48. package/dist/clients/registry.js +1 -1
  49. package/dist/commands/config.js +2 -2
  50. package/dist/commands/hook.js +22 -19
  51. package/dist/commands/install.js +1 -1
  52. package/dist/commands/platform-suggest.js +2 -0
  53. package/dist/commands/scenario.js +1 -1
  54. package/dist/commands/terminal.js +1 -0
  55. package/dist/hooks/core/actions.js +9 -7
  56. package/dist/hooks/core/run-checks.js +7 -0
  57. package/dist/hooks/core/verification-context.js +19 -15
  58. package/dist/hooks/core/verify-gate.js +35 -21
  59. package/dist/import/claude/events/tool-call.js +1 -1
  60. package/dist/import/codex/events/tool-call.js +1 -1
  61. package/dist/index.js +1 -1
  62. package/dist/lib/config.js +1 -1
  63. package/dist/lib/event.js +1 -1
  64. package/dist/lib/headless.js +1 -0
  65. package/dist/lib/install-version.js +1 -1
  66. package/dist/lib/platform-section.js +5 -4
  67. package/dist/lib/prompt.js +6 -5
  68. package/dist/lib/scenario-staleness.js +1 -1
  69. package/dist/tui/config/schema.js +1 -1
  70. package/dist/tui/platforms/area.js +2 -2
  71. package/dist/tui/projects/area.js +4 -4
  72. package/dist/tui/shell/session.js +5 -5
  73. package/package.json +1 -1
@@ -1,7 +1,8 @@
1
- "use strict";var w=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var K=Object.prototype.hasOwnProperty;var c=(e,n)=>w(e,"name",{value:n,configurable:!0});var P=(e,n)=>{for(var o in n)w(e,o,{get:n[o],enumerable:!0})},$=(e,n,o,u)=>{if(n&&typeof n=="object"||typeof n=="function")for(let t of A(n))!K.call(e,t)&&t!==o&&w(e,t,{get:()=>n[t],enumerable:!(u=k(n,t))||u.enumerable});return e};var E=e=>$(w({},"__esModule",{value:!0}),e);var I={};P(I,{PROMPT_BACK:()=>C,isInteractive:()=>h,keyToMultiSelectAction:()=>y,promptAcknowledge:()=>L,promptChoice:()=>N,promptMultiSelect:()=>j,promptSelect:()=>B,promptYesNo:()=>T,reduceMultiSelect:()=>M,renderMultiSelect:()=>x,renderSelect:()=>R});module.exports=E(I);var f=require("readline"),a=require("./output");function h(){return!!process.stdin.isTTY&&!!process.stdout.isTTY}c(h,"isInteractive");function N(e,n,o=0){const t=[e,...n.map((r,i)=>{const l=i===o?" (default)":"";return` ${i+1}) ${r}${l}`})].join(`
1
+ "use strict";var x=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var T=Object.prototype.hasOwnProperty;var a=(e,n)=>x(e,"name",{value:n,configurable:!0});var j=(e,n)=>{for(var o in n)x(e,o,{get:n[o],enumerable:!0})},B=(e,n,o,s)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of N(n))!T.call(e,r)&&r!==o&&x(e,r,{get:()=>n[r],enumerable:!(s=E(n,r))||s.enumerable});return e};var I=e=>B(x({},"__esModule",{value:!0}),e);var W={};j(W,{PROMPT_BACK:()=>L,isInteractive:()=>P,keyToMultiSelectAction:()=>k,promptAcknowledge:()=>H,promptChoice:()=>_,promptMultiSelect:()=>J,promptSelect:()=>O,promptYesNo:()=>q,reduceMultiSelect:()=>R,renderMultiSelect:()=>K,renderSelect:()=>$});module.exports=I(W);var h=require("readline"),c=require("./output");function P(){return!!process.stdin.isTTY&&!!process.stdout.isTTY}a(P,"isInteractive");function _(e,n,o=0){const r=[e,...n.map((i,l)=>{const u=l===o?" (default)":"";return` ${l+1}) ${i}${u}`})].join(`
2
2
  `)+`
3
- > `,s=(0,f.createInterface)({input:process.stdin,output:process.stdout});return new Promise(r=>{s.question(t,i=>{s.close();const l=i.trim();if(l.length===0){r(o);return}const d=Number.parseInt(l,10);if(!Number.isNaN(d)&&d>=1&&d<=n.length){r(d-1);return}const b=n.findIndex(m=>m.toLowerCase()===l.toLowerCase());if(b!==-1){r(b);return}r(o)})})}c(N,"promptChoice");function T(e,n){const o=n?" [Y/n] ":" [y/N] ",u=(0,f.createInterface)({input:process.stdin,output:process.stdout});return new Promise(t=>{u.question(e+o,s=>{u.close();const r=s.trim().toLowerCase();if(r.length===0){t(n);return}if(r==="y"||r==="yes"){t(!0);return}if(r==="n"||r==="no"){t(!1);return}t(n)})})}c(T,"promptYesNo");function L(e){const n=(0,f.createInterface)({input:process.stdin,output:process.stdout});return new Promise(o=>{let u=!1;const t=c(()=>{u||(u=!0,n.close(),o())},"done");n.question(e,()=>t()),n.on("close",()=>t())})}c(L,"promptAcknowledge");function y(e){if(e.ctrl===!0&&e.name==="c")return"cancel";switch(e.name){case"up":case"k":return"up";case"down":case"j":return"down";case"space":return"toggle";case"a":return"toggleAll";case"return":case"enter":return"submit";case"escape":return"back";default:return"none"}}c(y,"keyToMultiSelectAction");function M(e,n){if(e.n<=0)return!1;switch(n){case"up":return e.cursor=(e.cursor-1+e.n)%e.n,!0;case"down":return e.cursor=(e.cursor+1)%e.n,!0;case"toggle":return e.selected.has(e.cursor)?e.selected.delete(e.cursor):e.selected.add(e.cursor),!0;case"toggleAll":if(e.selected.size===e.n)e.selected.clear();else for(let o=0;o<e.n;o++)e.selected.add(o);return!0;default:return!1}}c(M,"reduceMultiSelect");function p(e,n,o){return`${o(a.pc.bold(e))} ${a.pc.dim(n)}`}c(p,"keyHint");const S=a.pc.dim(" \xB7 ");function x(e,n,o){const u=n.reduce((r,i)=>Math.max(r,i.label.length),0),t=" "+[p("\u2191/\u2193","move",a.pc.cyan),p("space","select",a.pc.yellow),p("a","all",a.pc.magenta),p("enter","confirm",a.pc.green)].join(S),s=[e,t];return n.forEach((r,i)=>{const l=i===o.cursor,d=l?a.pc.cyan(">"):" ",b=o.selected.has(i)?a.pc.yellow("[x]"):"[ ]",m=l?a.pc.bold(r.label.padEnd(u)):r.label.padEnd(u),g=r.hint?" "+a.pc.dim(r.hint):"";s.push(`${d} ${b} ${m}${g}`)}),s}c(x,"renderMultiSelect");function j(e,n,o){const u=o.filter(s=>s>=0&&s<n.length).sort((s,r)=>s-r);if(n.length===0)return Promise.resolve([...u]);const t={cursor:0,selected:new Set(u),n:n.length};return new Promise(s=>{v(()=>x(e,n,t),i=>i==="cancel"||i==="back"?"cancel":i==="submit"?"submit":M(t,i)?"redraw":"ignore",()=>s([...t.selected].sort((i,l)=>i-l)))||s([...u])})}c(j,"promptMultiSelect");function R(e,n,o){const u=n.reduce((r,i)=>Math.max(r,i.label.length),0),t=" "+[p("\u2191/\u2193","move",a.pc.cyan),p("enter","select",a.pc.green)].join(S),s=[e,t];return n.forEach((r,i)=>{const l=i===o,d=l?a.pc.cyan(">"):" ",b=l?a.pc.bold(r.label.padEnd(u)):r.label.padEnd(u),m=r.hint?" "+a.pc.dim(r.hint):"";s.push(`${d} ${b}${m}`)}),s}c(R,"renderSelect");function B(e,n,o=0,u={}){if(n.length===0)return Promise.resolve(o);let t=o>=0&&o<n.length?o:0;return new Promise(s=>{v(()=>R(e,n,t),i=>i==="cancel"?"cancel":i==="back"?u.allowBack===!0?"back":"cancel":i==="submit"?"submit":i==="up"?(t=(t-1+n.length)%n.length,"redraw"):i==="down"?(t=(t+1)%n.length,"redraw"):"ignore",()=>s(t),u.allowBack===!0?()=>s(C):void 0)||s(o)})}c(B,"promptSelect");const C=-1;function v(e,n,o,u){const t=process.stdin;if(!h()||typeof t.setRawMode!="function")return!1;const s=process.stdout;let r=0;const i=c(b=>{!b&&r>0&&s.write(`\x1B[${r}A`),s.write("\x1B[0J");const m=e();s.write(m.join(`
3
+ > `,t=(0,h.createInterface)({input:process.stdin,output:process.stdout});return new Promise(i=>{t.question(r,l=>{t.close();const u=l.trim();if(u.length===0){i(o);return}const g=Number.parseInt(u,10);if(!Number.isNaN(g)&&g>=1&&g<=n.length){i(g-1);return}const b=n.findIndex(m=>m.toLowerCase()===u.toLowerCase());if(b!==-1){i(b);return}i(o)})})}a(_,"promptChoice");function q(e,n){const o=n?" [Y/n] ":" [y/N] ",s=(0,h.createInterface)({input:process.stdin,output:process.stdout});return new Promise(r=>{s.question(e+o,t=>{s.close();const i=t.trim().toLowerCase();if(i.length===0){r(n);return}if(i==="y"||i==="yes"){r(!0);return}if(i==="n"||i==="no"){r(!1);return}r(n)})})}a(q,"promptYesNo");function H(e){const n=(0,h.createInterface)({input:process.stdin,output:process.stdout});return new Promise(o=>{let s=!1;const r=a(()=>{s||(s=!0,n.close(),o())},"done");n.question(e,()=>r()),n.on("close",()=>r())})}a(H,"promptAcknowledge");function k(e){if(e.ctrl===!0&&e.name==="c")return"cancel";switch(e.name){case"up":case"k":return"up";case"down":case"j":return"down";case"space":return"toggle";case"a":return"toggleAll";case"s":return"suggest";case"return":case"enter":return"submit";case"escape":return"back";default:return"none"}}a(k,"keyToMultiSelectAction");function R(e,n){if(e.n<=0)return!1;switch(n){case"up":return e.cursor=(e.cursor-1+e.n)%e.n,!0;case"down":return e.cursor=(e.cursor+1)%e.n,!0;case"toggle":return e.selected.has(e.cursor)?e.selected.delete(e.cursor):e.selected.add(e.cursor),!0;case"toggleAll":if(e.selected.size===e.n)e.selected.clear();else for(let o=0;o<e.n;o++)e.selected.add(o);return!0;default:return!1}}a(R,"reduceMultiSelect");function S(e,n,o){return`${o(c.pc.bold(e))} ${c.pc.dim(n)}`}a(S,"keyHint");const A=c.pc.dim(" \xB7 ");function K(e,n,o,s){const r=n.reduce((u,g)=>Math.max(u,g.label.length),0),t=[S("\u2191/\u2193","move",c.pc.cyan),S("space","select",c.pc.yellow),S("a","all",c.pc.magenta)];s&&t.push(S("s",`suggest (${s.label})`,c.pc.blue)),t.push(S("enter","confirm",c.pc.green));const i=" "+t.join(A),l=[e,i];return n.forEach((u,g)=>{const b=g===o.cursor,m=b?c.pc.cyan(">"):" ",p=o.selected.has(g)?c.pc.yellow("[x]"):"[ ]",w=b?c.pc.bold(u.label.padEnd(r)):u.label.padEnd(r),d=u.hint?" "+c.pc.dim(u.hint):"";l.push(`${m} ${p} ${w}${d}`)}),l}a(K,"renderMultiSelect");function J(e,n,o,s){const r=o.filter(d=>d>=0&&d<n.length).sort((d,v)=>d-v);if(n.length===0)return Promise.resolve([...r]);const t={cursor:0,selected:new Set(r),n:n.length},i=s?.onSuggest,l=typeof i=="function",u=s?.suggestLabel??"the agent",g=l?{label:s?.suggestLabel??"ai"}:void 0;let b=!1,m=null;const p=a(()=>{const d=K(e,n,t,g);return b?d.push(" "+c.pc.cyan(`Analysing project with ${u}... (${c.pc.bold("Esc")} to cancel)`)):m&&d.push(" "+c.pc.dim(m)),d},"render"),w=l?async(d,v)=>{b=!0,m=null,v();let f=null;try{f=await i(d)}catch{f=null}b=!1;const M=(f??[]).filter(y=>y>=0&&y<n.length);M.length>0?(t.selected=new Set(M),t.cursor=Math.min(t.cursor,n.length-1),m=null):m="Couldn't analyse \u2014 keeping current selection"}:void 0;return new Promise(d=>{C(p,f=>f==="cancel"||f==="back"?"cancel":f==="submit"?"submit":f==="suggest"?l?"suggest":"ignore":(m=null,R(t,f)?"redraw":"ignore"),()=>d([...t.selected].sort((f,M)=>f-M)),void 0,w)||d([...r])})}a(J,"promptMultiSelect");function $(e,n,o){const s=n.reduce((i,l)=>Math.max(i,l.label.length),0),r=" "+[S("\u2191/\u2193","move",c.pc.cyan),S("enter","select",c.pc.green)].join(A),t=[e,r];return n.forEach((i,l)=>{const u=l===o,g=u?c.pc.cyan(">"):" ",b=u?c.pc.bold(i.label.padEnd(s)):i.label.padEnd(s),m=i.hint?" "+c.pc.dim(i.hint):"";t.push(`${g} ${b}${m}`)}),t}a($,"renderSelect");function O(e,n,o=0,s={}){if(n.length===0)return Promise.resolve(o);let r=o>=0&&o<n.length?o:0;return new Promise(t=>{C(()=>$(e,n,r),l=>l==="cancel"?"cancel":l==="back"?s.allowBack===!0?"back":"cancel":l==="submit"?"submit":l==="up"?(r=(r-1+n.length)%n.length,"redraw"):l==="down"?(r=(r+1)%n.length,"redraw"):"ignore",()=>t(r),s.allowBack===!0?()=>t(L):void 0)||t(o)})}a(O,"promptSelect");const L=-1;function C(e,n,o,s,r){const t=process.stdin;if(!P()||typeof t.setRawMode!="function")return!1;const i=process.stdout;let l=0;const u=a(m=>{!m&&l>0&&i.write(`\x1B[${l}A`),i.write("\x1B[0J");const p=e();i.write(p.join(`
4
4
  `)+`
5
- `),r=m.length},"draw"),l=c(()=>{t.removeListener("keypress",d),typeof t.setRawMode=="function"&&t.setRawMode(!1),t.pause()},"cleanup"),d=c((b,m)=>{if(!m)return;const g=n(y(m));if(g==="cancel"){l(),s.write(`
6
- `),process.exit(130);return}if(g==="back"){l(),u?u():(s.write(`
7
- `),process.exit(130));return}if(g==="submit"){l(),o();return}g==="redraw"&&i(!1)},"onKey");return(0,f.emitKeypressEvents)(t),t.setRawMode(!0),t.resume(),t.on("keypress",d),i(!0),!0}c(v,"runRawKeypressUI");0&&(module.exports={PROMPT_BACK,isInteractive,keyToMultiSelectAction,promptAcknowledge,promptChoice,promptMultiSelect,promptSelect,promptYesNo,reduceMultiSelect,renderMultiSelect,renderSelect});
5
+ `),l=p.length},"draw"),g=a(()=>{t.removeListener("keypress",b),typeof t.setRawMode=="function"&&t.setRawMode(!1),t.pause()},"cleanup"),b=a((m,p)=>{if(!p)return;const w=n(k(p));if(w==="cancel"){g(),i.write(`
6
+ `),process.exit(130);return}if(w==="back"){g(),s?s():(i.write(`
7
+ `),process.exit(130));return}if(w==="submit"){g(),o();return}if(w==="suggest"&&r){t.removeListener("keypress",b);const d=new AbortController,v=a((M,y)=>{if(y){if(y.ctrl===!0&&y.name==="c"){d.abort(),g(),i.write(`
8
+ `),process.exit(130);return}y.name==="escape"&&d.abort()}},"onAnalysisKey"),f=a(()=>{t.removeListener("keypress",v),t.on("keypress",b),u(!1)},"reattach");t.on("keypress",v),r(d.signal,()=>u(!1)).then(f,f);return}w==="redraw"&&u(!1)},"onKey");return(0,h.emitKeypressEvents)(t),t.setRawMode(!0),t.resume(),t.on("keypress",b),u(!0),!0}a(C,"runRawKeypressUI");0&&(module.exports={PROMPT_BACK,isInteractive,keyToMultiSelectAction,promptAcknowledge,promptChoice,promptMultiSelect,promptSelect,promptYesNo,reduceMultiSelect,renderMultiSelect,renderSelect});
@@ -1 +1 @@
1
- "use strict";var h=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var l=(e,n)=>h(e,"name",{value:n,configurable:!0});var E=(e,n)=>{for(var s in n)h(e,s,{get:n[s],enumerable:!0})},F=(e,n,s,a)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of P(n))!C.call(e,r)&&r!==s&&h(e,r,{get:()=>n[r],enumerable:!(a=k(n,r))||a.enumerable});return e};var x=e=>F(h({},"__esModule",{value:!0}),e);var A={};E(A,{checkScenarioFreshness:()=>V,coverageGaps:()=>O});module.exports=x(A);var g=require("fs"),p=require("path"),f=require("./git"),b=require("./config"),y=require("./logger");const S={bdt:"browser",ndt:"node",bedt:"backend",adt:"android"};function v(e){return e.length>7?e.slice(0,7):e}l(v,"shortSha");function $(e){const n=e.metadata;if(n===null||typeof n!="object")return{};const s=n.ironbee;return s!==null&&typeof s=="object"?s:{}}l($,"readIronBeeMeta");function w(e){const n=(0,p.join)(e,".ironbee","scenarios");if(!(0,g.existsSync)(n))return[];const s=[];for(const a of Object.keys(S)){const r=(0,p.join)(n,a);if(!(0,g.existsSync)(r))continue;let t;try{t=(0,g.readdirSync)(r).filter(o=>o.endsWith(".json"))}catch(o){y.logger.debug(`scenario-staleness: cannot read ${r}: ${o instanceof Error?o.message:o}`);continue}for(const o of t){const c=(0,p.join)(r,o);let i;try{i=JSON.parse((0,g.readFileSync)(c,"utf-8"))}catch(m){y.logger.debug(`scenario-staleness: bad JSON ${c}: ${m instanceof Error?m.message:m}`);continue}const u=typeof i.name=="string"&&i.name.length>0?i.name:o.replace(/\.json$/,""),d=$(i),R=Array.isArray(d.coveredPaths)?d.coveredPaths.filter(m=>typeof m=="string"):[];s.push({name:u,platform:S[a],file:c,coveredPaths:R,commit:typeof d.commit=="string"&&d.commit.length>0?d.commit:void 0,liveValidated:typeof d.liveValidated=="boolean"?d.liveValidated:void 0})}}return s}l(w,"readScenarioEntries");function V(e){const n=w(e);if(n.length===0)return[];const s=(0,f.isGitRepo)(e),a=new Map,r=[];for(const t of n){const o={name:t.name,platform:t.platform,file:t.file,coveredPaths:t.coveredPaths,commit:t.commit,liveValidated:t.liveValidated,changedCoveredPaths:[]};if(!s){r.push({...o,state:"unknown",reason:"not a git repository"});continue}if(t.coveredPaths.length===0){r.push({...o,state:"unknown",reason:"no ironbee.coveredPaths metadata"});continue}if(t.commit===void 0){r.push({...o,state:"unknown",reason:"no ironbee.commit baseline"});continue}if(!(0,f.gitCommitExists)(e,t.commit)){r.push({...o,state:"unknown",reason:`baseline commit ${v(t.commit)} not in history`});continue}let c;const i=a.get(t.commit);i!==void 0?c=i:(c=(0,f.gitChangedPathsSince)(e,t.commit),a.set(t.commit,c));const u=c.filter(d=>(0,b.matchesAny)(d,t.coveredPaths));if(u.length>0){r.push({...o,state:"stale",reason:`${u.length} covered file(s) changed since ${v(t.commit)}`,changedCoveredPaths:u});continue}if(t.liveValidated===!1){r.push({...o,state:"stale",reason:"authored as a draft \u2014 not live-validated by a passing run"});continue}r.push({...o,state:"fresh",reason:`no covered files changed since ${v(t.commit)}`})}return r}l(V,"checkScenarioFreshness");function O(e,n){const s=w(e),a=Array.from(new Set(n.filter(o=>o.length>0))),r=[],t=[];for(const o of a){const c=s.filter(i=>i.coveredPaths.length>0&&(0,b.matchesAny)(o,i.coveredPaths)).map(i=>i.name);c.length>0?r.push({path:o,scenarios:c}):t.push(o)}return{scenarioCount:s.length,covered:r,gaps:t,changed:a}}l(O,"coverageGaps");0&&(module.exports={checkScenarioFreshness,coverageGaps});
1
+ "use strict";var h=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var l=(e,n)=>h(e,"name",{value:n,configurable:!0});var E=(e,n)=>{for(var s in n)h(e,s,{get:n[s],enumerable:!0})},F=(e,n,s,a)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of P(n))!C.call(e,r)&&r!==s&&h(e,r,{get:()=>n[r],enumerable:!(a=k(n,r))||a.enumerable});return e};var x=e=>F(h({},"__esModule",{value:!0}),e);var A={};E(A,{checkScenarioFreshness:()=>V,coverageGaps:()=>O});module.exports=x(A);var g=require("fs"),p=require("path"),f=require("./git"),b=require("./config"),y=require("./logger");const S={bdt:"browser",ndt:"node",bedt:"backend",adt:"android",tdt:"terminal"};function v(e){return e.length>7?e.slice(0,7):e}l(v,"shortSha");function $(e){const n=e.metadata;if(n===null||typeof n!="object")return{};const s=n.ironbee;return s!==null&&typeof s=="object"?s:{}}l($,"readIronBeeMeta");function w(e){const n=(0,p.join)(e,".ironbee","scenarios");if(!(0,g.existsSync)(n))return[];const s=[];for(const a of Object.keys(S)){const r=(0,p.join)(n,a);if(!(0,g.existsSync)(r))continue;let t;try{t=(0,g.readdirSync)(r).filter(o=>o.endsWith(".json"))}catch(o){y.logger.debug(`scenario-staleness: cannot read ${r}: ${o instanceof Error?o.message:o}`);continue}for(const o of t){const c=(0,p.join)(r,o);let i;try{i=JSON.parse((0,g.readFileSync)(c,"utf-8"))}catch(u){y.logger.debug(`scenario-staleness: bad JSON ${c}: ${u instanceof Error?u.message:u}`);continue}const m=typeof i.name=="string"&&i.name.length>0?i.name:o.replace(/\.json$/,""),d=$(i),R=Array.isArray(d.coveredPaths)?d.coveredPaths.filter(u=>typeof u=="string"):[];s.push({name:m,platform:S[a],file:c,coveredPaths:R,commit:typeof d.commit=="string"&&d.commit.length>0?d.commit:void 0,liveValidated:typeof d.liveValidated=="boolean"?d.liveValidated:void 0})}}return s}l(w,"readScenarioEntries");function V(e){const n=w(e);if(n.length===0)return[];const s=(0,f.isGitRepo)(e),a=new Map,r=[];for(const t of n){const o={name:t.name,platform:t.platform,file:t.file,coveredPaths:t.coveredPaths,commit:t.commit,liveValidated:t.liveValidated,changedCoveredPaths:[]};if(!s){r.push({...o,state:"unknown",reason:"not a git repository"});continue}if(t.coveredPaths.length===0){r.push({...o,state:"unknown",reason:"no ironbee.coveredPaths metadata"});continue}if(t.commit===void 0){r.push({...o,state:"unknown",reason:"no ironbee.commit baseline"});continue}if(!(0,f.gitCommitExists)(e,t.commit)){r.push({...o,state:"unknown",reason:`baseline commit ${v(t.commit)} not in history`});continue}let c;const i=a.get(t.commit);i!==void 0?c=i:(c=(0,f.gitChangedPathsSince)(e,t.commit),a.set(t.commit,c));const m=c.filter(d=>(0,b.matchesAny)(d,t.coveredPaths));if(m.length>0){r.push({...o,state:"stale",reason:`${m.length} covered file(s) changed since ${v(t.commit)}`,changedCoveredPaths:m});continue}if(t.liveValidated===!1){r.push({...o,state:"stale",reason:"authored as a draft \u2014 not live-validated by a passing run"});continue}r.push({...o,state:"fresh",reason:`no covered files changed since ${v(t.commit)}`})}return r}l(V,"checkScenarioFreshness");function O(e,n){const s=w(e),a=Array.from(new Set(n.filter(o=>o.length>0))),r=[],t=[];for(const o of a){const c=s.filter(i=>i.coveredPaths.length>0&&(0,b.matchesAny)(o,i.coveredPaths)).map(i=>i.name);c.length>0?r.push({path:o,scenarios:c}):t.push(o)}return{scenarioCount:s.length,covered:r,gaps:t,changed:a}}l(O,"coverageGaps");0&&(module.exports={checkScenarioFreshness,coverageGaps});
@@ -1 +1 @@
1
- "use strict";var a=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var n=(e,t)=>a(e,"name",{value:t,configurable:!0});var g=(e,t)=>{for(var o in t)a(e,o,{get:t[o],enumerable:!0})},y=(e,t,o,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of u(t))!h.call(e,r)&&r!==o&&a(e,r,{get:()=>t[r],enumerable:!(i=p(t,r))||i.enumerable});return e};var b=e=>y(a({},"__esModule",{value:!0}),e);var T={};g(T,{ARTIFACT_AFFECTING_TOP_KEYS:()=>v,CONFIG_SCHEMA:()=>d,GROUP_ORDER:()=>s,GROUP_TITLES:()=>f,findSchemaEntry:()=>A,groupOf:()=>l,groupRank:()=>c,groupTitle:()=>w,orderedEntries:()=>k,topKey:()=>m});module.exports=b(T);const v=new Set(["verification","collector","browser","node","backend","android","browserDevTools","nodeDevTools","backendDevTools","androidDevTools","telemetry","privacy","statusLine","otel","codex","runtime"]),s=["general","runtime","verification","verificationContext","browser","node","backend","android","collector","recording","jobQueue","analytics","statusLine","claude","codex","telemetry","privacy","otel","fileChange","import","browserDevTools","nodeDevTools","backendDevTools","androidDevTools"],f={general:"General",runtime:"Runtime",verification:"Verification",verificationContext:"Verification context",browser:"Browser cycle",node:"Node cycle",backend:"Backend cycle",android:"Android cycle",collector:"Collector",recording:"Recording",jobQueue:"Job queue",analytics:"Analytics",statusLine:"Statusline",claude:"Claude",codex:"Codex",telemetry:"Telemetry",privacy:"Privacy",otel:"OTEL collector",fileChange:"File change",import:"Import",browserDevTools:"Browser DevTools MCP",nodeDevTools:"Node DevTools MCP",backendDevTools:"Backend DevTools MCP",androidDevTools:"Android DevTools MCP"};function m(e){const t=e.indexOf(".");return t===-1?e:e.slice(0,t)}n(m,"topKey");function l(e){const t=e.indexOf(".");return t===-1?"general":e.slice(0,t)}n(l,"groupOf");function w(e){return f[e]??e}n(w,"groupTitle");function c(e){const t=s.indexOf(e);return t===-1?s.length:t}n(c,"groupRank");const d=[{path:"ignoredVerifyPatterns",type:"string-array",editor:"string-list",description:"Glob patterns excluded from verification, applied to every cycle (browser / node / backend). Checked first \u2014 a match here activates no cycle regardless of other patterns. Unioned on top of an always-on default set that excludes test files (**/*.spec.*, **/*.test.*, **/__tests__/**, **/__mocks__/**) \u2014 a test-only edit never activates a runtime-verification cycle.",def:"[] (plus always-on test-file defaults)",artifactAffecting:!1},{path:"maxRetries",type:"number",editor:"number",description:"Max verification retry attempts before the gate allows completion despite failures. Single global counter regardless of how many cycles ran.",def:"3",artifactAffecting:!1},{path:"runtime.location",type:"string",editor:"enum",enumValues:["external","in-project"],description:`Where per-session runtime data (the sessions/ folder \u2014 actions.jsonl, verdicts, queue, analytics) is stored. "external" (default) keeps it OUT of the project tree at ~/.ironbee/projects/<token> so a project never accumulates a growing sessions/ folder even when gitignored; "in-project" stores it under <project>/.ironbee/sessions (the legacy layout). Committed config / scenarios / VERIFICATION.md always stay in-project regardless. The IRONBEE_RUNTIME_LOCATION env var overrides this per process (used by the test suite). Artifact-affecting on Codex: the external layout adds a [sandbox_workspace_write].writable_roots grant so the agent's verdict write outside the workspace doesn't prompt. Takes effect on the next session.`,def:"external",artifactAffecting:!0},{path:"verification.enable",type:"boolean",editor:"toggle",description:"Master enforcement switch. Inverse semantics \u2014 verification is the core feature, opt out with false. When false, IronBee runs monitoring-only: no enforcement hooks, no skill/rule, no MCP servers; only session/activity/tool_call events flow to the collector.",def:"true",artifactAffecting:!0},{path:"verification.auto",type:"boolean",editor:"toggle",description:"Automatic-enforcement sub-toggle (only meaningful when verification.enable !== false). Default FALSE \u2014 assist is the default mode (the safer default): the /ironbee-verify command + MCP servers stay installed so the agent can verify manually, but nothing is enforced \u2014 no Stop gate, non-blocking (soft) PreToolUse hooks, and the skill/rule are omitted. Opt into full enforcement with true (blocking Stop gate + skill/rule installed).",def:"false",artifactAffecting:!0},{path:"verification.strict",type:"boolean",editor:"toggle",description:'Strict mode (only meaningful in enforce mode). Default false. When true the verify-gate refuses N/A verdicts \u2014 both a global status "not_applicable" and per-platform not_applicable_cycles exemptions \u2014 so the agent must produce real verification tool evidence for every active cycle. Default (false) accepts N/A: the agent can declare a change has no runtime surface (globally or per-cycle) and the gate allows it, recorded + observable. Inert in assist/monitor (no gate runs). The gate reads it live; the rerender it shares with the rest of the verification block is idempotent (the N/A guidance is mode-agnostic, so the installed artifacts don\'t change). Set via `ironbee verification strict` enable/disable, `config set`, or at install \u2014 picking enforce opens a strictness sub-choice (interactive) and the `--strict` flag sets it non-interactively.',def:"false",artifactAffecting:!0},{path:"verification.model",type:"json",editor:"json",description:`Model the delegated verifier sub-agent uses. Unset \u2192 the verifier inherits the session model (Claude verifier omits model: \u2192 inherit; Codex verifier omits agent-toml model \u2192 inherits config.toml's model). Set to PIN a specific model \u2014 e.g. verify on a cheaper/faster model than the main agent, or guarantee a model on Codex when config.toml has none. Two shapes: a string (applies to all clients, e.g. "sonnet" / "gpt-5.5") or a per-client object { claude: "sonnet", codex: "gpt-5.5" } when a project has both clients. Cursor has no verifier sub-agent \u2192 no-op there. Never resolves to a literal "inherit" on Codex (a 400). Artifact-affecting.`,def:"unset (inherit the session model)",artifactAffecting:!0},{path:"verificationContext.enable",type:"boolean",editor:"toggle",description:"Master switch for path-scoped verification context. When a cycle begins, the first devtools tool call injects the .ironbee/VERIFICATION.md files on/above the changed paths (author-written area guidance) into the agent's context via the host's additionalContext channel. Advisory only (does not gate). Inverse semantics \u2014 default-on, opt out with false. Not artifact-affecting (read live).",def:"true",artifactAffecting:!1},{path:"verificationContext.source",type:"string",editor:"enum",enumValues:["git","actions"],description:`Changed-path source. "git" (default) = working tree + last N commits, with an actions.jsonl fallback when not a git repo. "actions" = IronBee's own file_change events only (no git subprocess).`,def:"git",artifactAffecting:!1},{path:"verificationContext.commitDepth",type:"number",editor:"number",description:'Number of recent commits included on the git source (uncommitted \u222A last N commits). 0 = uncommitted only. Ignored when source is "actions".',def:"1",artifactAffecting:!1},{path:"verificationContext.maxBytes",type:"number",editor:"number",description:"Aggregate byte cap on the injected context string. When exceeded, the least-specific (root-side) docs are dropped first (leaf-first truncation priority).",def:"65536 (64 KB)",artifactAffecting:!1},{path:"browser.enable",type:"boolean",editor:"toggle",description:"Explicit on/off for the browser cycle. Written false by `browser disable`, stripped by `browser enable`. When false the cycle is disabled regardless of patterns.",def:"(absent \u2192 on; browser is the only default-on cycle)",artifactAffecting:!0},{path:"browser.verifyPatterns",type:"string-array",editor:"string-list",description:"Glob patterns for files requiring browser verification. Four-state: absent \u2192 code defaults (40+ extensions); [] \u2192 hard kill; non-empty \u2192 custom patterns (replaces defaults).",def:"40+ code extensions when unset; [] hard-disables",artifactAffecting:!0},{path:"browser.additionalVerifyPatterns",type:"string-array",editor:"string-list",description:"Extra patterns appended to browser.verifyPatterns (or to code defaults when verifyPatterns is unset). Ignored when verifyPatterns is [] (hard kill wins).",def:"[]",artifactAffecting:!0},{path:"browser.alwaysRequired",type:"string-array",editor:"string-list",description:"Browser-cycle required tools (all-of). The verify-gate blocks completion until every listed bdt_* tool was used.",def:"bdt_navigation_go-to, bdt_content_take-screenshot, bdt_a11y_take-aria-snapshot, bdt_o11y_get-console-messages",artifactAffecting:!0},{path:"browser.evidencePaths",type:"json",editor:"json",description:"Alternative tool-satisfaction paths (any-of). Browser uses pure all-of, so default is empty. Each path: { name, allOf: (string | { anyOf: string[] })[] }.",def:"[]",artifactAffecting:!0},{path:"node.enable",type:"boolean",editor:"toggle",description:"Explicit on/off for the Node.js runtime debug cycle (node-devtools, ndt_* V8 inspector probes). Opt-in \u2014 written by `node enable`.",def:"(absent \u2192 off; node is opt-in)",artifactAffecting:!0},{path:"node.verifyPatterns",type:"string-array",editor:"string-list",description:"Glob patterns for the Node.js runtime debug cycle. Default-off \u2014 block absent = inert. Block present + unset \u2192 9 code defaults (server/api/routes paths).",def:"block absent \u2192 disabled; present + unset \u2192 code defaults",artifactAffecting:!0},{path:"node.additionalVerifyPatterns",type:"string-array",editor:"string-list",description:"Extra patterns appended to node.verifyPatterns (or to code defaults when unset). Ignored when verifyPatterns is [].",def:"[]",artifactAffecting:!0},{path:"node.alwaysRequired",type:"string-array",editor:"string-list",description:"Node-cycle required tools (all-of). ndt_debug_connect always; evidence paths supply the rest.",def:"[ndt_debug_connect]",artifactAffecting:!0},{path:"node.evidencePaths",type:"json",editor:"json",description:"Alternative tool paths (any-of). Default: probe path (a put-*point AND get-probe-snapshots) OR log path (get-logs).",def:"probe path + log path",artifactAffecting:!0},{path:"backend.enable",type:"boolean",editor:"toggle",description:"Explicit on/off for the runtime-agnostic backend protocol cycle (backend-devtools, bedt_* HTTP/gRPC/GraphQL/WebSocket). Opt-in \u2014 written by `backend enable`.",def:"(absent \u2192 off; backend is opt-in)",artifactAffecting:!0},{path:"backend.verifyPatterns",type:"string-array",editor:"string-list",description:"Glob patterns for the backend protocol cycle. Default-off \u2014 block absent = inert. Block present + unset \u2192 13 multi-language code defaults (ts/js/py/go/java/rb/cs/rs/kt/scala/ex/php/clj).",def:"block absent \u2192 disabled; present + unset \u2192 code defaults",artifactAffecting:!0},{path:"backend.additionalVerifyPatterns",type:"string-array",editor:"string-list",description:"Extra patterns appended to backend.verifyPatterns (or to code defaults when unset). Ignored when verifyPatterns is [].",def:"[]",artifactAffecting:!0},{path:"backend.alwaysRequired",type:"string-array",editor:"string-list",description:"Backend-cycle required tools (all-of). Empty by default \u2014 backend uses any-of evidence paths instead.",def:"[]",artifactAffecting:!0},{path:"backend.evidencePaths",type:"json",editor:"json",description:"Alternative tool paths (any-of). Default three: protocol-call (any request tool) OR log-evidence (register-source + read) OR db-evidence (db_connect + a read op).",def:"protocol-call OR log-evidence OR db-evidence",artifactAffecting:!0},{path:"android.enable",type:"boolean",editor:"toggle",description:"Explicit on/off for the Android mobile verification cycle (android-devtools, adt_* device/emulator interaction). Opt-in \u2014 written by `android enable`.",def:"(absent \u2192 off; android is opt-in)",artifactAffecting:!0},{path:"android.verifyPatterns",type:"string-array",editor:"string-list",description:"Glob patterns for the Android mobile verification cycle. Default-off \u2014 block absent = inert. Block present + unset \u2192 code defaults (Android/React Native paths).",def:"block absent \u2192 disabled; present + unset \u2192 code defaults",artifactAffecting:!0},{path:"android.additionalVerifyPatterns",type:"string-array",editor:"string-list",description:"Extra patterns appended to android.verifyPatterns (or to code defaults when unset). Ignored when verifyPatterns is [].",def:"[]",artifactAffecting:!0},{path:"android.alwaysRequired",type:"string-array",editor:"string-list",description:"Android-cycle required tools (all-of). adt_device_connect always; evidence paths supply the rest.",def:"[adt_device_connect]",artifactAffecting:!0},{path:"android.evidencePaths",type:"json",editor:"json",description:"Alternative tool paths (any-of). Default three: device-evidence (UI interaction + screenshot + UI snapshot) OR log-evidence (Logcat read/follow) OR network-evidence (adt_o11y_get-http-requests HTTP capture). The adt_o11y_*-trace-context and adt_stub_* tools are auxiliary (NOT evidence paths).",def:"device-evidence OR log-evidence OR network-evidence",artifactAffecting:!0},{path:"collector.enable",type:"boolean",editor:"toggle",description:"Master switch for the IronBee Collector. Implicitly true when the section has url and at least one credential (oauthToken or apiKey); set false to suspend while keeping url/oauthToken/apiKey/batchSize around.",def:"implicit true when url + (oauthToken or apiKey) set",artifactAffecting:!0},{path:"collector.url",type:"string",editor:"text",description:"Remote collector endpoint URL (IronBee Platform). Required for the collector to be active. Events POST to {url}/v1/events.",def:"(unset \u2192 disabled)",artifactAffecting:!0},{path:"collector.oauthToken",type:"string",editor:"text",description:"Personal access token for collector auth (X-OAuth-Token header). Per-(user, account), independently revocable from the console's /access-tokens page. Minted by `ironbee login` \u2014 the primary path for interactive CLI use. Can be supplied via IRONBEE_OAUTH_TOKEN.",def:"(unset)",artifactAffecting:!0},{path:"collector.apiKey",type:"string",editor:"text",description:"Shared account API key for collector auth (X-API-Key header). Parallel first-class path alongside `oauthToken`, intended for CI / GitHub Actions / deployment tooling and other non-interactive integrations where rotating a per-engineer OAuth token is impractical. Either `oauthToken` OR `apiKey` is required for the collector to be active. Can be supplied via IRONBEE_API_KEY.",def:"(unset \u2192 disabled)",artifactAffecting:!0},{path:"collector.batchSize",type:"number",editor:"number",description:"Max events per POST from the send_event handler (the queue chunks bigger snapshots into N-sized POSTs).",def:"100",artifactAffecting:!0},{path:"collector.timeoutMs",type:"number",editor:"number",description:"Per-request HTTP timeout (ms) for batched analytics sends. Single-event interactive sends keep a fixed 3000ms cap. Clamped to [1000, 60000].",def:"10000",artifactAffecting:!0},{path:"recording.enable",type:"boolean",editor:"toggle",description:"Recording enforcement for the browser + android cycles. Presence opts in; enable:false opts out. Auto-enabled when a collector is configured. Node/backend cycles never trigger recording.",def:"implicit true when section present or collector configured",artifactAffecting:!1},{path:"jobQueue.enable",type:"boolean",editor:"toggle",description:"Master switch for the file-backed job queue. Presence opts in; enable:false opts out. Auto-enabled when a collector is configured (a collector is pointless without a queue feeding it).",def:"implicit true when section present or collector configured",artifactAffecting:!1},{path:"jobQueue.autoFlushSizeBytes",type:"number",editor:"number",description:"Size threshold (bytes) above which submit() spawns a detached worker mid-session. 0 / negative disables this check.",def:"32768 (32 KB)",artifactAffecting:!1},{path:"jobQueue.autoFlushIntervalSeconds",type:"number",editor:"number",description:"Interval threshold (seconds since the live jobs.jsonl was created) above which submit() spawns a detached worker. Complements size \u2014 whichever crosses first flushes. 0 / negative disables.",def:"60",artifactAffecting:!1},{path:"analytics.enable",type:"boolean",editor:"toggle",description:"Master switch for per-session structural analytics. Presence opts in; enable:false opts out. Auto-enabled when a collector is configured.",def:"implicit true when section present or collector configured",artifactAffecting:!1},{path:"analytics.emitOnStop",type:"boolean",editor:"toggle",description:"When true, project + emit analytics at every Stop hook. When false, only at SessionEnd.",def:"true",artifactAffecting:!1},{path:"analytics.emitOnStopMinIntervalSeconds",type:"number",editor:"number",description:"Throttle: skip Stop-hook projection if the last successful emit was within this many seconds. 0 disables the throttle (backend handles rate-limit / dedupe).",def:"0 (disabled)",artifactAffecting:!1},{path:"analytics.emitTurnEvents",type:"boolean",editor:"toggle",description:"Opt-in for per-turn session_turn_analytics wire records. High-volume secondary signal; the base session_analytics record always ships regardless.",def:"false",artifactAffecting:!1},{path:"analytics.emitStepEvents",type:"boolean",editor:"toggle",description:"Opt-in for per-step session_turn_step_analytics wire records (an order of magnitude higher volume than turn events). Independent of emitTurnEvents.",def:"false",artifactAffecting:!1},{path:"analytics.emitApiRequestEvents",type:"boolean",editor:"toggle",description:"Opt-OUT for per-API-request api_request wire records (one per assistant message, success + failure). Primary value for backend cost accounting, so ships by default.",def:"true",artifactAffecting:!1},{path:"statusLine.enable",type:"boolean",editor:"toggle",description:"Master switch for the Claude statusline integration (session_status event + statusline wrapper). Presence opts in; auto-enabled when a collector is configured. Claude-only.",def:"implicit true when section present or collector configured",artifactAffecting:!0},{path:"statusLine.renderDefault",type:"boolean",editor:"toggle",description:"When there is no upstream statusline to chain to, false keeps the statusline silent; true renders a minimal model + context-% line. No effect when the user already has a statusline.",def:"false",artifactAffecting:!0},{path:"statusLine.emitMinIntervalSeconds",type:"number",editor:"number",description:"Minimum seconds between two emitted session_status events, on top of skip-if-unchanged. Rapid changes coalesce to the latest state after the interval. 0 disables the throttle. Read live each tick.",def:"10",artifactAffecting:!0},{path:"statusLine.refreshInterval",type:"number",editor:"number",description:"Claude Code's own statusLine.refreshInterval (seconds, host min 1) \u2014 re-runs the statusline on a timer in addition to event-driven updates. Unset by default. Values < 1 treated as unset.",def:"unset",artifactAffecting:!0},{path:"claude.oauthAccess.enable",type:"boolean",editor:"toggle",description:"Whether IronBee may read the Claude Code OAuth token (macOS Keychain / ~/.claude/.credentials.json) and call OAuth-scoped Anthropic endpoints. Default-on (opt out with false or `ironbee claude oauth-access disable`). First consumer: the statusline rate-limit fallback \u2014 fetches /api/oauth/usage to fill rate_limits for plans the statusline JSON omits them for (team / enterprise). Claude-only; not artifact-affecting (read live).",def:"true",artifactAffecting:!1},{path:"claude.oauthAccess.usageTtlSeconds",type:"number",editor:"number",description:"TTL (seconds) for the statusline OAuth rate-limit fetch cache \u2014 the /api/oauth/usage call + credential read fire at most once per this interval even when the statusline ticks far more often. Default 60; 0 means every tick.",def:"60",artifactAffecting:!1},{path:"claude.autoModeAllowlist.enable",type:"boolean",editor:"toggle",description:"Whether IronBee writes the auto-mode allowlist carve-out for the verifier into .claude/settings.local.json. Claude Code 2.1.176+ ships a host-side sub-agent \"Content Integrity\" classifier (auto mode) that false-positives on IronBee's legitimate `ironbee hook submit-verdict` verdicts (the devtools calls happened earlier in the cycle, not re-shown in the handoff). When enabled (default), install adds a narrow, command-keyed autoMode.allow rule that exempts ONLY that command from the Content Integrity block ($defaults preserved \u2014 every other block rule still applies; IronBee's Stop-gate independently enforces real tool usage). Written only when verification is active (enforce/assist); inert when the host isn't in auto mode. Opt out with false \u2014 takes effect on the next `ironbee install`. Claude-only.",def:"true",artifactAffecting:!1},{path:"claude.trustWorkspace.enable",type:"boolean",editor:"toggle",description:"Whether `ironbee install` marks the installed project trusted in Claude Code's machine-global ~/.claude.json (projects[\"<dir>\"].hasTrustDialogAccepted: true) when it isn't already. Claude Code 2.1.x ignores a project's committed permissions.allow (the devtools + `Bash(ironbee *)` entries IronBee writes) until the workspace is trusted \u2014 and once onboarding has been seen the trust dialog no longer re-appears, so the entries stay silently disabled and the agent gets prompted on every devtools/ironbee call. Default-on (opt out with false). Only ever flips a missing/false flag to true; never clobbers other ~/.claude.json content. Best-effort + idempotent. Claude-only; not artifact-affecting (writes the host's global config, not a project artifact).",def:"true",artifactAffecting:!1},{path:"codex.verifier.mode",type:"string",editor:"enum",enumValues:["sub-agent","main-agent"],description:'How the Codex verification cycle is driven (Codex-only). "sub-agent" (default) delegates to the ironbee-verifier custom agent (per-agent MCP, SubagentStart bridge, slim delegation skill/rule/command). "main-agent" makes the MAIN agent drive the devtools tools directly (session-level [mcp_servers.*], no verifier agent, inline skill/rule/command) \u2014 the Cursor-style fallback for when Codex\'s sub-agent machinery regresses. Re-renders the Codex client. Toggle via `ironbee codex verifier mode <sub-agent|main-agent>`.',def:"sub-agent",artifactAffecting:!0},{path:"telemetry.enable",type:"boolean",editor:"toggle",description:"Master switch for anonymous PostHog telemetry (CLI's own product analytics). Inverse semantics \u2014 opt out with false. Disabling also injects TELEMETRY_ENABLE=false into devtools MCP env. Orthogonal to the collector pipeline.",def:"true",artifactAffecting:!0},{path:"privacy.enable",type:"boolean",editor:"toggle",description:"Privacy mode \u2014 a single cross-cutting switch (all platforms) that redacts potentially sensitive data from what the @ironbee-ai/devtools MCP servers ship to the collector. Opt-in, default OFF. When true, injects COLLECTOR_EVENTS_TOOL_DETAILS_ENABLE=false (tool input/output detail) + COLLECTOR_ARTIFACTS_ENABLE=false (screenshots, recordings) into every devtools MCP env. Devtools-side only \u2014 the CLI's own send_event pipeline already whitelists tool_input and strips tool_response. Orthogonal to telemetry (PostHog) and collector (the sink).",def:"false",artifactAffecting:!0},{path:"otel.enable",type:"boolean",editor:"toggle",description:"Master switch for the local OTEL collector pipeline (Claude Code OTLP raw-API-body export \u2192 local daemon \u2192 session_context context-usage events). Presence opts in; enable:false opts out; auto-enabled when a collector is configured. session_context derivation is the sole consumer, so this also gates whether the settings.json OTEL env block (incl. raw-bodies) is written. Orthogonal to telemetry (PostHog) and collector (event sink).",def:"implicit true when collector configured",artifactAffecting:!0},{path:"otel.port",type:"number",editor:"number",description:"Loopback port the shared OTEL collector daemon binds to, and which the settings.json OTEL endpoint env var points at. One daemon per machine across all sessions.",def:"15986",artifactAffecting:!0},{path:"otel.idleTimeoutSeconds",type:"number",editor:"number",description:"The daemon self-reaps (graceful shutdown) after this many seconds with no /health hit and no OTLP event. Restarted on the next session/turn ensure.",def:"600",artifactAffecting:!0},{path:"otel.ensureMinIntervalSeconds",type:"number",editor:"number",description:"Throttle (seconds) for the high-frequency liveness `ensure` from per-tool hooks, so we don't pay a /health check on every tool call. session-start / activity-start ensure are unthrottled.",def:"30",artifactAffecting:!0},{path:"otel.emitMinIntervalSeconds",type:"number",editor:"number",description:"Per-session session_context emit throttle: admit at most one event per session per interval (leading-edge \u2014 the first request in each window is emitted, in-between requests are coalesced away and their body files dropped). Applies to the live path only; the catch-up/reprocess path is never throttled. 0 = emit on every API request (full context-growth time series).",def:"0",artifactAffecting:!0},{path:"fileChange.captureChangeset",type:"boolean",editor:"toggle",description:"When true, every file_change event carries a hunks-only unified-diff changeset string. Off by default \u2014 the default wire shape stays metadata-only (operation + line counts).",def:"false",artifactAffecting:!1},{path:"fileChange.maxChangesetBytes",type:"number",editor:"number",description:"Hard cap on the changeset string size. Diffs over the cap are truncated with a footer so the collector POST stays within typical reverse-proxy body limits.",def:"65536 (64 KB)",artifactAffecting:!1},{path:"import.concurrency",type:"number",editor:"number",description:"Default number of sessions `ironbee import` processes in parallel. Resolution: --concurrency flag > this value > built-in default. Clamped to [1, 32].",def:"4",artifactAffecting:!1},{path:"browserDevTools.env",type:"json",editor:"json",description:"Env-var overrides merged into the browser-devtools MCP server entry. Operators can override individual OTEL keys; IronBee invariants (TOOL_NAME_PREFIX, \u2026) always win last.",def:"unset (defaults + auto-OTEL when collector configured)",artifactAffecting:!0},{path:"browserDevTools.mcp",type:"json",editor:"json",description:"Full-replacement MCP config for the browser-devtools server entry. Auto-OTEL + telemetry env are still injected; IronBee env wins last.",def:"unset (use default npx -y @ironbee-ai/devtools entry)",artifactAffecting:!0},{path:"nodeDevTools.env",type:"json",editor:"json",description:"Env-var overrides merged into the node-devtools MCP server entry. Same auto-OTEL injection as browserDevTools minus the browser-only vars.",def:"unset (defaults + auto-OTEL when collector configured)",artifactAffecting:!0},{path:"nodeDevTools.mcp",type:"json",editor:"json",description:"Full-replacement MCP config for the node-devtools server entry. IronBee env wins last.",def:"unset (use default npx -y @ironbee-ai/devtools entry)",artifactAffecting:!0},{path:"backendDevTools.env",type:"json",editor:"json",description:"Env-var overrides merged into the backend-devtools MCP server entry. Same auto-OTEL injection as nodeDevTools.",def:"unset (defaults + auto-OTEL when collector configured)",artifactAffecting:!0},{path:"backendDevTools.mcp",type:"json",editor:"json",description:"Full-replacement MCP config for the backend-devtools server entry. IronBee env wins last.",def:"unset (use default npx -y @ironbee-ai/devtools entry)",artifactAffecting:!0},{path:"androidDevTools.env",type:"json",editor:"json",description:"Env-var overrides merged into the android-devtools MCP server entry. Same auto-OTEL injection as nodeDevTools.",def:"unset (defaults + auto-OTEL when collector configured)",artifactAffecting:!0},{path:"androidDevTools.mcp",type:"json",editor:"json",description:"Full-replacement MCP config for the android-devtools server entry. IronBee env wins last.",def:"unset (use default npx -y @ironbee-ai/devtools entry)",artifactAffecting:!0}];function A(e){return d.find(t=>t.path===e)}n(A,"findSchemaEntry");function k(){return[...d].sort((e,t)=>{const o=c(l(e.path)),i=c(l(t.path));return o!==i?o-i:e.path.localeCompare(t.path)})}n(k,"orderedEntries");0&&(module.exports={ARTIFACT_AFFECTING_TOP_KEYS,CONFIG_SCHEMA,GROUP_ORDER,GROUP_TITLES,findSchemaEntry,groupOf,groupRank,groupTitle,orderedEntries,topKey});
1
+ "use strict";var a=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var n=(e,t)=>a(e,"name",{value:t,configurable:!0});var b=(e,t)=>{for(var o in t)a(e,o,{get:t[o],enumerable:!0})},m=(e,t,o,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of y(t))!v.call(e,r)&&r!==o&&a(e,r,{get:()=>t[r],enumerable:!(i=g(t,r))||i.enumerable});return e};var w=e=>m(a({},"__esModule",{value:!0}),e);var _={};b(_,{ARTIFACT_AFFECTING_TOP_KEYS:()=>f,CONFIG_SCHEMA:()=>d,GROUP_ORDER:()=>s,GROUP_TITLES:()=>p,READ_LIVE_NESTED_PREFIXES:()=>h,findSchemaEntry:()=>k,groupOf:()=>c,groupRank:()=>l,groupTitle:()=>T,isArtifactAffectingPath:()=>A,orderedEntries:()=>x,topKey:()=>u});module.exports=w(_);const f=new Set(["verification","collector","browser","node","backend","android","terminal","browserDevTools","nodeDevTools","backendDevTools","androidDevTools","terminalDevTools","telemetry","privacy","statusLine","otel","codex","runtime"]),s=["general","runtime","verification","browser","node","backend","android","terminal","collector","recording","jobQueue","analytics","statusLine","claude","codex","telemetry","privacy","otel","fileChange","import","browserDevTools","nodeDevTools","backendDevTools","androidDevTools","terminalDevTools"],p={general:"General",runtime:"Runtime",verification:"Verification",browser:"Browser cycle",node:"Node cycle",backend:"Backend cycle",android:"Android cycle",terminal:"Terminal cycle",collector:"Collector",recording:"Recording",jobQueue:"Job queue",analytics:"Analytics",statusLine:"Statusline",claude:"Claude",codex:"Codex",telemetry:"Telemetry",privacy:"Privacy",otel:"OTEL collector",fileChange:"File change",import:"Import",browserDevTools:"Browser DevTools MCP",nodeDevTools:"Node DevTools MCP",backendDevTools:"Backend DevTools MCP",androidDevTools:"Android DevTools MCP",terminalDevTools:"Terminal DevTools MCP"};function u(e){const t=e.indexOf(".");return t===-1?e:e.slice(0,t)}n(u,"topKey");const h=["verification.context","verification.checks"];function A(e){for(const t of h)if(e===t||e.startsWith(t+"."))return!1;return f.has(u(e))}n(A,"isArtifactAffectingPath");function c(e){const t=e.indexOf(".");return t===-1?"general":e.slice(0,t)}n(c,"groupOf");function T(e){return p[e]??e}n(T,"groupTitle");function l(e){const t=s.indexOf(e);return t===-1?s.length:t}n(l,"groupRank");const d=[{path:"ignoredVerifyPatterns",type:"string-array",editor:"string-list",description:"Glob patterns excluded from verification, applied to every cycle (browser / node / backend). Checked first \u2014 a match here activates no cycle regardless of other patterns. Unioned on top of an always-on default set that excludes test files (**/*.spec.*, **/*.test.*, **/__tests__/**, **/__mocks__/**) \u2014 a test-only edit never activates a runtime-verification cycle.",def:"[] (plus always-on test-file defaults)",artifactAffecting:!1},{path:"maxRetries",type:"number",editor:"number",description:"Max verification retry attempts before the gate allows completion despite failures. Single global counter regardless of how many cycles ran.",def:"3",artifactAffecting:!1},{path:"runtime.location",type:"string",editor:"enum",enumValues:["external","in-project"],description:`Where per-session runtime data (the sessions/ folder \u2014 actions.jsonl, verdicts, queue, analytics) is stored. "external" (default) keeps it OUT of the project tree at ~/.ironbee/projects/<token> so a project never accumulates a growing sessions/ folder even when gitignored; "in-project" stores it under <project>/.ironbee/sessions (the legacy layout). Committed config / scenarios / VERIFICATION.md always stay in-project regardless. The IRONBEE_RUNTIME_LOCATION env var overrides this per process (used by the test suite). Artifact-affecting on Codex: the external layout adds a [sandbox_workspace_write].writable_roots grant so the agent's verdict write outside the workspace doesn't prompt. Takes effect on the next session.`,def:"external",artifactAffecting:!0},{path:"verification.enable",type:"boolean",editor:"toggle",description:"Master enforcement switch. Inverse semantics \u2014 verification is the core feature, opt out with false. When false, IronBee runs monitoring-only: no enforcement hooks, no skill/rule, no MCP servers; only session/activity/tool_call events flow to the collector.",def:"true",artifactAffecting:!0},{path:"verification.auto",type:"boolean",editor:"toggle",description:"Automatic-enforcement sub-toggle (only meaningful when verification.enable !== false). Default FALSE \u2014 assist is the default mode (the safer default): the /ironbee-verify command + MCP servers stay installed so the agent can verify manually, but nothing is enforced \u2014 no Stop gate, non-blocking (soft) PreToolUse hooks, and the skill/rule are omitted. Opt into full enforcement with true (blocking Stop gate + skill/rule installed).",def:"false",artifactAffecting:!0},{path:"verification.strict",type:"boolean",editor:"toggle",description:'Strict mode (only meaningful in enforce mode). Default false. When true the verify-gate refuses N/A verdicts \u2014 both a global status "not_applicable" and per-platform not_applicable_cycles exemptions \u2014 so the agent must produce real verification tool evidence for every active cycle. Default (false) accepts N/A: the agent can declare a change has no runtime surface (globally or per-cycle) and the gate allows it, recorded + observable. Inert in assist/monitor (no gate runs). The gate reads it live; the rerender it shares with the rest of the verification block is idempotent (the N/A guidance is mode-agnostic, so the installed artifacts don\'t change). Set via `ironbee verification strict` enable/disable, `config set`, or at install \u2014 picking enforce opens a strictness sub-choice (interactive) and the `--strict` flag sets it non-interactively.',def:"false",artifactAffecting:!0},{path:"verification.model",type:"json",editor:"json",description:`Model the delegated verifier sub-agent uses. Unset \u2192 the verifier inherits the session model (Claude verifier omits model: \u2192 inherit; Codex verifier omits agent-toml model \u2192 inherits config.toml's model). Set to PIN a specific model \u2014 e.g. verify on a cheaper/faster model than the main agent, or guarantee a model on Codex when config.toml has none. Two shapes: a string (applies to all clients, e.g. "sonnet" / "gpt-5.5") or a per-client object { claude: "sonnet", codex: "gpt-5.5" } when a project has both clients. Cursor has no verifier sub-agent \u2192 no-op there. Never resolves to a literal "inherit" on Codex (a 400). Artifact-affecting.`,def:"unset (inherit the session model)",artifactAffecting:!0},{path:"verification.context.enable",type:"boolean",editor:"toggle",description:"Master switch for path-scoped verification context. When a cycle begins, the first devtools tool call injects the .ironbee/VERIFICATION.md files on/above the changed paths (author-written area guidance) into the agent's context via the host's additionalContext channel. Advisory only (does not gate). Inverse semantics \u2014 default-on, opt out with false. Not artifact-affecting (read live).",def:"true",artifactAffecting:!1},{path:"verification.context.source",type:"string",editor:"enum",enumValues:["git","actions"],description:`Changed-path source. "git" (default) = working tree + last N commits, with an actions.jsonl fallback when not a git repo. "actions" = IronBee's own file_change events only (no git subprocess).`,def:"git",artifactAffecting:!1},{path:"verification.context.commitDepth",type:"number",editor:"number",description:'Number of recent commits included on the git source (uncommitted \u222A last N commits). 0 = uncommitted only. Ignored when source is "actions".',def:"1",artifactAffecting:!1},{path:"verification.context.maxBytes",type:"number",editor:"number",description:"Aggregate byte cap on the injected context string. When exceeded, the least-specific (root-side) docs are dropped first (leaf-first truncation priority).",def:"65536 (64 KB)",artifactAffecting:!1},{path:"verification.context.message",type:"string",editor:"text",description:"Custom instruction injected into EVERY verification cycle, independent of which files changed \u2014 so it reaches the verifier even on a manual no-change verify (where the path-scoped VERIFICATION.md injection is empty). Two forms: literal inline text, or a file:<path> reference whose contents are read (path relative to the project dir; a leading ~ expands to the home dir). Layered across global/project/local (highest layer that sets it wins). Never truncated (highest injection priority). Read live; not artifact-affecting.",def:"(unset)",artifactAffecting:!1},{path:"verification.checks",type:"json",editor:"json",description:"Deterministic project commands (lint/test/typecheck/\u2026) run as the FIRST step of the verification cycle, before any devtools verification. Array of { name, command, args?, env?, cwd?, timeoutMs?, required? }. The verifier runs them via `ironbee hook run-checks`; a required failure blocks the verify-gate (enforce). Read live; not artifact-affecting (the value).",def:"[]",artifactAffecting:!1},{path:"browser.enable",type:"boolean",editor:"toggle",description:"Explicit on/off for the browser cycle. Written false by `browser disable`, stripped by `browser enable`. When false the cycle is disabled regardless of patterns.",def:"(absent \u2192 on; browser is the only default-on cycle)",artifactAffecting:!0},{path:"browser.verifyPatterns",type:"string-array",editor:"string-list",description:"Glob patterns for files requiring browser verification. Four-state: absent \u2192 code defaults (40+ extensions); [] \u2192 hard kill; non-empty \u2192 custom patterns (replaces defaults).",def:"40+ code extensions when unset; [] hard-disables",artifactAffecting:!0},{path:"browser.additionalVerifyPatterns",type:"string-array",editor:"string-list",description:"Extra patterns appended to browser.verifyPatterns (or to code defaults when verifyPatterns is unset). Ignored when verifyPatterns is [] (hard kill wins).",def:"[]",artifactAffecting:!0},{path:"browser.alwaysRequired",type:"string-array",editor:"string-list",description:"Browser-cycle required tools (all-of). The verify-gate blocks completion until every listed bdt_* tool was used.",def:"bdt_navigation_go-to, bdt_content_take-screenshot, bdt_a11y_take-aria-snapshot, bdt_o11y_get-console-messages",artifactAffecting:!0},{path:"browser.evidencePaths",type:"json",editor:"json",description:"Alternative tool-satisfaction paths (any-of). Browser uses pure all-of, so default is empty. Each path: { name, allOf: (string | { anyOf: string[] })[] }.",def:"[]",artifactAffecting:!0},{path:"node.enable",type:"boolean",editor:"toggle",description:"Explicit on/off for the Node.js runtime debug cycle (node-devtools, ndt_* V8 inspector probes). Opt-in \u2014 written by `node enable`.",def:"(absent \u2192 off; node is opt-in)",artifactAffecting:!0},{path:"node.verifyPatterns",type:"string-array",editor:"string-list",description:"Glob patterns for the Node.js runtime debug cycle. Default-off \u2014 block absent = inert. Block present + unset \u2192 9 code defaults (server/api/routes paths).",def:"block absent \u2192 disabled; present + unset \u2192 code defaults",artifactAffecting:!0},{path:"node.additionalVerifyPatterns",type:"string-array",editor:"string-list",description:"Extra patterns appended to node.verifyPatterns (or to code defaults when unset). Ignored when verifyPatterns is [].",def:"[]",artifactAffecting:!0},{path:"node.alwaysRequired",type:"string-array",editor:"string-list",description:"Node-cycle required tools (all-of). ndt_debug_connect always; evidence paths supply the rest.",def:"[ndt_debug_connect]",artifactAffecting:!0},{path:"node.evidencePaths",type:"json",editor:"json",description:"Alternative tool paths (any-of). Default: probe path (a put-*point AND get-probe-snapshots) OR log path (get-logs).",def:"probe path + log path",artifactAffecting:!0},{path:"backend.enable",type:"boolean",editor:"toggle",description:"Explicit on/off for the runtime-agnostic backend protocol cycle (backend-devtools, bedt_* HTTP/gRPC/GraphQL/WebSocket). Opt-in \u2014 written by `backend enable`.",def:"(absent \u2192 off; backend is opt-in)",artifactAffecting:!0},{path:"backend.verifyPatterns",type:"string-array",editor:"string-list",description:"Glob patterns for the backend protocol cycle. Default-off \u2014 block absent = inert. Block present + unset \u2192 13 multi-language code defaults (ts/js/py/go/java/rb/cs/rs/kt/scala/ex/php/clj).",def:"block absent \u2192 disabled; present + unset \u2192 code defaults",artifactAffecting:!0},{path:"backend.additionalVerifyPatterns",type:"string-array",editor:"string-list",description:"Extra patterns appended to backend.verifyPatterns (or to code defaults when unset). Ignored when verifyPatterns is [].",def:"[]",artifactAffecting:!0},{path:"backend.alwaysRequired",type:"string-array",editor:"string-list",description:"Backend-cycle required tools (all-of). Empty by default \u2014 backend uses any-of evidence paths instead.",def:"[]",artifactAffecting:!0},{path:"backend.evidencePaths",type:"json",editor:"json",description:"Alternative tool paths (any-of). Default three: protocol-call (any request tool) OR log-evidence (register-source + read) OR db-evidence (db_connect + a read op).",def:"protocol-call OR log-evidence OR db-evidence",artifactAffecting:!0},{path:"android.enable",type:"boolean",editor:"toggle",description:"Explicit on/off for the Android mobile verification cycle (android-devtools, adt_* device/emulator interaction). Opt-in \u2014 written by `android enable`.",def:"(absent \u2192 off; android is opt-in)",artifactAffecting:!0},{path:"android.verifyPatterns",type:"string-array",editor:"string-list",description:"Glob patterns for the Android mobile verification cycle. Default-off \u2014 block absent = inert. Block present + unset \u2192 code defaults (Android/React Native paths).",def:"block absent \u2192 disabled; present + unset \u2192 code defaults",artifactAffecting:!0},{path:"android.additionalVerifyPatterns",type:"string-array",editor:"string-list",description:"Extra patterns appended to android.verifyPatterns (or to code defaults when unset). Ignored when verifyPatterns is [].",def:"[]",artifactAffecting:!0},{path:"android.alwaysRequired",type:"string-array",editor:"string-list",description:"Android-cycle required tools (all-of). adt_device_connect always; evidence paths supply the rest.",def:"[adt_device_connect]",artifactAffecting:!0},{path:"android.evidencePaths",type:"json",editor:"json",description:"Alternative tool paths (any-of). Default three: device-evidence (UI interaction + screenshot + UI snapshot) OR log-evidence (Logcat read/follow) OR network-evidence (adt_o11y_get-http-requests HTTP capture). The adt_o11y_*-trace-context and adt_stub_* tools are auxiliary (NOT evidence paths).",def:"device-evidence OR log-evidence OR network-evidence",artifactAffecting:!0},{path:"terminal.enable",type:"boolean",editor:"toggle",description:"Explicit on/off for the terminal interaction verification cycle (terminal-devtools, tdt_* CLI/REPL/TUI driving in a PTY). Opt-in \u2014 written by `terminal enable`.",def:"(absent \u2192 off; terminal is opt-in)",artifactAffecting:!0},{path:"terminal.verifyPatterns",type:"string-array",editor:"string-list",description:"Glob patterns for the terminal interaction verification cycle. Default-off \u2014 block absent = inert. Block present + unset \u2192 code defaults (cli/** / cmd/** / bin/** / commands/** / shell scripts).",def:"block absent \u2192 disabled; present + unset \u2192 code defaults",artifactAffecting:!0},{path:"terminal.additionalVerifyPatterns",type:"string-array",editor:"string-list",description:"Extra patterns appended to terminal.verifyPatterns (or to code defaults when unset). Ignored when verifyPatterns is [].",def:"[]",artifactAffecting:!0},{path:"terminal.alwaysRequired",type:"string-array",editor:"string-list",description:"Terminal-cycle required tools (all-of). Empty by default \u2014 terminal uses any-of evidence paths instead (the one-shot tdt_pty_run path needs no separate tdt_pty_start).",def:"[]",artifactAffecting:!0},{path:"terminal.evidencePaths",type:"json",editor:"json",description:"Alternative tool paths (any-of). Default two: run-evidence (tdt_pty_run one-shot run + output + exit code) OR interactive-evidence (tdt_pty_start + tdt_interaction_send-keys/send-text + tdt_content_capture). The tdt_sync_* / tdt_content_get-cursor / tdt_pty_resize|signal|stop|list tools are auxiliary (NOT evidence paths).",def:"run-evidence OR interactive-evidence",artifactAffecting:!0},{path:"collector.enable",type:"boolean",editor:"toggle",description:"Master switch for the IronBee Collector. Implicitly true when the section has url and at least one credential (oauthToken or apiKey); set false to suspend while keeping url/oauthToken/apiKey/batchSize around.",def:"implicit true when url + (oauthToken or apiKey) set",artifactAffecting:!0},{path:"collector.url",type:"string",editor:"text",description:"Remote collector endpoint URL (IronBee Platform). Required for the collector to be active. Events POST to {url}/v1/events.",def:"(unset \u2192 disabled)",artifactAffecting:!0},{path:"collector.oauthToken",type:"string",editor:"text",description:"Personal access token for collector auth (X-OAuth-Token header). Per-(user, account), independently revocable from the console's /access-tokens page. Minted by `ironbee login` \u2014 the primary path for interactive CLI use. Can be supplied via IRONBEE_OAUTH_TOKEN.",def:"(unset)",artifactAffecting:!0},{path:"collector.apiKey",type:"string",editor:"text",description:"Shared account API key for collector auth (X-API-Key header). Parallel first-class path alongside `oauthToken`, intended for CI / GitHub Actions / deployment tooling and other non-interactive integrations where rotating a per-engineer OAuth token is impractical. Either `oauthToken` OR `apiKey` is required for the collector to be active. Can be supplied via IRONBEE_API_KEY.",def:"(unset \u2192 disabled)",artifactAffecting:!0},{path:"collector.batchSize",type:"number",editor:"number",description:"Max events per POST from the send_event handler (the queue chunks bigger snapshots into N-sized POSTs).",def:"100",artifactAffecting:!0},{path:"collector.timeoutMs",type:"number",editor:"number",description:"Per-request HTTP timeout (ms) for batched analytics sends. Single-event interactive sends keep a fixed 3000ms cap. Clamped to [1000, 60000].",def:"10000",artifactAffecting:!0},{path:"recording.enable",type:"boolean",editor:"toggle",description:"Recording enforcement for the browser + android cycles. Presence opts in; enable:false opts out. Auto-enabled when a collector is configured. Node/backend cycles never trigger recording.",def:"implicit true when section present or collector configured",artifactAffecting:!1},{path:"jobQueue.enable",type:"boolean",editor:"toggle",description:"Master switch for the file-backed job queue. Presence opts in; enable:false opts out. Auto-enabled when a collector is configured (a collector is pointless without a queue feeding it).",def:"implicit true when section present or collector configured",artifactAffecting:!1},{path:"jobQueue.autoFlushSizeBytes",type:"number",editor:"number",description:"Size threshold (bytes) above which submit() spawns a detached worker mid-session. 0 / negative disables this check.",def:"32768 (32 KB)",artifactAffecting:!1},{path:"jobQueue.autoFlushIntervalSeconds",type:"number",editor:"number",description:"Interval threshold (seconds since the live jobs.jsonl was created) above which submit() spawns a detached worker. Complements size \u2014 whichever crosses first flushes. 0 / negative disables.",def:"60",artifactAffecting:!1},{path:"analytics.enable",type:"boolean",editor:"toggle",description:"Master switch for per-session structural analytics. Presence opts in; enable:false opts out. Auto-enabled when a collector is configured.",def:"implicit true when section present or collector configured",artifactAffecting:!1},{path:"analytics.emitOnStop",type:"boolean",editor:"toggle",description:"When true, project + emit analytics at every Stop hook. When false, only at SessionEnd.",def:"true",artifactAffecting:!1},{path:"analytics.emitOnStopMinIntervalSeconds",type:"number",editor:"number",description:"Throttle: skip Stop-hook projection if the last successful emit was within this many seconds. 0 disables the throttle (backend handles rate-limit / dedupe).",def:"0 (disabled)",artifactAffecting:!1},{path:"analytics.emitTurnEvents",type:"boolean",editor:"toggle",description:"Opt-in for per-turn session_turn_analytics wire records. High-volume secondary signal; the base session_analytics record always ships regardless.",def:"false",artifactAffecting:!1},{path:"analytics.emitStepEvents",type:"boolean",editor:"toggle",description:"Opt-in for per-step session_turn_step_analytics wire records (an order of magnitude higher volume than turn events). Independent of emitTurnEvents.",def:"false",artifactAffecting:!1},{path:"analytics.emitApiRequestEvents",type:"boolean",editor:"toggle",description:"Opt-OUT for per-API-request api_request wire records (one per assistant message, success + failure). Primary value for backend cost accounting, so ships by default.",def:"true",artifactAffecting:!1},{path:"statusLine.enable",type:"boolean",editor:"toggle",description:"Master switch for the Claude statusline integration (session_status event + statusline wrapper). Presence opts in; auto-enabled when a collector is configured. Claude-only.",def:"implicit true when section present or collector configured",artifactAffecting:!0},{path:"statusLine.renderDefault",type:"boolean",editor:"toggle",description:"When there is no upstream statusline to chain to, false keeps the statusline silent; true renders a minimal model + context-% line. No effect when the user already has a statusline.",def:"false",artifactAffecting:!0},{path:"statusLine.emitMinIntervalSeconds",type:"number",editor:"number",description:"Minimum seconds between two emitted session_status events, on top of skip-if-unchanged. Rapid changes coalesce to the latest state after the interval. 0 disables the throttle. Read live each tick.",def:"10",artifactAffecting:!0},{path:"statusLine.refreshInterval",type:"number",editor:"number",description:"Claude Code's own statusLine.refreshInterval (seconds, host min 1) \u2014 re-runs the statusline on a timer in addition to event-driven updates. Unset by default. Values < 1 treated as unset.",def:"unset",artifactAffecting:!0},{path:"claude.oauthAccess.enable",type:"boolean",editor:"toggle",description:"Whether IronBee may read the Claude Code OAuth token (macOS Keychain / ~/.claude/.credentials.json) and call OAuth-scoped Anthropic endpoints. Default-on (opt out with false or `ironbee claude oauth-access disable`). First consumer: the statusline rate-limit fallback \u2014 fetches /api/oauth/usage to fill rate_limits for plans the statusline JSON omits them for (team / enterprise). Claude-only; not artifact-affecting (read live).",def:"true",artifactAffecting:!1},{path:"claude.oauthAccess.usageTtlSeconds",type:"number",editor:"number",description:"TTL (seconds) for the statusline OAuth rate-limit fetch cache \u2014 the /api/oauth/usage call + credential read fire at most once per this interval even when the statusline ticks far more often. Default 60; 0 means every tick.",def:"60",artifactAffecting:!1},{path:"claude.autoModeAllowlist.enable",type:"boolean",editor:"toggle",description:"Whether IronBee writes the auto-mode allowlist carve-out for the verifier into .claude/settings.local.json. Claude Code 2.1.176+ ships a host-side sub-agent \"Content Integrity\" classifier (auto mode) that false-positives on IronBee's legitimate `ironbee hook submit-verdict` verdicts (the devtools calls happened earlier in the cycle, not re-shown in the handoff). When enabled (default), install adds a narrow, command-keyed autoMode.allow rule that exempts ONLY that command from the Content Integrity block ($defaults preserved \u2014 every other block rule still applies; IronBee's Stop-gate independently enforces real tool usage). Written only when verification is active (enforce/assist); inert when the host isn't in auto mode. Opt out with false \u2014 takes effect on the next `ironbee install`. Claude-only.",def:"true",artifactAffecting:!1},{path:"claude.trustWorkspace.enable",type:"boolean",editor:"toggle",description:"Whether `ironbee install` marks the installed project trusted in Claude Code's machine-global ~/.claude.json (projects[\"<dir>\"].hasTrustDialogAccepted: true) when it isn't already. Claude Code 2.1.x ignores a project's committed permissions.allow (the devtools + `Bash(ironbee *)` entries IronBee writes) until the workspace is trusted \u2014 and once onboarding has been seen the trust dialog no longer re-appears, so the entries stay silently disabled and the agent gets prompted on every devtools/ironbee call. Default-on (opt out with false). Only ever flips a missing/false flag to true; never clobbers other ~/.claude.json content. Best-effort + idempotent. Claude-only; not artifact-affecting (writes the host's global config, not a project artifact).",def:"true",artifactAffecting:!1},{path:"codex.verifier.mode",type:"string",editor:"enum",enumValues:["sub-agent","main-agent"],description:'How the Codex verification cycle is driven (Codex-only). "sub-agent" (default) delegates to the ironbee-verifier custom agent (per-agent MCP, SubagentStart bridge, slim delegation skill/rule/command). "main-agent" makes the MAIN agent drive the devtools tools directly (session-level [mcp_servers.*], no verifier agent, inline skill/rule/command) \u2014 the Cursor-style fallback for when Codex\'s sub-agent machinery regresses. Re-renders the Codex client. Toggle via `ironbee codex verifier mode <sub-agent|main-agent>`.',def:"sub-agent",artifactAffecting:!0},{path:"telemetry.enable",type:"boolean",editor:"toggle",description:"Master switch for anonymous PostHog telemetry (CLI's own product analytics). Inverse semantics \u2014 opt out with false. Disabling also injects TELEMETRY_ENABLE=false into devtools MCP env. Orthogonal to the collector pipeline.",def:"true",artifactAffecting:!0},{path:"privacy.enable",type:"boolean",editor:"toggle",description:"Privacy mode \u2014 a single cross-cutting switch (all platforms) that redacts potentially sensitive data from what the @ironbee-ai/devtools MCP servers ship to the collector. Opt-in, default OFF. When true, injects COLLECTOR_EVENTS_TOOL_DETAILS_ENABLE=false (tool input/output detail) + COLLECTOR_ARTIFACTS_ENABLE=false (screenshots, recordings) into every devtools MCP env. Devtools-side only \u2014 the CLI's own send_event pipeline already whitelists tool_input and strips tool_response. Orthogonal to telemetry (PostHog) and collector (the sink).",def:"false",artifactAffecting:!0},{path:"otel.enable",type:"boolean",editor:"toggle",description:"Master switch for the local OTEL collector pipeline (Claude Code OTLP raw-API-body export \u2192 local daemon \u2192 session_context context-usage events). Presence opts in; enable:false opts out; auto-enabled when a collector is configured. session_context derivation is the sole consumer, so this also gates whether the settings.json OTEL env block (incl. raw-bodies) is written. Orthogonal to telemetry (PostHog) and collector (event sink).",def:"implicit true when collector configured",artifactAffecting:!0},{path:"otel.port",type:"number",editor:"number",description:"Loopback port the shared OTEL collector daemon binds to, and which the settings.json OTEL endpoint env var points at. One daemon per machine across all sessions.",def:"15986",artifactAffecting:!0},{path:"otel.idleTimeoutSeconds",type:"number",editor:"number",description:"The daemon self-reaps (graceful shutdown) after this many seconds with no /health hit and no OTLP event. Restarted on the next session/turn ensure.",def:"600",artifactAffecting:!0},{path:"otel.ensureMinIntervalSeconds",type:"number",editor:"number",description:"Throttle (seconds) for the high-frequency liveness `ensure` from per-tool hooks, so we don't pay a /health check on every tool call. session-start / activity-start ensure are unthrottled.",def:"30",artifactAffecting:!0},{path:"otel.emitMinIntervalSeconds",type:"number",editor:"number",description:"Per-session session_context emit throttle: admit at most one event per session per interval (leading-edge \u2014 the first request in each window is emitted, in-between requests are coalesced away and their body files dropped). Applies to the live path only; the catch-up/reprocess path is never throttled. 0 = emit on every API request (full context-growth time series).",def:"0",artifactAffecting:!0},{path:"fileChange.captureChangeset",type:"boolean",editor:"toggle",description:"When true, every file_change event carries a hunks-only unified-diff changeset string. Off by default \u2014 the default wire shape stays metadata-only (operation + line counts).",def:"false",artifactAffecting:!1},{path:"fileChange.maxChangesetBytes",type:"number",editor:"number",description:"Hard cap on the changeset string size. Diffs over the cap are truncated with a footer so the collector POST stays within typical reverse-proxy body limits.",def:"65536 (64 KB)",artifactAffecting:!1},{path:"import.concurrency",type:"number",editor:"number",description:"Default number of sessions `ironbee import` processes in parallel. Resolution: --concurrency flag > this value > built-in default. Clamped to [1, 32].",def:"4",artifactAffecting:!1},{path:"browserDevTools.env",type:"json",editor:"json",description:"Env-var overrides merged into the browser-devtools MCP server entry. Operators can override individual OTEL keys; IronBee invariants (TOOL_NAME_PREFIX, \u2026) always win last.",def:"unset (defaults + auto-OTEL when collector configured)",artifactAffecting:!0},{path:"browserDevTools.mcp",type:"json",editor:"json",description:"Full-replacement MCP config for the browser-devtools server entry. Auto-OTEL + telemetry env are still injected; IronBee env wins last.",def:"unset (use default npx -y @ironbee-ai/devtools entry)",artifactAffecting:!0},{path:"nodeDevTools.env",type:"json",editor:"json",description:"Env-var overrides merged into the node-devtools MCP server entry. Same auto-OTEL injection as browserDevTools minus the browser-only vars.",def:"unset (defaults + auto-OTEL when collector configured)",artifactAffecting:!0},{path:"nodeDevTools.mcp",type:"json",editor:"json",description:"Full-replacement MCP config for the node-devtools server entry. IronBee env wins last.",def:"unset (use default npx -y @ironbee-ai/devtools entry)",artifactAffecting:!0},{path:"backendDevTools.env",type:"json",editor:"json",description:"Env-var overrides merged into the backend-devtools MCP server entry. Same auto-OTEL injection as nodeDevTools.",def:"unset (defaults + auto-OTEL when collector configured)",artifactAffecting:!0},{path:"backendDevTools.mcp",type:"json",editor:"json",description:"Full-replacement MCP config for the backend-devtools server entry. IronBee env wins last.",def:"unset (use default npx -y @ironbee-ai/devtools entry)",artifactAffecting:!0},{path:"androidDevTools.env",type:"json",editor:"json",description:"Env-var overrides merged into the android-devtools MCP server entry. Same auto-OTEL injection as nodeDevTools.",def:"unset (defaults + auto-OTEL when collector configured)",artifactAffecting:!0},{path:"androidDevTools.mcp",type:"json",editor:"json",description:"Full-replacement MCP config for the android-devtools server entry. IronBee env wins last.",def:"unset (use default npx -y @ironbee-ai/devtools entry)",artifactAffecting:!0},{path:"terminalDevTools.env",type:"json",editor:"json",description:"Env-var overrides merged into the terminal-devtools MCP server entry. Same auto-OTEL injection as nodeDevTools.",def:"unset (defaults + auto-OTEL when collector configured)",artifactAffecting:!0},{path:"terminalDevTools.mcp",type:"json",editor:"json",description:"Full-replacement MCP config for the terminal-devtools server entry. IronBee env wins last.",def:"unset (use default npx -y @ironbee-ai/devtools entry)",artifactAffecting:!0}];function k(e){return d.find(t=>t.path===e)}n(k,"findSchemaEntry");function x(){return[...d].sort((e,t)=>{const o=l(c(e.path)),i=l(c(t.path));return o!==i?o-i:e.path.localeCompare(t.path)})}n(x,"orderedEntries");0&&(module.exports={ARTIFACT_AFFECTING_TOP_KEYS,CONFIG_SCHEMA,GROUP_ORDER,GROUP_TITLES,READ_LIVE_NESTED_PREFIXES,findSchemaEntry,groupOf,groupRank,groupTitle,isArtifactAffectingPath,orderedEntries,topKey});
@@ -1,2 +1,2 @@
1
- "use strict";var D=Object.create;var h=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,W=Object.prototype.hasOwnProperty;var l=(e,n)=>h(e,"name",{value:n,configurable:!0});var O=(e,n)=>{for(var a in n)h(e,a,{get:n[a],enumerable:!0})},I=(e,n,a,b)=>{if(n&&typeof n=="object"||typeof n=="function")for(let f of H(n))!W.call(e,f)&&f!==a&&h(e,f,{get:()=>n[f],enumerable:!(b=Y(n,f))||b.enumerable});return e};var U=(e,n,a)=>(a=e!=null?D(q(e)):{},I(n||!e||!e.__esModule?h(a,"default",{value:e,enumerable:!0}):a,e)),z=e=>I(h({},"__esModule",{value:!0}),e);var Q={};O(Q,{platformsArea:()=>M});module.exports=z(Q);var j=U(require("blessed")),g=require("../../lib/config"),y=require("../config/introspect"),A=require("../config/value"),d=require("../shell/util"),L=require("../config/edit");const V={browser:"Browser",node:"Node",backend:"Backend",android:"Android"},F=" {bold}\u2191/\u2193{/bold} move {bold}e{/bold}/{bold}g{/bold}/{bold}l{/bold} toggle project/global/local {bold}x{/bold} clear enable flag {bold}Esc{/bold} back {bold}q{/bold} quit",G={global:"global ",project:"project",local:"local "};function J(e){const n=e.session.projectDir,a=g.ALL_CYCLES;let b=(0,y.loadLayers)(n),f=(0,g.loadConfig)(n),v=0;const i=j.list({parent:e.container,top:0,left:0,width:"40%",height:"100%",border:{type:"line"},label:" Cycles ",tags:!0,keys:!1,mouse:!1,style:{selected:{bg:"blue",fg:"white"},border:{fg:"cyan"}},items:[]}),C=j.box({parent:e.container,top:0,left:"40%",width:"60%",height:"100%",border:{type:"line"},label:" Detail ",tags:!0,scrollable:!0,alwaysScroll:!0,scrollbar:{ch:" "},style:{border:{fg:"cyan"}},content:""});function $(){return a[(0,d.clamp)(v,0,a.length-1)]}l($,"currentCycle");function E(r){return(0,g.isCycleEnabled)(f,r)}l(E,"enabled");function N(r){const t=E(r),s=t?"{green-fg}\u25CF{/green-fg}":"{gray-fg}\u25CB{/gray-fg}",c=t?"{green-fg}enabled{/green-fg}":"{gray-fg}disabled{/gray-fg}";return`${s} {bold}${V[r]??r}{/bold} ${c}`}l(N,"rowLabel");function P(r){const t=[],s=E(r),c=V[r]??r,o=g.CYCLE_TO_SERVER[r]??"";t.push(`{bold}{cyan-fg}${(0,d.escapeTags)(c)} cycle{/cyan-fg}{/bold} {gray-fg}${(0,d.escapeTags)(o)}{/gray-fg}`),t.push("{gray-fg}"+"\u2500".repeat(46)+"{/gray-fg}"),t.push(`Effective: ${s?"{green-fg}enabled{/green-fg}":"{gray-fg}disabled{/gray-fg}"}`),t.push("");const m=(0,y.introspectKey)(`${r}.enable`,b);t.push("{bold}enable flag by layer{/bold}");for(const p of m.layers){const K=p.present?(0,d.escapeTags)((0,A.formatValueShort)(p.value,20)):"{gray-fg}(unset){/gray-fg}",_=m.effective===p.layer?" {green-fg}\u2190 effective{/green-fg}":"";t.push(` ${G[p.layer]} ${K}${_}`)}if(m.effective==="none"){const p=r==="browser"?"on (browser is default-on)":"off (opt-in cycle)";t.push(` {gray-fg}(no enable flag set \u2014 default: ${p}){/gray-fg}`)}t.push("");const u=(0,y.introspectKey)(`${r}.verifyPatterns`,b);t.push("{bold}verifyPatterns (config){/bold}");const B=u.merged===void 0?"{gray-fg}(unset \u2192 code defaults apply when enabled){/gray-fg}":(0,d.escapeTags)((0,A.formatValueShort)(u.merged,60));return t.push(` ${B}`),t.push(" {gray-fg}edit patterns in the Configuration area{/gray-fg}"),t.push(""),t.push("{gray-fg}e/g/l toggles the enable flag in project/global/local; x clears it.{/gray-fg}"),t.join(`
2
- `)}l(P,"buildDetail");function k(){i.setItems(a.map(r=>N(r))),i.select((0,d.clamp)(v,0,a.length-1)),C.setContent(P($())),C.setScroll(0),e.screen.render()}l(k,"render");function T(){b=(0,y.loadLayers)(n),f=(0,g.loadConfig)(n),k()}l(T,"reload");function S(r){v=(0,d.clamp)(v+r,0,a.length-1),k()}l(S,"move");function w(r){const t=$(),s=!E(t),c=(0,g.getTargetConfigPath)(r,n);try{(0,L.setLayerValue)(c,`${t}.enable`,s?"true":"false",!1),e.session.markRerenderNeeded(n),T()}catch(o){e.session.message(`Toggle failed: ${o instanceof Error?o.message:String(o)}`)}}l(w,"toggleEnable");function R(){const r=$(),s=(0,y.introspectKey)(`${r}.enable`,b).layers.filter(o=>o.present);if(s.length===0){e.session.message(`${r}.enable is not set in any layer.`);return}const c=l(o=>{const m=(0,g.getTargetConfigPath)(o,n);try{(0,L.unsetLayerValue)(m,`${r}.enable`),e.session.markRerenderNeeded(n),T()}catch(u){e.session.message(`Clear failed: ${u instanceof Error?u.message:String(u)}`)}},"apply");if(s.length===1){c(s[0].layer);return}e.session.pick("Clear enable flag from which layer?",s.map(o=>o.layer),o=>{o>=0&&o<s.length&&c(s[o].layer)})}return l(R,"clearEnable"),i.key(["up","k"],()=>S(-1)),i.key(["down","j"],()=>S(1)),i.key(["e"],()=>w("project")),i.key(["g"],()=>w("global")),i.key(["l"],()=>w("local")),i.key(["x","d"],()=>R()),e.setStatus(F),k(),i.focus(),e.screen.render(),{unmount(){i.destroy(),C.destroy()}}}l(J,"mountPlatformsView");const M={id:"platforms",title:"Platforms",summary:"Enable / disable the browser \xB7 node \xB7 backend \xB7 android cycles per layer",mount(e){return J(e)}};0&&(module.exports={platformsArea});
1
+ "use strict";var F=Object.create;var C=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var Z=Object.getPrototypeOf,x=Object.prototype.hasOwnProperty;var l=(e,r)=>C(e,"name",{value:r,configurable:!0});var ee=(e,r)=>{for(var s in r)C(e,s,{get:r[s],enumerable:!0})},_=(e,r,s,u)=>{if(r&&typeof r=="object"||typeof r=="function")for(let c of X(r))!x.call(e,c)&&c!==s&&C(e,c,{get:()=>r[c],enumerable:!(u=Q(r,c))||u.enumerable});return e};var re=(e,r,s)=>(s=e!=null?F(Z(e)):{},_(r||!e||!e.__esModule?C(s,"default",{value:e,enumerable:!0}):s,e)),ne=e=>_(C({},"__esModule",{value:!0}),e);var ae={};ee(ae,{platformsArea:()=>se});module.exports=ne(ae);var B=re(require("blessed")),g=require("../../lib/config"),y=require("../config/introspect"),P=require("../config/value"),f=require("../shell/util"),w=require("../config/edit"),S=require("../../clients/registry"),Y=require("../../commands/platform-suggest"),H=require("../../commands/cycle-toggle"),M=require("../../commands/install");const K={browser:"Browser",node:"Node",backend:"Backend",android:"Android",terminal:"Terminal"},D=" {bold}\u2191/\u2193{/bold} move {bold}e{/bold}/{bold}g{/bold}/{bold}l{/bold} toggle project/global/local {bold}x{/bold} clear enable flag {bold}Esc{/bold} back {bold}q{/bold} quit",te={global:"global ",project:"project",local:"local "};function oe(e){const r=e.session.projectDir,s=g.ALL_CYCLES;let u=(0,y.loadLayers)(r),c=(0,g.loadConfig)(r),L=0;const b=(0,S.resolveSuggestionClient)((0,S.detectClients)(r)),R=b?D+` {bold}s{/bold} suggest (${(0,f.escapeTags)(b.name)})`:D;let m=!1,E=!1,$=null;const d=B.list({parent:e.container,top:0,left:0,width:"40%",height:"100%",border:{type:"line"},label:" Cycles ",tags:!0,keys:!1,mouse:!1,style:{selected:{bg:"blue",fg:"white"},border:{fg:"cyan"}},items:[]}),k=B.box({parent:e.container,top:0,left:"40%",width:"60%",height:"100%",border:{type:"line"},label:" Detail ",tags:!0,scrollable:!0,alwaysScroll:!0,scrollbar:{ch:" "},style:{border:{fg:"cyan"}},content:""});function A(){return s[(0,f.clamp)(L,0,s.length-1)]}l(A,"currentCycle");function T(n){return(0,g.isCycleEnabled)(c,n)}l(T,"enabled");function O(n){const t=T(n),a=t?"{green-fg}\u25CF{/green-fg}":"{gray-fg}\u25CB{/gray-fg}",i=t?"{green-fg}enabled{/green-fg}":"{gray-fg}disabled{/gray-fg}";return`${a} {bold}${K[n]??n}{/bold} ${i}`}l(O,"rowLabel");function U(n){const t=[],a=T(n),i=K[n]??n,o=g.CYCLE_TO_SERVER[n]??"";t.push(`{bold}{cyan-fg}${(0,f.escapeTags)(i)} cycle{/cyan-fg}{/bold} {gray-fg}${(0,f.escapeTags)(o)}{/gray-fg}`),t.push("{gray-fg}"+"\u2500".repeat(46)+"{/gray-fg}"),t.push(`Effective: ${a?"{green-fg}enabled{/green-fg}":"{gray-fg}disabled{/gray-fg}"}`),t.push("");const v=(0,y.introspectKey)(`${n}.enable`,u);t.push("{bold}enable flag by layer{/bold}");for(const h of v.layers){const J=h.present?(0,f.escapeTags)((0,P.formatValueShort)(h.value,20)):"{gray-fg}(unset){/gray-fg}",z=v.effective===h.layer?" {green-fg}\u2190 effective{/green-fg}":"";t.push(` ${te[h.layer]} ${J}${z}`)}if(v.effective==="none"){const h=n==="browser"?"on (browser is default-on)":"off (opt-in cycle)";t.push(` {gray-fg}(no enable flag set \u2014 default: ${h}){/gray-fg}`)}t.push("");const p=(0,y.introspectKey)(`${n}.verifyPatterns`,u);t.push("{bold}verifyPatterns (config){/bold}");const W=p.merged===void 0?"{gray-fg}(unset \u2192 code defaults apply when enabled){/gray-fg}":(0,f.escapeTags)((0,P.formatValueShort)(p.merged,60));return t.push(` ${W}`),t.push(" {gray-fg}edit patterns in the Configuration area{/gray-fg}"),t.push(""),t.push("{gray-fg}e/g/l toggles the enable flag in project/global/local; x clears it.{/gray-fg}"),t.join(`
2
+ `)}l(U,"buildDetail");function I(){d.setItems(s.map(n=>O(n))),d.select((0,f.clamp)(L,0,s.length-1)),k.setContent(U(A())),k.setScroll(0),e.screen.render()}l(I,"render");function j(){u=(0,y.loadLayers)(r),c=(0,g.loadConfig)(r),I()}l(j,"reload");function V(n){m||(L=(0,f.clamp)(L+n,0,s.length-1),I())}l(V,"move");function N(n){if(m)return;const t=A(),a=!T(t),i=(0,g.getTargetConfigPath)(n,r);try{(0,w.setLayerValue)(i,`${t}.enable`,a?"true":"false",!1),e.session.markRerenderNeeded(r),j()}catch(o){e.session.message(`Toggle failed: ${o instanceof Error?o.message:String(o)}`)}}l(N,"toggleEnable");function q(){if(m)return;const n=A(),a=(0,y.introspectKey)(`${n}.enable`,u).layers.filter(o=>o.present);if(a.length===0){e.session.message(`${n}.enable is not set in any layer.`);return}const i=l(o=>{const v=(0,g.getTargetConfigPath)(o,r);try{(0,w.unsetLayerValue)(v,`${n}.enable`),e.session.markRerenderNeeded(r),j()}catch(p){e.session.message(`Clear failed: ${p instanceof Error?p.message:String(p)}`)}},"apply");if(a.length===1){i(a[0].layer);return}e.session.pick("Clear enable flag from which layer?",a.map(o=>o.layer),o=>{o>=0&&o<a.length&&i(a[o].layer)})}l(q,"clearEnable");function G(){if(m||!b)return;m=!0,$=new AbortController,e.setStatus(`{cyan-fg}Analysing project with ${(0,f.escapeTags)(b.name)}... please wait{/cyan-fg}`),e.screen.render();const n=l(()=>{m=!1,$=null,E||(e.setStatus(R),e.screen.render())},"done");(0,Y.suggestPlatforms)(b,{projectDir:r,timeoutMs:M.SUGGEST_TIMEOUT_MS,signal:$.signal}).then(t=>{if(n(),!E){if(t===null||t.length===0){e.session.message("Couldn't analyse the project \u2014 no changes made.");return}e.session.confirm(`Apply suggested platforms to the PROJECT config: ${t.join(", ")}? (other cycles will be disabled)`,a=>{if(!(!a||E))try{(0,H.reconcileCyclesInLayer)(r,"project",t,!0),e.session.markRerenderNeeded(r),j()}catch(i){e.session.message(`Apply failed: ${i instanceof Error?i.message:String(i)}`)}})}},()=>n())}return l(G,"runSuggest"),d.key(["up","k"],()=>V(-1)),d.key(["down","j"],()=>V(1)),d.key(["e"],()=>N("project")),d.key(["g"],()=>N("global")),d.key(["l"],()=>N("local")),d.key(["x","d"],()=>q()),b&&d.key(["s"],()=>G()),e.setStatus(R),I(),d.focus(),e.screen.render(),{unmount(){E=!0,$?.abort(),d.destroy(),k.destroy()}}}l(oe,"mountPlatformsView");const se={id:"platforms",title:"Platforms",summary:"Enable / disable the browser \xB7 node \xB7 backend \xB7 android \xB7 terminal cycles per layer",mount(e){return oe(e)}};0&&(module.exports={platformsArea});
@@ -1,4 +1,4 @@
1
- "use strict";var me=Object.create;var P=Object.defineProperty;var ve=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames;var je=Object.getPrototypeOf,$e=Object.prototype.hasOwnProperty;var r=(n,o)=>P(n,"name",{value:o,configurable:!0});var Ce=(n,o)=>{for(var b in o)P(n,b,{get:o[b],enumerable:!0})},X=(n,o,b,y)=>{if(o&&typeof o=="object"||typeof o=="function")for(let a of we(o))!$e.call(n,a)&&a!==b&&P(n,a,{get:()=>o[a],enumerable:!(y=ve(o,a))||y.enumerable});return n};var Ee=(n,o,b)=>(b=n!=null?me(je(n)):{},X(o||!n||!n.__esModule?P(b,"default",{value:n,enumerable:!0}):b,n)),Ie=n=>X(P({},"__esModule",{value:!0}),n);var Ae={};Ce(Ae,{projectsArea:()=>Se});module.exports=Ie(Ae);var H=Ee(require("blessed")),U=require("fs"),J=require("path"),m=require("../../clients/registry"),R=require("../../commands/install"),K=require("../../commands/cycle-toggle"),f=require("../../commands/mode-select"),Z=require("../../commands/uninstall"),j=require("../../lib/config"),v=require("../../lib/projects-registry"),c=require("../shell/util");const L=6;function u(n){const o=n.replace(/[/\\]+$/,"").split(/[/\\]/);return o[o.length-1]||n}r(u,"basename");function ke(n){const o=n.session.launchDir;function b(e){try{return(0,v.canonicalizePath)(e)}catch{return e}}r(b,"safeCanonical");const y=b(o);let a=(0,v.listProjects)(),E=Math.max(0,a.findIndex(e=>e.path===y)),W=b(n.session.projectDir),h="cwd";const M=H.box({parent:n.container,top:0,left:0,width:"100%",height:L,border:{type:"line"},label:" Current directory ",tags:!0,style:{border:{fg:"yellow"}},content:""}),g=H.list({parent:n.container,top:L,left:0,width:"52%",height:`100%-${L}`,border:{type:"line"},label:" Registered projects ",tags:!0,keys:!1,mouse:!1,invertSelected:!1,scrollbar:{ch:" "},style:{selected:{bg:"blue"},border:{fg:"cyan"}},items:[]}),T=H.box({parent:n.container,top:L,left:"52%",width:"48%",height:`100%-${L}`,border:{type:"line"},label:" Detail ",tags:!0,scrollable:!0,alwaysScroll:!0,scrollbar:{ch:" "},style:{border:{fg:"cyan"}},content:""});function A(){return a.length===0?void 0:a[(0,c.clamp)(E,0,a.length-1)]}r(A,"selected");function k(e){return(0,m.detectClients)(e).map(t=>t.name).join(", ")}r(k,"detectedNames");function D(e){return e===W||b(e)===W}r(D,"isActive");function x(e){const s=(0,m.isProjectActive)(e)?"{green-fg}\u25CF{/green-fg}":"{red-fg}\u25CB{/red-fg}";return`${D(e.path)?"{yellow-fg}\u2605{/yellow-fg} ":" "}${s} ${(0,c.escapeTags)(u(e.path))} {gray-fg}${(0,c.escapeTags)(k(e.path))}{/gray-fg}`}r(x,"rowLabel");function _(){return{installed:k(o),registered:a.some(e=>e.path===y),active:D(y)}}r(_,"cwdState");function $(e,t){return t?`{bold}${e}{/bold}`:`{gray-fg}${e}{/gray-fg}`}r($,"keyLabel");function ee(){const{installed:e,registered:t,active:s}=_(),i=e.length>0,d=[];d.push(i?`{green-fg}\u25CF installed{/green-fg} {gray-fg}(${(0,c.escapeTags)(e)}){/gray-fg}`:"{gray-fg}\u25CB not installed{/gray-fg}"),d.push(t?"{green-fg}registered{/green-fg}":"{gray-fg}not registered{/gray-fg}"),d.push(s?"{yellow-fg}\u2605 active project{/yellow-fg}":"{gray-fg}not the active project{/gray-fg}");const p=`${$("i install",!i)} ${$("x uninstall",i)} {gray-fg}\xB7{/gray-fg} ${$("a register",!t)} ${$("d unregister",t)} {gray-fg}\xB7{/gray-fg} ${$("c make active",!s)}`,l=[];return l.push(`{bold}${(0,c.escapeTags)(o)}{/bold}`),l.push(d.join(" {gray-fg}\xB7{/gray-fg} ")),l.push(p),l.join(`
2
- `)}r(ee,"buildCwdPanel");function ne(){const e="{bold}Tab{/bold} switch section {bold}I/X{/bold} all {bold}r{/bold} refresh {bold}Esc/q{/bold}";let t;if(h==="cwd"){const{installed:s,registered:i}=_(),d=s.length>0;t=`{cyan-fg}cwd:{/cyan-fg} ${$("i install",!d)} ${$("x uninstall",d)} ${$("a register",!i)} ${$("d unregister",i)} {bold}c{/bold} make active`}else t="{bold}\u2191/\u2193{/bold} move {bold}Enter{/bold} switch {bold}i{/bold} install {bold}x{/bold} uninstall {bold}d{/bold} unregister";return` ${t} {gray-fg}\u2502{/gray-fg} ${e}`}r(ne,"buildStatus");function te(e){if(e===void 0){const d=k(o).length>0,p=[];return p.push("{gray-fg}No projects registered yet.{/gray-fg}"),p.push(""),p.push("{gray-fg}Use the {/gray-fg}{bold}Current directory{/bold}{gray-fg} panel above:{/gray-fg}"),p.push(d?"{bold}x{/bold} {gray-fg}\u2014 uninstall IronBee from here (removes hooks + guidance){/gray-fg}":"{bold}i{/bold} {gray-fg}\u2014 install IronBee here (writes hooks + guidance, registers it){/gray-fg}"),p.push("{bold}a{/bold} {gray-fg}\u2014 register here only (inventory, no artifact writes){/gray-fg}"),p.join(`
3
- `)}const t=(0,m.isProjectActive)(e),s=(0,j.getConfigLayerPaths)(e.path),i=[];return i.push(`{bold}${(0,c.escapeTags)(u(e.path))}{/bold}`),i.push("{gray-fg}"+"\u2500".repeat(46)+"{/gray-fg}"),i.push(`{gray-fg}path:{/gray-fg} ${(0,c.escapeTags)(e.path)}`),i.push(`{gray-fg}detected:{/gray-fg} ${(0,c.escapeTags)(k(e.path))||"(none on disk)"}`),i.push(`{gray-fg}added:{/gray-fg} ${(0,c.escapeTags)(e.installedAt)}`),i.push(`{gray-fg}on disk:{/gray-fg} ${t?"{green-fg}detected{/green-fg}":"{red-fg}stale (artifacts not detected){/red-fg}"}`),i.push(""),i.push("{bold}config layers{/bold}"),i.push(` {gray-fg}global {/gray-fg} ${(0,c.escapeTags)(s.global)}`),i.push(` {gray-fg}project{/gray-fg} ${(0,c.escapeTags)(s.project??"-")}`),i.push(` {gray-fg}local {/gray-fg} ${(0,c.escapeTags)(s.local??"-")}`),i.push(""),D(e.path)?(i.push("{yellow-fg}\u2605 active project{/yellow-fg} \u2014 Config / Sessions / Queue target this."),i.push("{gray-fg}c (in the cwd panel) = unselect \u2192 back to the current directory{/gray-fg}")):i.push("{gray-fg}Enter/s = make active (Config / Sessions / Queue switch to it){/gray-fg}"),i.push("{gray-fg}i = install \xB7 x = uninstall (pick a client when >1 registered; runs here, blocking){/gray-fg}"),i.join(`
4
- `)}r(te,"buildDetail");function V(e,t){const s=e.style;s.border!==void 0&&(s.border.fg=t)}r(V,"setBorderFg");function ie(){const e=h==="cwd";M.setLabel(e?" {yellow-fg}\u25B8 Current directory{/yellow-fg} ":" Current directory "),g.setLabel(e?" Registered projects ":" {yellow-fg}\u25B8 Registered projects{/yellow-fg} "),V(M,e?"yellow":"gray"),V(g,e?"gray":"yellow"),V(T,e?"gray":"cyan");const t=g.style.selected??{};t.bg=e?void 0:"blue",t.fg=void 0}r(ie,"applyFocusStyles");function S(){W=b(n.session.projectDir),n.setStatus(ne()),ie(),M.setContent(ee()),a.length===0?g.setItems(["{gray-fg}(no registered projects){/gray-fg}"]):(g.setItems(a.map(e=>x(e))),g.select((0,c.clamp)(E,0,a.length-1))),T.setContent(te(A())),T.setScroll(0),n.screen.render()}r(S,"render");function O(){h=h==="cwd"?"list":"cwd",S()}r(O,"toggleSection");function I(e){if(a=(0,v.listProjects)(),e!==void 0){const t=a.findIndex(s=>s.path===e);t>=0&&(E=t)}E=(0,c.clamp)(E,0,Math.max(0,a.length-1)),S()}r(I,"refresh");function N(e){a.length!==0&&(E=(0,c.clamp)(E+e,0,a.length-1),S())}r(N,"move");function re(){try{(0,v.upsertProject)(o),I(y),n.session.message(`Registered ${u(o)} in the inventory. Use d to unregister, i to install.`)}catch(e){n.session.message(`Register failed: ${e instanceof Error?e.message:String(e)}`)}}r(re,"registerCwd");function oe(){n.session.confirm(`Unregister ${u(o)}? (inventory only, no files touched)`,e=>{if(e)try{(0,v.removeProject)(o),I()}catch(t){n.session.message(`Unregister failed: ${t instanceof Error?t.message:String(t)}`)}})}r(oe,"unregisterCwd");function se(){if(a.some(e=>e.path===y)){n.session.message(`${u(o)} is already registered \u2014 press d to unregister.`);return}re()}r(se,"cwdRegister");function le(){if(!a.some(e=>e.path===y)){n.session.message(`${u(o)} is not registered \u2014 nothing to unregister.`);return}oe()}r(le,"cwdUnregister");function F(){if(D(y)){n.session.message(`The current directory (${u(o)}) is already the active project.`);return}n.setActiveProject(y);const e=a.findIndex(t=>t.path===y);e>=0&&(E=e),S(),n.session.message(`Active project \u2192 current directory (${u(o)}). Any switched project is unselected.`)}r(F,"setActiveToCwd");function ae(e,t){const s=n.session.silently(()=>(0,f.resolveInstallDefaultMode)(e)),i=[s,...f.ALL_MODES.filter(w=>w!==s)],d=i.map(w=>`${f.MODE_LABELS[w]} \u2014 ${f.MODE_HINTS[w]}`),l=n.session.silently(()=>(0,f.resolveInstallDefaultStrict)(e))?[!0,!1]:[!1,!0],C=l.map(w=>`${f.STRICT_LABELS[w?"true":"false"]} \u2014 ${f.STRICT_HINTS[w?"true":"false"]}`),Y=r(()=>{n.session.pick("Which verification mode?",d,w=>{if(w<0){t("cancel");return}const B=i[w];if(B!=="enforce"){t(B);return}n.session.pick("How strict should verification be? ({cyan-fg}Esc{/cyan-fg} = back)",C,z=>{if(z<0){Y();return}t(B,l[z])})})},"askMode");Y()}r(ae,"chooseMode");function ge(e,t,s){if(t==="monitor"){s(void 0);return}const i=n.session.silently(()=>(0,j.loadConfig)(e)),d=j.ALL_CYCLES.map(l=>`${l} \u2014 ${R.CYCLE_HINTS[l]}`),p=j.ALL_CYCLES.map((l,C)=>(0,j.isCyclePatternsActive)(i,l)?C:-1).filter(l=>l>=0);n.session.pickMulti("Which platforms should require verification?",d,p,l=>{if(l===null){s("cancel");return}s(l.map(C=>j.ALL_CYCLES[C]))})}r(ge,"choosePlatforms");function Q(e,t,s){G(t,i=>{ae(e,(d,p)=>{d!=="cancel"&&ge(e,d,l=>{l!=="cancel"&&n.session.runWithOutput(`Install ${u(e)} (${i.map(C=>C.name).join(", ")})`,()=>{(0,f.applyModeToLayer)(e,"project",d,p),l!==void 0&&(0,K.reconcileCyclesInLayer)(e,"project",l,!0);for(const C of i)C.install(e);(0,v.upsertProject)(e)}).then(()=>I(s))})})})}r(Q,"doInstall");function q(e,t){G("Uninstall which client?",s=>{n.session.confirm(`Uninstall ${s.map(i=>i.name).join(", ")} from ${u(e)}?`,i=>{i&&n.session.runWithOutput(`Uninstall ${u(e)} (${s.map(d=>d.name).join(", ")})`,()=>{const d=new Set(s.map(l=>l.name));for(const l of s)l.uninstall(e);if(!m.REGISTERED_CLIENTS.some(l=>!d.has(l.name)&&l.detect(e))){const l=(0,J.join)(e,".ironbee");(0,U.existsSync)(l)&&(0,U.rmSync)(l,{recursive:!0,force:!0}),(0,v.removeProject)(e)}}).then(()=>I(t))})})}r(q,"doUninstall");function de(){if(k(o).length>0){n.session.message(`${u(o)} is already installed \u2014 press x to uninstall.`);return}Q(o,"Install into the current directory \u2014 which client?",y)}r(de,"cwdInstall");function ce(){if(k(o).length===0){n.session.message(`${u(o)} is not installed \u2014 nothing to uninstall.`);return}q(o,y)}r(ce,"cwdUninstall");function fe(){const e=A();e!==void 0&&(n.setActiveProject(e.path),S(),n.session.message(`Active project \u2192 ${u(e.path)}. Config / Sessions / Queue now target it.`))}r(fe,"switchTo");function ue(){const e=A();e!==void 0&&n.session.confirm(`Unregister ${u(e.path)}? (inventory only, no files touched)`,t=>{if(t)try{(0,v.removeProject)(e.path),I()}catch(s){n.session.message(`Unregister failed: ${s instanceof Error?s.message:String(s)}`)}})}r(ue,"unregisterSelected");function G(e,t){if(m.REGISTERED_CLIENTS.length<=1){t(m.REGISTERED_CLIENTS);return}const s=m.REGISTERED_CLIENTS.map(i=>i.name);n.session.pick(e,["All clients",...s],i=>{i<0||t(i===0?m.REGISTERED_CLIENTS:[m.REGISTERED_CLIENTS[i-1]])})}r(G,"pickClient");function ye(){const e=A();e!==void 0&&Q(e.path,"Install which client?")}r(ye,"installSelected");function pe(){const e=A();e!==void 0&&q(e.path)}r(pe,"uninstallSelected");async function be(){await n.session.runWithOutput("Install \u2014 all registered projects",async()=>{await(0,R.runInstallAll)({})}),I()}r(be,"installAll");function he(){n.session.confirm("Uninstall IronBee from ALL registered projects? (destructive)",e=>{e&&n.session.runWithOutput("Uninstall \u2014 all registered projects",async()=>{await(0,Z.runUninstallAll)({yes:!0})}).then(()=>I())})}return r(he,"uninstallAllFlow"),g.key(["tab"],()=>O()),g.key(["S-tab"],()=>O()),g.key(["up","k"],()=>{h==="list"&&N(-1)}),g.key(["down","j"],()=>{h==="list"&&N(1)}),g.key(["i"],()=>{h==="cwd"?de():ye()}),g.key(["x"],()=>{h==="cwd"?ce():pe()}),g.key(["d"],()=>{h==="cwd"?le():ue()}),g.key(["a"],()=>{h==="cwd"&&se()}),g.key(["c"],()=>{h==="cwd"&&F()}),g.key(["enter","s"],()=>{h==="list"?fe():F()}),g.key(["S-i"],()=>{be()}),g.key(["S-x"],()=>he()),g.key(["r"],()=>I()),S(),g.focus(),n.screen.render(),{unmount(){M.destroy(),g.destroy(),T.destroy()}}}r(ke,"mountProjectsView");const Se={id:"projects",title:"Projects",summary:"Registry \u2014 switch active \xB7 register / unregister \xB7 install / uninstall (+ --all)",mount(n){return ke(n)}};0&&(module.exports={projectsArea});
1
+ "use strict";var ve=Object.create;var T=Object.defineProperty;var we=Object.getOwnPropertyDescriptor;var je=Object.getOwnPropertyNames;var $e=Object.getPrototypeOf,Ce=Object.prototype.hasOwnProperty;var r=(n,o)=>T(n,"name",{value:o,configurable:!0});var Se=(n,o)=>{for(var h in o)T(n,h,{get:o[h],enumerable:!0})},X=(n,o,h,p)=>{if(o&&typeof o=="object"||typeof o=="function")for(let a of je(o))!Ce.call(n,a)&&a!==h&&T(n,a,{get:()=>o[a],enumerable:!(p=we(o,a))||p.enumerable});return n};var Ee=(n,o,h)=>(h=n!=null?ve($e(n)):{},X(o||!n||!n.__esModule?T(h,"default",{value:n,enumerable:!0}):h,n)),Ie=n=>X(T({},"__esModule",{value:!0}),n);var Pe={};Se(Pe,{projectsArea:()=>Ae});module.exports=Ie(Pe);var H=Ee(require("blessed")),O=require("fs"),J=require("path"),m=require("../../clients/registry"),L=require("../../commands/install"),K=require("../../commands/platform-suggest"),Z=require("../../commands/cycle-toggle"),u=require("../../commands/mode-select"),x=require("../../commands/uninstall"),j=require("../../lib/config"),w=require("../../lib/projects-registry"),f=require("../shell/util");const D=6;function y(n){const o=n.replace(/[/\\]+$/,"").split(/[/\\]/);return o[o.length-1]||n}r(y,"basename");function ke(n){const o=n.session.launchDir;function h(e){try{return(0,w.canonicalizePath)(e)}catch{return e}}r(h,"safeCanonical");const p=h(o);let a=(0,w.listProjects)(),E=Math.max(0,a.findIndex(e=>e.path===p)),V=h(n.session.projectDir),v="cwd";const U=H.box({parent:n.container,top:0,left:0,width:"100%",height:D,border:{type:"line"},label:" Current directory ",tags:!0,style:{border:{fg:"yellow"}},content:""}),d=H.list({parent:n.container,top:D,left:0,width:"52%",height:`100%-${D}`,border:{type:"line"},label:" Registered projects ",tags:!0,keys:!1,mouse:!1,invertSelected:!1,scrollbar:{ch:" "},style:{selected:{bg:"blue"},border:{fg:"cyan"}},items:[]}),R=H.box({parent:n.container,top:D,left:"52%",width:"48%",height:`100%-${D}`,border:{type:"line"},label:" Detail ",tags:!0,scrollable:!0,alwaysScroll:!0,scrollbar:{ch:" "},style:{border:{fg:"cyan"}},content:""});function M(){return a.length===0?void 0:a[(0,f.clamp)(E,0,a.length-1)]}r(M,"selected");function k(e){return(0,m.detectClients)(e).map(i=>i.name).join(", ")}r(k,"detectedNames");function W(e){return e===V||h(e)===V}r(W,"isActive");function ee(e){const s=(0,m.isProjectActive)(e)?"{green-fg}\u25CF{/green-fg}":"{red-fg}\u25CB{/red-fg}";return`${W(e.path)?"{yellow-fg}\u2605{/yellow-fg} ":" "}${s} ${(0,f.escapeTags)(y(e.path))} {gray-fg}${(0,f.escapeTags)(k(e.path))}{/gray-fg}`}r(ee,"rowLabel");function N(){return{installed:k(o),registered:a.some(e=>e.path===p),active:W(p)}}r(N,"cwdState");function C(e,i){return i?`{bold}${e}{/bold}`:`{gray-fg}${e}{/gray-fg}`}r(C,"keyLabel");function ne(){const{installed:e,registered:i,active:s}=N(),t=e.length>0,c=[];c.push(t?`{green-fg}\u25CF installed{/green-fg} {gray-fg}(${(0,f.escapeTags)(e)}){/gray-fg}`:"{gray-fg}\u25CB not installed{/gray-fg}"),c.push(i?"{green-fg}registered{/green-fg}":"{gray-fg}not registered{/gray-fg}"),c.push(s?"{yellow-fg}\u2605 active project{/yellow-fg}":"{gray-fg}not the active project{/gray-fg}");const b=`${C("i install",!t)} ${C("x uninstall",t)} {gray-fg}\xB7{/gray-fg} ${C("a register",!i)} ${C("d unregister",i)} {gray-fg}\xB7{/gray-fg} ${C("c make active",!s)}`,l=[];return l.push(`{bold}${(0,f.escapeTags)(o)}{/bold}`),l.push(c.join(" {gray-fg}\xB7{/gray-fg} ")),l.push(b),l.join(`
2
+ `)}r(ne,"buildCwdPanel");function te(){const e="{bold}Tab{/bold} switch section {bold}I/X{/bold} all {bold}r{/bold} refresh {bold}Esc/q{/bold}";let i;if(v==="cwd"){const{installed:s,registered:t}=N(),c=s.length>0;i=`{cyan-fg}cwd:{/cyan-fg} ${C("i install",!c)} ${C("x uninstall",c)} ${C("a register",!t)} ${C("d unregister",t)} {bold}c{/bold} make active`}else i="{bold}\u2191/\u2193{/bold} move {bold}Enter{/bold} switch {bold}i{/bold} install {bold}x{/bold} uninstall {bold}d{/bold} unregister";return` ${i} {gray-fg}\u2502{/gray-fg} ${e}`}r(te,"buildStatus");function ie(e){if(e===void 0){const c=k(o).length>0,b=[];return b.push("{gray-fg}No projects registered yet.{/gray-fg}"),b.push(""),b.push("{gray-fg}Use the {/gray-fg}{bold}Current directory{/bold}{gray-fg} panel above:{/gray-fg}"),b.push(c?"{bold}x{/bold} {gray-fg}\u2014 uninstall IronBee from here (removes hooks + guidance){/gray-fg}":"{bold}i{/bold} {gray-fg}\u2014 install IronBee here (writes hooks + guidance, registers it){/gray-fg}"),b.push("{bold}a{/bold} {gray-fg}\u2014 register here only (inventory, no artifact writes){/gray-fg}"),b.join(`
3
+ `)}const i=(0,m.isProjectActive)(e),s=(0,j.getConfigLayerPaths)(e.path),t=[];return t.push(`{bold}${(0,f.escapeTags)(y(e.path))}{/bold}`),t.push("{gray-fg}"+"\u2500".repeat(46)+"{/gray-fg}"),t.push(`{gray-fg}path:{/gray-fg} ${(0,f.escapeTags)(e.path)}`),t.push(`{gray-fg}detected:{/gray-fg} ${(0,f.escapeTags)(k(e.path))||"(none on disk)"}`),t.push(`{gray-fg}added:{/gray-fg} ${(0,f.escapeTags)(e.installedAt)}`),t.push(`{gray-fg}on disk:{/gray-fg} ${i?"{green-fg}detected{/green-fg}":"{red-fg}stale (artifacts not detected){/red-fg}"}`),t.push(""),t.push("{bold}config layers{/bold}"),t.push(` {gray-fg}global {/gray-fg} ${(0,f.escapeTags)(s.global)}`),t.push(` {gray-fg}project{/gray-fg} ${(0,f.escapeTags)(s.project??"-")}`),t.push(` {gray-fg}local {/gray-fg} ${(0,f.escapeTags)(s.local??"-")}`),t.push(""),W(e.path)?(t.push("{yellow-fg}\u2605 active project{/yellow-fg} \u2014 Config / Sessions / Queue target this."),t.push("{gray-fg}c (in the cwd panel) = unselect \u2192 back to the current directory{/gray-fg}")):t.push("{gray-fg}Enter/s = make active (Config / Sessions / Queue switch to it){/gray-fg}"),t.push("{gray-fg}i = install \xB7 x = uninstall (pick a client when >1 registered; runs here, blocking){/gray-fg}"),t.join(`
4
+ `)}r(ie,"buildDetail");function B(e,i){const s=e.style;s.border!==void 0&&(s.border.fg=i)}r(B,"setBorderFg");function re(){const e=v==="cwd";U.setLabel(e?" {yellow-fg}\u25B8 Current directory{/yellow-fg} ":" Current directory "),d.setLabel(e?" Registered projects ":" {yellow-fg}\u25B8 Registered projects{/yellow-fg} "),B(U,e?"yellow":"gray"),B(d,e?"gray":"yellow"),B(R,e?"gray":"cyan");const i=d.style.selected??{};i.bg=e?void 0:"blue",i.fg=void 0}r(re,"applyFocusStyles");function A(){V=h(n.session.projectDir),n.setStatus(te()),re(),U.setContent(ne()),a.length===0?d.setItems(["{gray-fg}(no registered projects){/gray-fg}"]):(d.setItems(a.map(e=>ee(e))),d.select((0,f.clamp)(E,0,a.length-1))),R.setContent(ie(M())),R.setScroll(0),n.screen.render()}r(A,"render");function G(){v=v==="cwd"?"list":"cwd",A()}r(G,"toggleSection");function I(e){if(a=(0,w.listProjects)(),e!==void 0){const i=a.findIndex(s=>s.path===e);i>=0&&(E=i)}E=(0,f.clamp)(E,0,Math.max(0,a.length-1)),A()}r(I,"refresh");function F(e){a.length!==0&&(E=(0,f.clamp)(E+e,0,a.length-1),A())}r(F,"move");function oe(){try{(0,w.upsertProject)(o),I(p),n.session.message(`Registered ${y(o)} in the inventory. Use d to unregister, i to install.`)}catch(e){n.session.message(`Register failed: ${e instanceof Error?e.message:String(e)}`)}}r(oe,"registerCwd");function se(){n.session.confirm(`Unregister ${y(o)}? (inventory only, no files touched)`,e=>{if(e)try{(0,w.removeProject)(o),I()}catch(i){n.session.message(`Unregister failed: ${i instanceof Error?i.message:String(i)}`)}})}r(se,"unregisterCwd");function le(){if(a.some(e=>e.path===p)){n.session.message(`${y(o)} is already registered \u2014 press d to unregister.`);return}oe()}r(le,"cwdRegister");function ae(){if(!a.some(e=>e.path===p)){n.session.message(`${y(o)} is not registered \u2014 nothing to unregister.`);return}se()}r(ae,"cwdUnregister");function Q(){if(W(p)){n.session.message(`The current directory (${y(o)}) is already the active project.`);return}n.setActiveProject(p);const e=a.findIndex(i=>i.path===p);e>=0&&(E=e),A(),n.session.message(`Active project \u2192 current directory (${y(o)}). Any switched project is unselected.`)}r(Q,"setActiveToCwd");function ge(e,i){const s=n.session.silently(()=>(0,u.resolveInstallDefaultMode)(e)),t=[s,...u.ALL_MODES.filter(g=>g!==s)],c=t.map(g=>`${u.MODE_LABELS[g]} \u2014 ${u.MODE_HINTS[g]}`),l=n.session.silently(()=>(0,u.resolveInstallDefaultStrict)(e))?[!0,!1]:[!1,!0],S=l.map(g=>`${u.STRICT_LABELS[g?"true":"false"]} \u2014 ${u.STRICT_HINTS[g?"true":"false"]}`),_=r(()=>{n.session.pick("Which verification mode?",c,g=>{if(g<0){i("cancel");return}const $=t[g];if($!=="enforce"){i($);return}n.session.pick("How strict should verification be? ({cyan-fg}Esc{/cyan-fg} = back)",S,P=>{if(P<0){_();return}i($,l[P])})})},"askMode");_()}r(ge,"chooseMode");function de(e,i,s,t){if(i==="monitor"){t(void 0);return}const c=n.session.silently(()=>(0,j.loadConfig)(e)),b=j.ALL_CYCLES.map(g=>`${g} \u2014 ${L.CYCLE_HINTS[g]}`),l=j.ALL_CYCLES.map((g,$)=>(0,j.isCyclePatternsActive)(c,g)?$:-1).filter(g=>g>=0),S=(0,m.resolveSuggestionClient)(s),_=S?{suggestLabel:S.name,onSuggest:r(async g=>{const $=await(0,K.suggestPlatforms)(S,{projectDir:e,timeoutMs:L.SUGGEST_TIMEOUT_MS,signal:g});return $===null?null:$.map(P=>j.ALL_CYCLES.indexOf(P)).filter(P=>P>=0)},"onSuggest")}:void 0;n.session.pickMulti("Which platforms should require verification?",b,l,g=>{if(g===null){t("cancel");return}t(g.map($=>j.ALL_CYCLES[$]))},_)}r(de,"choosePlatforms");function q(e,i,s){z(i,t=>{ge(e,(c,b)=>{c!=="cancel"&&de(e,c,t,l=>{l!=="cancel"&&n.session.runWithOutput(`Install ${y(e)} (${t.map(S=>S.name).join(", ")})`,()=>{(0,u.applyModeToLayer)(e,"project",c,b),l!==void 0&&(0,Z.reconcileCyclesInLayer)(e,"project",l,!0);for(const S of t)S.install(e);(0,w.upsertProject)(e)}).then(()=>I(s))})})})}r(q,"doInstall");function Y(e,i){z("Uninstall which client?",s=>{n.session.confirm(`Uninstall ${s.map(t=>t.name).join(", ")} from ${y(e)}?`,t=>{t&&n.session.runWithOutput(`Uninstall ${y(e)} (${s.map(c=>c.name).join(", ")})`,()=>{const c=new Set(s.map(l=>l.name));for(const l of s)l.uninstall(e);if(!m.REGISTERED_CLIENTS.some(l=>!c.has(l.name)&&l.detect(e))){const l=(0,J.join)(e,".ironbee");(0,O.existsSync)(l)&&(0,O.rmSync)(l,{recursive:!0,force:!0}),(0,w.removeProject)(e)}}).then(()=>I(i))})})}r(Y,"doUninstall");function ce(){if(k(o).length>0){n.session.message(`${y(o)} is already installed \u2014 press x to uninstall.`);return}q(o,"Install into the current directory \u2014 which client?",p)}r(ce,"cwdInstall");function fe(){if(k(o).length===0){n.session.message(`${y(o)} is not installed \u2014 nothing to uninstall.`);return}Y(o,p)}r(fe,"cwdUninstall");function ue(){const e=M();e!==void 0&&(n.setActiveProject(e.path),A(),n.session.message(`Active project \u2192 ${y(e.path)}. Config / Sessions / Queue now target it.`))}r(ue,"switchTo");function ye(){const e=M();e!==void 0&&n.session.confirm(`Unregister ${y(e.path)}? (inventory only, no files touched)`,i=>{if(i)try{(0,w.removeProject)(e.path),I()}catch(s){n.session.message(`Unregister failed: ${s instanceof Error?s.message:String(s)}`)}})}r(ye,"unregisterSelected");function z(e,i){if(m.REGISTERED_CLIENTS.length<=1){i(m.REGISTERED_CLIENTS);return}const s=m.REGISTERED_CLIENTS.map(t=>t.name);n.session.pick(e,["All clients",...s],t=>{t<0||i(t===0?m.REGISTERED_CLIENTS:[m.REGISTERED_CLIENTS[t-1]])})}r(z,"pickClient");function pe(){const e=M();e!==void 0&&q(e.path,"Install which client?")}r(pe,"installSelected");function be(){const e=M();e!==void 0&&Y(e.path)}r(be,"uninstallSelected");async function me(){await n.session.runWithOutput("Install \u2014 all registered projects",async()=>{await(0,L.runInstallAll)({})}),I()}r(me,"installAll");function he(){n.session.confirm("Uninstall IronBee from ALL registered projects? (destructive)",e=>{e&&n.session.runWithOutput("Uninstall \u2014 all registered projects",async()=>{await(0,x.runUninstallAll)({yes:!0})}).then(()=>I())})}return r(he,"uninstallAllFlow"),d.key(["tab"],()=>G()),d.key(["S-tab"],()=>G()),d.key(["up","k"],()=>{v==="list"&&F(-1)}),d.key(["down","j"],()=>{v==="list"&&F(1)}),d.key(["i"],()=>{v==="cwd"?ce():pe()}),d.key(["x"],()=>{v==="cwd"?fe():be()}),d.key(["d"],()=>{v==="cwd"?ae():ye()}),d.key(["a"],()=>{v==="cwd"&&le()}),d.key(["c"],()=>{v==="cwd"&&Q()}),d.key(["enter","s"],()=>{v==="list"?ue():Q()}),d.key(["S-i"],()=>{me()}),d.key(["S-x"],()=>he()),d.key(["r"],()=>I()),A(),d.focus(),n.screen.render(),{unmount(){U.destroy(),d.destroy(),R.destroy()}}}r(ke,"mountProjectsView");const Ae={id:"projects",title:"Projects",summary:"Registry \u2014 switch active \xB7 register / unregister \xB7 install / uninstall (+ --all)",mount(n){return ke(n)}};0&&(module.exports={projectsArea});
@@ -1,8 +1,8 @@
1
- "use strict";var m=Object.create;var v=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var E=Object.getPrototypeOf,P=Object.prototype.hasOwnProperty;var g=(d,e)=>v(d,"name",{value:e,configurable:!0});var W=(d,e)=>{for(var t in e)v(d,t,{get:e[t],enumerable:!0})},f=(d,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of k(e))!P.call(d,r)&&r!==t&&v(d,r,{get:()=>e[r],enumerable:!(n=w(e,r))||n.enumerable});return d};var D=(d,e,t)=>(t=d!=null?m(E(d)):{},f(e||!d||!d.__esModule?v(t,"default",{value:d,enumerable:!0}):t,d)),S=d=>f(v({},"__esModule",{value:!0}),d);var $={};W($,{TuiSession:()=>M});module.exports=S($);var u=D(require("blessed")),p=require("./util");class M{constructor(e,t){this.rerenderDirs=new Set;this.modalOpen=!1;this.screen=e,this.launchDir=t,this.activeProjectDir=t}static{g(this,"TuiSession")}get projectDir(){return this.activeProjectDir}setProjectDir(e){this.activeProjectDir=e}markRerenderNeeded(e){this.rerenderDirs.add(e)}isRerenderNeeded(){return this.rerenderDirs.size>0}rerenderProjects(){const e=[...this.rerenderDirs];return this.rerenderDirs.clear(),e}isModalOpen(){return this.modalOpen}openModal(){const e=this.screen.focused;return this.modalOpen=!0,()=>{e!=null&&e.detached!==!0&&e.focus(),this.screen.render(),setImmediate(()=>{this.modalOpen=!1})}}message(e){const t=this.openModal(),n=u.message({parent:this.screen,top:"center",left:"center",width:"60%",height:"shrink",border:{type:"line"},tags:!0,style:{border:{fg:"yellow"}}});n.display((0,p.escapeTags)(e),3,()=>{n.destroy(),t()})}prompt(e,t,n){const r=this.openModal(),o=u.prompt({parent:this.screen,top:"center",left:"center",width:"72%",height:"shrink",border:{type:"line"},tags:!0,keys:!0,style:{border:{fg:"green"}}});o.input(e,t,(i,c)=>{o.destroy(),r(),n(typeof c=="string"?c:null)}),this.screen.render()}confirm(e,t){const n=this.openModal(),r=u.box({parent:this.screen,top:"center",left:"center",width:"60%",height:8,border:{type:"line"},tags:!0,style:{border:{fg:"cyan"}},content:` ${(0,p.escapeTags)(e)}
1
+ "use strict";var j=Object.create;var w=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var O=Object.getPrototypeOf,T=Object.prototype.hasOwnProperty;var h=(i,e)=>w(i,"name",{value:e,configurable:!0});var C=(i,e)=>{for(var t in e)w(i,t,{get:e[t],enumerable:!0})},M=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of B(e))!T.call(i,s)&&s!==t&&w(i,s,{get:()=>e[s],enumerable:!(n=x(e,s))||n.enumerable});return i};var A=(i,e,t)=>(t=i!=null?j(O(i)):{},M(e||!i||!i.__esModule?w(t,"default",{value:i,enumerable:!0}):t,i)),L=i=>M(w({},"__esModule",{value:!0}),i);var _={};C(_,{TuiSession:()=>q});module.exports=L(_);var p=A(require("blessed")),a=require("./util");class q{constructor(e,t){this.rerenderDirs=new Set;this.modalOpen=!1;this.screen=e,this.launchDir=t,this.activeProjectDir=t}static{h(this,"TuiSession")}get projectDir(){return this.activeProjectDir}setProjectDir(e){this.activeProjectDir=e}markRerenderNeeded(e){this.rerenderDirs.add(e)}isRerenderNeeded(){return this.rerenderDirs.size>0}rerenderProjects(){const e=[...this.rerenderDirs];return this.rerenderDirs.clear(),e}isModalOpen(){return this.modalOpen}openModal(){const e=this.screen.focused;return this.modalOpen=!0,()=>{e!=null&&e.detached!==!0&&e.focus(),this.screen.render(),setImmediate(()=>{this.modalOpen=!1})}}message(e){const t=this.openModal(),n=p.message({parent:this.screen,top:"center",left:"center",width:"60%",height:"shrink",border:{type:"line"},tags:!0,style:{border:{fg:"yellow"}}});n.display((0,a.escapeTags)(e),3,()=>{n.destroy(),t()})}prompt(e,t,n){const s=this.openModal(),r=p.prompt({parent:this.screen,top:"center",left:"center",width:"72%",height:"shrink",border:{type:"line"},tags:!0,keys:!0,style:{border:{fg:"green"}}});r.input(e,t,(g,o)=>{r.destroy(),s(),n(typeof o=="string"?o:null)}),this.screen.render()}confirm(e,t){const n=this.openModal(),s=p.box({parent:this.screen,top:"center",left:"center",width:"60%",height:8,border:{type:"line"},tags:!0,style:{border:{fg:"cyan"}},content:` ${(0,a.escapeTags)(e)}
2
2
 
3
- {gray-fg}\u2191/\u2193 choose \xB7 Enter confirm \xB7 Esc cancel{/gray-fg}`}),o=u.list({parent:r,bottom:0,left:1,right:1,height:2,keys:!0,tags:!0,style:{selected:{bg:"blue",fg:"white"}},items:["Yes","No"]});o.select(1);const i=g(c=>{r.destroy(),n(),t(c)},"finish");o.on("select",(c,h)=>i(h===0)),o.key(["escape","q"],()=>i(!1)),o.focus(),this.screen.render()}pickMulti(e,t,n,r){const o=this.openModal(),i=new Set(n.filter(s=>s>=0&&s<t.length)),c=g(()=>t.map((s,y)=>`${i.has(y)?"{green-fg}[x]{/green-fg}":"[ ]"} ${(0,p.escapeTags)(s)}`),"rows"),h=u.box({parent:this.screen,top:"center",left:"center",width:"60%",height:t.length+5,border:{type:"line"},label:` ${e} `,tags:!0,style:{border:{fg:"yellow"}},content:" {gray-fg}space toggle \xB7 a all \xB7 Enter confirm \xB7 Esc cancel{/gray-fg}"}),a=u.list({parent:h,top:1,left:1,right:1,bottom:0,keys:!0,tags:!0,style:{selected:{bg:"blue",fg:"white"}},items:c()}),b=g(s=>{h.destroy(),o(),r(s)},"finish"),l=g(()=>{const s=a.selected;a.setItems(c()),a.select(s),this.screen.render()},"redraw");a.key(["space"],()=>{const s=a.selected;i.has(s)?i.delete(s):i.add(s),l()}),a.key(["a"],()=>{i.size===t.length?i.clear():t.forEach((s,y)=>{i.add(y)}),l()}),a.on("select",()=>b([...i].sort((s,y)=>s-y))),a.key(["escape","q"],()=>b(null)),a.focus(),this.screen.render()}pick(e,t,n){const r=this.openModal(),o=u.list({parent:this.screen,top:"center",left:"center",width:"50%",height:t.length+2,border:{type:"line"},label:` ${e} `,tags:!0,keys:!0,style:{selected:{bg:"blue",fg:"white"},border:{fg:"yellow"}},items:t.map(i=>(0,p.escapeTags)(i))});o.on("select",(i,c)=>{o.destroy(),r(),n(c)}),o.key(["escape","q"],()=>{o.destroy(),r(),n(-1)}),o.focus(),this.screen.render()}silently(e){const t=process.stdout.write,n=process.stderr.write,r=g(()=>!0,"noop");process.stdout.write=r,process.stderr.write=r;try{return e()}finally{process.stdout.write=t,process.stderr.write=n}}bindPaneKeys(e,t){e.key(["up","k"],()=>{e.scroll(-1),this.screen.render()}),e.key(["down","j"],()=>{e.scroll(1),this.screen.render()}),e.key(["pageup"],()=>{e.scroll(-10),this.screen.render()}),e.key(["pagedown"],()=>{e.scroll(10),this.screen.render()}),e.key(["escape","enter","q"],()=>{e.destroy(),t()}),e.focus()}showPane(e,t){const n=this.openModal(),r=u.box({parent:this.screen,top:"center",left:"center",width:"82%",height:"82%",border:{type:"line"},label:` ${e} `,tags:!0,scrollable:!0,alwaysScroll:!0,scrollbar:{ch:" "},style:{border:{fg:"cyan"}},content:`${t}
3
+ {gray-fg}\u2191/\u2193 choose \xB7 Enter confirm \xB7 Esc cancel{/gray-fg}`}),r=p.list({parent:s,bottom:0,left:1,right:1,height:2,keys:!0,tags:!0,style:{selected:{bg:"blue",fg:"white"}},items:["Yes","No"]});r.select(1);const g=h(o=>{s.destroy(),n(),t(o)},"finish");r.on("select",(o,y)=>g(y===0)),r.key(["escape","q"],()=>g(!1)),r.focus(),this.screen.render()}pickMulti(e,t,n,s,r){const g=this.openModal(),o=new Set(n.filter(l=>l>=0&&l<t.length)),y=r?.onSuggest,v=typeof y=="function",m=r?.suggestLabel??"the agent",d=` {gray-fg}space toggle \xB7 a all${v?` \xB7 s suggest (${(0,a.escapeTags)(m)})`:""} \xB7 Enter confirm \xB7 Esc cancel{/gray-fg}`;let c=!1,b=null,k=null;const W=h(()=>t.map((l,f)=>`${o.has(f)?"{green-fg}[x]{/green-fg}":"[ ]"} ${(0,a.escapeTags)(l)}`),"rows"),$=h(()=>c?` {cyan-fg}Analysing project with ${(0,a.escapeTags)(m)}... (Esc to cancel){/cyan-fg}`:b!==null?` {gray-fg}${(0,a.escapeTags)(b)}{/gray-fg}`:d,"statusText"),E=p.box({parent:this.screen,top:"center",left:"center",width:"60%",height:t.length+5,border:{type:"line"},label:` ${e} `,tags:!0,style:{border:{fg:"yellow"}},content:d}),u=p.list({parent:E,top:1,left:1,right:1,bottom:0,keys:!0,tags:!0,style:{selected:{bg:"blue",fg:"white"}},items:W()}),D=h(l=>{E.destroy(),g(),s(l)},"finish"),S=h(()=>{const l=u.selected;u.setItems(W()),u.select(l),E.setContent($()),this.screen.render()},"redraw");u.key(["space"],()=>{if(c)return;const l=u.selected;o.has(l)?o.delete(l):o.add(l),b=null,S()}),u.key(["a"],()=>{c||(o.size===t.length?o.clear():t.forEach((l,f)=>{o.add(f)}),b=null,S())}),u.on("select",()=>{c||D([...o].sort((l,f)=>l-f))}),u.key(["escape","q"],()=>{if(c){k?.abort();return}D(null)}),v&&u.key(["s"],()=>{c||(c=!0,b=null,k=new AbortController,E.setContent($()),this.screen.render(),y(k.signal).then(l=>{const f=(l??[]).filter(P=>P>=0&&P<t.length);f.length>0?(o.clear(),f.forEach(P=>{o.add(P)}),b=null):b="Couldn't analyse \u2014 keeping current selection"},()=>{b="Couldn't analyse \u2014 keeping current selection"}).then(()=>{c=!1,k=null,S()}))}),u.focus(),this.screen.render()}pick(e,t,n){const s=this.openModal(),r=p.list({parent:this.screen,top:"center",left:"center",width:"50%",height:t.length+2,border:{type:"line"},label:` ${e} `,tags:!0,keys:!0,style:{selected:{bg:"blue",fg:"white"},border:{fg:"yellow"}},items:t.map(g=>(0,a.escapeTags)(g))});r.on("select",(g,o)=>{r.destroy(),s(),n(o)}),r.key(["escape","q"],()=>{r.destroy(),s(),n(-1)}),r.focus(),this.screen.render()}silently(e){const t=process.stdout.write,n=process.stderr.write,s=h(()=>!0,"noop");process.stdout.write=s,process.stderr.write=s;try{return e()}finally{process.stdout.write=t,process.stderr.write=n}}bindPaneKeys(e,t){e.key(["up","k"],()=>{e.scroll(-1),this.screen.render()}),e.key(["down","j"],()=>{e.scroll(1),this.screen.render()}),e.key(["pageup"],()=>{e.scroll(-10),this.screen.render()}),e.key(["pagedown"],()=>{e.scroll(10),this.screen.render()}),e.key(["escape","enter","q"],()=>{e.destroy(),t()}),e.focus()}showPane(e,t){const n=this.openModal(),s=p.box({parent:this.screen,top:"center",left:"center",width:"82%",height:"82%",border:{type:"line"},label:` ${e} `,tags:!0,scrollable:!0,alwaysScroll:!0,scrollbar:{ch:" "},style:{border:{fg:"cyan"}},content:`${t}
4
4
 
5
- {gray-fg}[ \u2191/\u2193 scroll \xB7 Esc/Enter close ]{/gray-fg}`});this.bindPaneKeys(r,n),this.screen.render()}runWithOutput(e,t){return new Promise(n=>{const r=this.openModal(),o=u.box({parent:this.screen,top:"center",left:"center",width:"82%",height:"82%",border:{type:"line"},label:` ${e} `,tags:!0,scrollable:!0,alwaysScroll:!0,scrollbar:{ch:" "},style:{border:{fg:"green"}},content:"{gray-fg}Running\u2026 (the TUI is blocked until this finishes){/gray-fg}"});o.focus(),this.screen.render();const i=[],c=process.stdout.write,h=process.stderr.write,a=g(l=>(i.push(typeof l=="string"?l:String(l)),!0),"capture");process.stdout.write=a,process.stderr.write=a;const b=g(l=>{process.stdout.write=c,process.stderr.write=h;let s=(0,p.stripAnsi)(i.join(""));l.length>0&&(s+=(s.length>0?`
6
- `:"")+l),s=s.trim(),s.length===0&&(s="(done \u2014 no output)"),o.setContent(`${(0,p.escapeTags)(s)}
5
+ {gray-fg}[ \u2191/\u2193 scroll \xB7 Esc/Enter close ]{/gray-fg}`});this.bindPaneKeys(s,n),this.screen.render()}runWithOutput(e,t){return new Promise(n=>{const s=this.openModal(),r=p.box({parent:this.screen,top:"center",left:"center",width:"82%",height:"82%",border:{type:"line"},label:` ${e} `,tags:!0,scrollable:!0,alwaysScroll:!0,scrollbar:{ch:" "},style:{border:{fg:"green"}},content:"{gray-fg}Running\u2026 (the TUI is blocked until this finishes){/gray-fg}"});r.focus(),this.screen.render();const g=[],o=process.stdout.write,y=process.stderr.write,v=h(d=>(g.push(typeof d=="string"?d:String(d)),!0),"capture");process.stdout.write=v,process.stderr.write=v;const m=h(d=>{process.stdout.write=o,process.stderr.write=y;let c=(0,a.stripAnsi)(g.join(""));d.length>0&&(c+=(c.length>0?`
6
+ `:"")+d),c=c.trim(),c.length===0&&(c="(done \u2014 no output)"),r.setContent(`${(0,a.escapeTags)(c)}
7
7
 
8
- {gray-fg}[ \u2191/\u2193 scroll \xB7 Esc/Enter close ]{/gray-fg}`),o.setScroll(0),this.bindPaneKeys(o,()=>{r(),n()}),this.screen.render()},"present");Promise.resolve().then(()=>t()).then(l=>b(typeof l=="string"?l:""),l=>b(`\u2717 ${l instanceof Error?l.message:String(l)}`))})}}0&&(module.exports={TuiSession});
8
+ {gray-fg}[ \u2191/\u2193 scroll \xB7 Esc/Enter close ]{/gray-fg}`),r.setScroll(0),this.bindPaneKeys(r,()=>{s(),n()}),this.screen.render()},"present");Promise.resolve().then(()=>t()).then(d=>m(typeof d=="string"?d:""),d=>m(`\u2717 ${d instanceof Error?d.message:String(d)}`))})}}0&&(module.exports={TuiSession});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ironbee-ai/cli",
3
- "version": "0.31.0",
3
+ "version": "0.33.0",
4
4
  "description": "The CLI for IronBee — Verification and Intelligence Layer for Agentic Development",
5
5
  "main": "dist/index.js",
6
6
  "bin": {