ozmoz 0.1.25 → 0.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -1,33 +1,33 @@
1
1
  #!/usr/bin/env node
2
- var r=require("fs"),c=require("path"),W=require("https"),ne=require("http"),w=require("os"),{exec:oe,spawnSync:j}=require("child_process"),se=[c.join(__dirname,"..","scripts","setup-lib.cjs"),c.join(__dirname,"..","..","scripts","setup-lib.cjs"),c.join(__dirname,"scripts","setup-lib.cjs")],ie=se.find(r.existsSync)||c.join(__dirname,"..","scripts","setup-lib.cjs"),{runFullSetup:K,handleAuthAndEnv:q,touchTsConfig:re,attemptViteAutoImportPatch:ae,injectUniversalRuntime:ce,writeBrowserConfig:le,patchAllowScripts:de}=require(ie),ue="\x1B[38;2;15;156;140m",pe="\x1B[31m",Y="\x1B[0m";function d(e){console.log(e.replace(/OZmoz|\[|\]|→/g,t=>`${ue}${t}${Y}`))}function y(e){console.error(`${pe}${e}${Y}`)}var A="ozmoz",J=/<!--\s*(?:ozmoz|fleetbo|OZmoz):start[^>]*-->[\s\S]*?<!--\s*(?:ozmoz|fleetbo|OZmoz):end\s*-->/i,me="<!-- OZmoz:end -->",H="# OZMOZ DATA OS \u2014 DIRECTIVES SYST\xC8ME",R={claude:"Claude Code",cursor:"Cursor",windsurf:"Windsurf",devin:"Devin",codex:"Codex CLI",gemini:"Gemini CLI",antigravity:"Antigravity CLI",copilot:"GitHub Copilot"},D={created:"created",updated:"updated",unchanged:"already up to date",appended:"OZmoz block appended (your own content was kept)",migrated:"old file replaced (backup: <file>.ozmoz-legacy.bak)",invalid:"skipped: the file is not valid JSON, fix or delete it first"};function fe(){try{return JSON.parse(r.readFileSync(c.join(__dirname,"..","package.json"),"utf8")).version||"dev"}catch{return"dev"}}var he=Buffer.from("QUl6YVN5QUM1Uk94STNibklPMUR5TmZsTWhGUnJ0blItNDVwNFJF","base64").toString("utf8");function ge(e){try{let t=JSON.parse(Buffer.from(e.split(".")[1],"base64url").toString("utf8"));return typeof t.exp=="number"&&t.exp*1e3<Date.now()+6e4}catch{return!1}}async function ye(e,t){let s=await fetch(`https://securetoken.googleapis.com/v1/token?key=${he}`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`grant_type=refresh_token&refresh_token=${encodeURIComponent(t)}`});if(!s.ok)return null;let n=await s.json();return n.id_token?(r.writeFileSync(e,JSON.stringify({devToken:n.id_token,refreshToken:n.refresh_token||t,updatedAt:new Date().toISOString()},null,2)),n.id_token):null}async function Oe(){if(process.env.FLEETBO_DEV_TOKEN)return process.env.FLEETBO_DEV_TOKEN;try{let e=c.join(w.homedir(),".fleetbo","credentials.json");if(r.existsSync(e)){let t=JSON.parse(r.readFileSync(e,"utf8"));if(t.devToken&&!ge(t.devToken))return t.devToken;if(t.refreshToken)try{let s=await ye(e,t.refreshToken);if(s)return s}catch{}}}catch{}return null}async function X(){let e=c.join(w.homedir(),".fleetbo","guidelines.json"),t=await Oe();t||y('[OZmoz] Not logged in: run "npx ozmoz login" first to load the full instructions. Using local cache if available.');try{d("[OZmoz] Fetching instructions from Cloud...");let s=await fetch("https://getagentdirectives-jqycakhlxa-uc.a.run.app",{method:"POST",headers:Object.assign({"Content-Type":"application/json"},t?{Authorization:`Bearer ${t}`}:{}),body:JSON.stringify({data:{}})});if(!s.ok)y("[OZmoz] Cloud error HTTP "+s.status);else{let n=await s.json(),i=n.result?.data||n.result||n.data;if(i&&i.protocol&&i.directives)return d("[OZmoz] Instructions loaded successfully."),r.existsSync(c.dirname(e))||r.mkdirSync(c.dirname(e),{recursive:!0}),r.writeFileSync(e,JSON.stringify(i,null,2),"utf8"),i;y("[OZmoz] Empty Cloud response.")}}catch(s){y("[OZmoz] Network error: "+s.message)}if(r.existsSync(e)){d("[OZmoz] Using local cache (~/.fleetbo/guidelines.json)");try{return JSON.parse(r.readFileSync(e,"utf8"))}catch{}}return{protocol:"",directives:"",version:"1.0.0"}}function V(e,t){return"<!-- ozmoz:start v"+e+` -->
2
+ var i=require("fs"),c=require("path"),W=require("https"),ne=require("http"),b=require("os"),{exec:oe,spawnSync:x}=require("child_process"),re=[c.join(__dirname,"..","scripts","setup-lib.cjs"),c.join(__dirname,"..","..","scripts","setup-lib.cjs"),c.join(__dirname,"scripts","setup-lib.cjs")],se=re.find(i.existsSync)||c.join(__dirname,"..","scripts","setup-lib.cjs"),{runFullSetup:Y,handleAuthAndEnv:K,touchTsConfig:ie,attemptViteAutoImportPatch:ae,injectUniversalRuntime:ce,writeBrowserConfig:le,patchAllowScripts:de}=require(se),ue=!!(process.stdout&&process.stdout.isTTY&&typeof process.stdout.hasColors=="function"&&process.stdout.hasColors(16777216)),pe=ue?"\x1B[38;2;15;156;140m":"\x1B[36m",me="\x1B[31m",q="\x1B[0m";function d(e){console.log(e.replace(/OZmoz|\[|\]|→/g,t=>`${pe}${t}${q}`))}function O(e){console.error(`${me}${e}${q}`)}var k="ozmoz",V=/<!--\s*(?:ozmoz|fleetbo|OZmoz):start[^>]*-->[\s\S]*?<!--\s*(?:ozmoz|fleetbo|OZmoz):end\s*-->/i,fe="<!-- OZmoz:end -->",H="# OZMOZ DATA OS \u2014 DIRECTIVES SYST\xC8ME",F={claude:"Claude Code",cursor:"Cursor",windsurf:"Windsurf",devin:"Devin",codex:"Codex CLI",gemini:"Gemini CLI",antigravity:"Antigravity CLI",copilot:"GitHub Copilot"},P={created:"created",updated:"updated",unchanged:"already up to date",appended:"OZmoz block appended (your own content was kept)",migrated:"old file replaced (backup: <file>.ozmoz-legacy.bak)",invalid:"skipped: the file is not valid JSON, fix or delete it first"};function he(){try{return JSON.parse(i.readFileSync(c.join(__dirname,"..","package.json"),"utf8")).version||"dev"}catch{return"dev"}}var ge=Buffer.from("QUl6YVN5QUM1Uk94STNibklPMUR5TmZsTWhGUnJ0blItNDVwNFJF","base64").toString("utf8");function ye(e){try{let t=JSON.parse(Buffer.from(e.split(".")[1],"base64url").toString("utf8"));return typeof t.exp=="number"&&t.exp*1e3<Date.now()+6e4}catch{return!1}}async function Oe(e,t){let r=await fetch(`https://securetoken.googleapis.com/v1/token?key=${ge}`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`grant_type=refresh_token&refresh_token=${encodeURIComponent(t)}`});if(!r.ok)return null;let n=await r.json();return n.id_token?(i.writeFileSync(e,JSON.stringify({devToken:n.id_token,refreshToken:n.refresh_token||t,updatedAt:new Date().toISOString()},null,2)),n.id_token):null}async function ze(){if(process.env.FLEETBO_DEV_TOKEN)return process.env.FLEETBO_DEV_TOKEN;try{let e=c.join(b.homedir(),".fleetbo","credentials.json");if(i.existsSync(e)){let t=JSON.parse(i.readFileSync(e,"utf8"));if(t.devToken&&!ye(t.devToken))return t.devToken;if(t.refreshToken)try{let r=await Oe(e,t.refreshToken);if(r)return r}catch{}}}catch{}return null}async function X(){let e=c.join(b.homedir(),".fleetbo","guidelines.json"),t=await ze();t||O('[OZmoz] Not logged in: run "npx ozmoz login" first to load the full instructions. Using local cache if available.');try{d("[OZmoz] Fetching instructions from Cloud...");let r=await fetch("https://getagentdirectives-jqycakhlxa-uc.a.run.app",{method:"POST",headers:Object.assign({"Content-Type":"application/json"},t?{Authorization:`Bearer ${t}`}:{}),body:JSON.stringify({data:{}})});if(!r.ok)O("[OZmoz] Cloud error HTTP "+r.status);else{let n=await r.json(),s=n.result?.data||n.result||n.data;if(s&&s.protocol&&s.directives)return d("[OZmoz] Instructions loaded successfully."),i.existsSync(c.dirname(e))||i.mkdirSync(c.dirname(e),{recursive:!0}),i.writeFileSync(e,JSON.stringify(s,null,2),"utf8"),s;O("[OZmoz] Empty Cloud response.")}}catch(r){O("[OZmoz] Network error: "+r.message)}if(i.existsSync(e)){d("[OZmoz] Using local cache (~/.fleetbo/guidelines.json)");try{return JSON.parse(i.readFileSync(e,"utf8"))}catch{}}return{protocol:"",directives:"",version:"1.0.0"}}function G(e,t){return"<!-- ozmoz:start v"+e+` -->
3
3
  `+t.trim()+`
4
- `+me+`
5
- `}function ze(e,t,s){let n=r.existsSync(e)?r.readFileSync(e,"utf8"):null,i,o;return n===null?(i="created",o=t):J.test(n)?(o=n.replace(J,()=>t.trimEnd()),i=o===n?"unchanged":"updated"):n.includes(H)?(i="migrated",o=t):(i="appended",o=n.replace(/\s*$/,`
4
+ `+fe+`
5
+ `}function ve(e,t,r){let n=i.existsSync(e)?i.readFileSync(e,"utf8"):null,s,o;return n===null?(s="created",o=t):V.test(n)?(o=n.replace(V,()=>t.trimEnd()),s=o===n?"unchanged":"updated"):n.includes(H)?(s="migrated",o=t):(s="appended",o=n.replace(/\s*$/,`
6
6
 
7
- `)+t),!s&&i!=="unchanged"&&(i==="migrated"&&r.writeFileSync(e+".ozmoz-legacy.bak",n,"utf8"),r.mkdirSync(c.dirname(e),{recursive:!0}),r.writeFileSync(e,o,"utf8")),i}function Q(){return[c.join(__dirname,"ozmoz-mcp.js"),c.join(__dirname,"..","bin","ozmoz-mcp.js"),c.join(__dirname,"bin","ozmoz-mcp.js"),c.join(__dirname,"..","src","bin","ozmoz-mcp.js")].find(t=>r.existsSync(t))||c.resolve(__dirname,"ozmoz-mcp.js")}function Z(e,t,s){let n=Object.assign({command:process.execPath,args:[__filename,"mcp","--run"]},s||{}),i={};if(r.existsSync(e))try{let l=JSON.parse(r.readFileSync(e,"utf8"));if(!l||typeof l!="object"||Array.isArray(l))return"invalid";i=l}catch{return"invalid"}let o=i.mcpServers&&i.mcpServers[A];return o&&JSON.stringify(o)===JSON.stringify(n)?"unchanged":(i.mcpServers=i.mcpServers||{},i.mcpServers[A]=n,t||(r.mkdirSync(c.dirname(e),{recursive:!0}),r.writeFileSync(e,JSON.stringify(i,null,2)+`
8
- `,"utf8")),o?"updated":"created")}function F(e){let t=process.platform==="win32"?"where":"which";return j(t,[e],{stdio:"ignore"}).status===0}function B(e,t,s){let n=j(e,t,{encoding:"utf8",timeout:s||3e4,shell:process.platform==="win32"});return{ok:n.status===0,out:(n.stdout||"")+(n.stderr||"")}}function Se(e,t,s){let n=e==="claude"?["--scope",s||"user"]:[],i=Q(),o=["mcp","add"].concat(n,[A,"--",process.execPath,i]),l=["mcp","remove",A].concat(n),a=e+" "+o.join(" ");if(!F(e))return{status:"manual",detail:a};if(t)return{status:"planned",detail:a};let p=B(e,["mcp","list"],6e4),u=p.ok?p.out.split(`
9
- `):[],m=u.find(v=>/^[\s|│┃]*ozmoz(?![\w@-])/.test(v)),f=u.some(v=>/^\s*(?:fleetbo|fleetbo-svro):\s/.test(v));if(m&&m.includes("ozmoz@latest"))return{status:"unchanged",legacy:f};if(m&&!B(e,l).ok)return{status:"manual",detail:e+" "+l.join(" ")+" && "+a,legacy:f};let g=B(e,o);return g.ok?{status:m?"updated":"created",legacy:f}:{status:"failed",detail:a,message:g.out.trim().split(`
10
- `).slice(-2).join(" "),legacy:f}}function ve(e){let t={user:!1,local:!1,others:[]};try{let s=JSON.parse(r.readFileSync(c.join(w.homedir(),".claude.json"),"utf8")),n=a=>!!a&&typeof a=="object"&&/fleetbo-svro|ozmoz/.test(String(a.command||"")+" "+JSON.stringify(a.args||[])),i=(a,p)=>{!a||typeof a!="object"||Object.keys(a).forEach(u=>{u===A?t[p]=!0:n(a[u])&&t.others.push({name:u,where:p})})};i(s.mcpServers,"user");let o=e;try{o=r.realpathSync(e)}catch{}let l=s.projects||{};Array.from(new Set([e,o])).forEach(a=>i((l[a]||{}).mcpServers,"local"))}catch{}return t}function Ee(e){let t=ve(e);t.user&&d(" \u26A0\uFE0F A global (user-scope) '"+A+"' entry from a previous version also exists: the tools appear in every project. To keep them in OZmoz projects only: claude mcp remove "+A+" --scope user"),t.local&&d(" \u26A0\uFE0F A local-scope '"+A+"' entry exists for this folder and takes precedence over .mcp.json. Remove it: claude mcp remove "+A+" --scope local"),t.others.forEach(s=>{d(" \u26A0\uFE0F An old MCP entry named '"+s.name+"' ("+s.where+" scope) points to OZmoz/Fleetbo. Remove it: claude mcp remove "+s.name+" --scope "+s.where)})}function Te(e){let t=w.homedir(),s=n=>r.existsSync(n);return{claude:F("claude")||s(c.join(t,".claude")),cursor:s(c.join(e,".cursor"))||s(c.join(t,".cursor"))||F("cursor"),windsurf:s(c.join(t,".codeium","windsurf"))||s(c.join(e,".windsurf")),devin:s(c.join(e,".devin")),codex:F("codex")||s(c.join(t,".codex")),gemini:F("gemini")||s(c.join(t,".gemini")),antigravity:F("agy")||s(c.join(t,".antigravity"))||s(c.join(e,".antigravity")),copilot:F("copilot")||s(c.join(t,".copilot"))}}var we={claude:{bin:"claude",launch:e=>[e]},gemini:{bin:"gemini",launch:e=>["-i",e]},codex:{bin:"codex",launch:e=>[e]},antigravity:{bin:"agy",launch:e=>["-i",e]}};function be(e){return String(e||"").replace(/[^\p{L}\p{N} '.,:\-_]/gu," ").replace(/\s+/g," ").trim().slice(0,4e3)}function xe(e,t,s){let n=be(t),i=n?`The user already provided their project description and technical choices: "${n}".
7
+ `)+t),!r&&s!=="unchanged"&&(s==="migrated"&&i.writeFileSync(e+".ozmoz-legacy.bak",n,"utf8"),i.mkdirSync(c.dirname(e),{recursive:!0}),i.writeFileSync(e,o,"utf8")),s}function Q(){return[c.join(__dirname,"ozmoz-mcp.js"),c.join(__dirname,"..","bin","ozmoz-mcp.js"),c.join(__dirname,"bin","ozmoz-mcp.js"),c.join(__dirname,"..","src","bin","ozmoz-mcp.js")].find(t=>i.existsSync(t))||c.resolve(__dirname,"ozmoz-mcp.js")}function U(e,t,r){let n=Object.assign({command:process.execPath,args:[__filename,"mcp","--run"]},r||{}),s={};if(i.existsSync(e))try{let l=JSON.parse(i.readFileSync(e,"utf8"));if(!l||typeof l!="object"||Array.isArray(l))return"invalid";s=l}catch{return"invalid"}let o=s.mcpServers&&s.mcpServers[k];return o&&JSON.stringify(o)===JSON.stringify(n)?"unchanged":(s.mcpServers=s.mcpServers||{},s.mcpServers[k]=n,t||(i.mkdirSync(c.dirname(e),{recursive:!0}),i.writeFileSync(e,JSON.stringify(s,null,2)+`
8
+ `,"utf8")),o?"updated":"created")}function R(e){let t=process.platform==="win32"?"where":"which";return x(t,[e],{stdio:"ignore"}).status===0}function $(e,t,r){let n=x(e,t,{encoding:"utf8",timeout:r||3e4,shell:process.platform==="win32"});return{ok:n.status===0,out:(n.stdout||"")+(n.stderr||"")}}function Se(e,t,r){let n=e==="claude"?["--scope",r||"user"]:[],s=Q(),o=["mcp","add"].concat(n,[k,"--",process.execPath,s]),l=["mcp","remove",k].concat(n),a=e+" "+o.join(" ");if(!R(e))return{status:"manual",detail:a};if(t)return{status:"planned",detail:a};let m=$(e,["mcp","list"],6e4),u=m.ok?m.out.split(`
9
+ `):[],f=u.find(v=>/^[\s|│┃]*ozmoz(?![\w@-])/.test(v)),p=u.some(v=>/^\s*(?:fleetbo|ozmoz):\s/.test(v));if(f&&f.includes("ozmoz@latest"))return{status:"unchanged",legacy:p};if(f&&!$(e,l).ok)return{status:"manual",detail:e+" "+l.join(" ")+" && "+a,legacy:p};let h=$(e,o);return h.ok?{status:f?"updated":"created",legacy:p}:{status:"failed",detail:a,message:h.out.trim().split(`
10
+ `).slice(-2).join(" "),legacy:p}}function Ee(e){let t={user:!1,local:!1,others:[]};try{let r=JSON.parse(i.readFileSync(c.join(b.homedir(),".claude.json"),"utf8")),n=a=>!!a&&typeof a=="object"&&/ozmoz|ozmoz/.test(String(a.command||"")+" "+JSON.stringify(a.args||[])),s=(a,m)=>{!a||typeof a!="object"||Object.keys(a).forEach(u=>{u===k?t[m]=!0:n(a[u])&&t.others.push({name:u,where:m})})};s(r.mcpServers,"user");let o=e;try{o=i.realpathSync(e)}catch{}let l=r.projects||{};Array.from(new Set([e,o])).forEach(a=>s((l[a]||{}).mcpServers,"local"))}catch{}return t}function we(e){let t=Ee(e);t.user&&d(" \u26A0\uFE0F A global (user-scope) '"+k+"' entry from a previous version also exists: the tools appear in every project. To keep them in OZmoz projects only: claude mcp remove "+k+" --scope user"),t.local&&d(" \u26A0\uFE0F A local-scope '"+k+"' entry exists for this folder and takes precedence over .mcp.json. Remove it: claude mcp remove "+k+" --scope local"),t.others.forEach(r=>{d(" \u26A0\uFE0F An old MCP entry named '"+r.name+"' ("+r.where+" scope) points to OZmoz/OZmoz. Remove it: claude mcp remove "+r.name+" --scope "+r.where)})}function be(e){let t=b.homedir(),r=n=>i.existsSync(n);return{claude:R("claude")||r(c.join(t,".claude")),cursor:r(c.join(e,".cursor"))||r(c.join(t,".cursor"))||R("cursor"),windsurf:r(c.join(t,".codeium","windsurf"))||r(c.join(e,".windsurf")),devin:r(c.join(e,".devin")),codex:R("codex")||r(c.join(t,".codex")),gemini:R("gemini")||r(c.join(t,".gemini")),antigravity:R("agy")||r(c.join(t,".antigravity"))||r(c.join(e,".antigravity")),copilot:R("copilot")||r(c.join(t,".copilot"))}}var Te={claude:{bin:"claude",launch:e=>[e]},gemini:{bin:"gemini",launch:e=>["-i",e]},codex:{bin:"codex",launch:e=>[e]},antigravity:{bin:"agy",launch:e=>["-i",e]}};function Ae(e){return String(e||"").replace(/[^\p{L}\p{N} '.,:\-_]/gu," ").replace(/\s+/g," ").trim().slice(0,4e3)}function Ce(e,t,r){let n=Ae(t),s=n?`The user already provided their project description and technical choices: "${n}".
11
11
  - Check if the framework (e.g. React, Vue) is already specified.
12
12
  - If it is, DO NOT ask a generic "what tech do you want" question. Acknowledge their choice naturally (e.g. "J'ai bien not\xE9 que vous souhaitez utiliser React...") and only ask for the missing precision (TypeScript vs JavaScript) in a single friendly confirmation, or proceed directly if obvious.
13
- - Once the user answers, do NOT run exploratory bash commands. IMMEDIATELY call the MCP tool 'oz_create_project' with the application name.`:"Ask me the starter questions from your OZmoz instructions before installing anything: the technology first, then a one-sentence project description, one question at a time.",o=null;try{let u=c.join(s,".env");if(r.existsSync(u)){let m=r.readFileSync(u,"utf8").match(/^\s*OZ_DB_KEY\s*=\s*(.+?)\s*$/m);m&&(o=m[1].trim())}}catch{}let l=r.existsSync(c.join(s,"svro.schema.json")),a=r.existsSync(c.join(s,"index.html"))||r.existsSync(c.join(s,"package.json")),p=o||l?"This folder ALREADY contains an OZmoz project"+(o?" (OZ_DB_KEY="+o+")":"")+" \u2014 the required key is already given above, so do NOT read .env or svro.schema.json yourself under any circumstance, even to verify or double-check. Do NOT call oz_create_project, and do NOT ask the starter questions (technology/description). State this in one plain sentence to the user \u2014 then ask what I want to work on now.":a?'This folder does NOT have an OZmoz project yet, but a frontend project ALREADY exists here \u2014 do NOT run "npm create vite" or scaffold a new frontend. Skip the technology question and ask me only for a one-sentence project description, then call oz_create_project directly.':"This folder does NOT contain an OZmoz project yet (no .env, no svro.schema.json). "+i;return"Use OZmoz as the backend of my app. You are in the project folder ("+s+"). Follow your OZmoz local instructions (do NOT run bash commands or web searches to inspect instruction files, they are already active). "+p}function Ce(){let e=process.env;if(e.CLAUDECODE==="1"||e.GEMINI_CLI||e.CODEX_CLI||e.AI_AGENT||e.CURSOR_AGENT||e.ANTIGRAVITY_CLI)return!0;if(process.platform==="win32")return!1;try{let t=j("ps",["-A","-o","pid=,ppid=,args="],{encoding:"utf8"});if(t.status!==0)return!1;let s=new Map;t.stdout.split(`
14
- `).forEach(i=>{let o=i.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);o&&s.set(Number(o[1]),{ppid:Number(o[2]),args:o[3]})});let n=process.ppid;for(let i=0;n>1&&i<20&&s.has(n);i++){let{ppid:o,args:l}=s.get(n);if(l.split(/\s+/).slice(0,2).some(p=>/(^|\/)(gemini|claude|codex|antigravity|agy)$/.test(p))||/@google\/gemini-cli|@anthropic-ai\/claude-code|@openai\/codex/.test(l))return!0;n=o}}catch{}return!1}function ke(e){let t=process.platform==="win32"?"where":"which";return j(t,[e],{stdio:"ignore"}).status===0}function Ae(e,t){let s=t.slice(1).filter(m=>!m.startsWith("--")),n=(s[0]||"").toLowerCase(),i=s.slice(1).join(" "),o=we[n];o||(y('Usage: npx ozmoz start <claude|gemini|codex> ["your app idea"]'),y('Cursor, Windsurf, Devin and GitHub Copilot have no terminal agent to launch: run "npx ozmoz mcp --agent=<cursor|windsurf|devin|copilot>" instead.'),process.exit(1));let l=!1;try{l=!!JSON.parse(r.readFileSync(c.join(w.homedir(),".fleetbo","credentials.json"),"utf8")).devToken}catch{}l||(d("[OZmoz] First use on this machine: sign in (your browser opens, approve once)."),j(process.execPath,[__filename,"login"],{stdio:"inherit",cwd:e,env:Object.assign({},process.env,{FLEETBO_START:"1"})}).status!==0&&(y('Sign-in did not complete. Run "npx ozmoz start '+n+'" again.'),process.exit(1))),j(process.execPath,[__filename,"mcp","--agent="+n],{stdio:"inherit",cwd:e,env:Object.assign({},process.env,{FLEETBO_START:"1"})}).status!==0&&(y("Could not configure "+o.bin+'. Run "npx ozmoz mcp --agent='+n+'" to see why.'),process.exit(1)),Ce()&&(d(`
15
- [OZmoz] OZmoz is set up in this folder (instruction file + MCP server).`),d("[OZmoz] You are already inside an AI agent's shell, so no second agent is launched."),d('[OZmoz] NEXT: tell the user, in plain words, to quit this agent and start it again in this folder (or to run "npx -y ozmoz@latest start '+n+`" in a normal terminal), then to paste the message again. Do not run any other command.
16
- `),process.exit(0)),ke(o.bin)||(y('"'+o.bin+'" is not installed or not in your PATH. Install it, then run: npx ozmoz start '+n),process.exit(1));let p=xe(o.rules,i,e);d(`
13
+ - Once the user answers, do NOT run exploratory bash commands. IMMEDIATELY call the MCP tool 'oz_create_project' with the application name.`:"Ask me the starter questions from your OZmoz instructions before installing anything: the technology first, then a one-sentence project description, one question at a time.",o=null,l=!0;try{let p=c.join(r,".env");if(i.existsSync(p)){let h=i.readFileSync(p,"utf8"),v=h.match(/^\s*OZ_DB_KEY\s*=\s*(.+?)\s*$/m);v&&(o=v[1].trim());let y=h.match(/^\s*OZ_PROTOTYPE\s*=\s*(.+?)\s*$/m);y&&(l=y[1].trim().toLowerCase()==="true")}}catch{}let a=i.existsSync(c.join(r,"svro.schema.json")),m=i.existsSync(c.join(r,"index.html"))||i.existsSync(c.join(r,"package.json")),u=l?"OZ_PROTOTYPE=true (mode essai / local sandbox)":"OZ_PROTOTYPE=false (mode r\xE9el / live database)",f=o||a?"This folder ALREADY contains an OZmoz project (OZ_DB_KEY="+o+", "+u+"). Do NOT call oz_create_project, and do NOT ask the starter questions. State this in one plain sentence to the user \u2014 then ask what I want to work on now.":m?'This folder does NOT have an OZmoz project yet, but a frontend project ALREADY exists here \u2014 do NOT run "npm create vite" or scaffold a new frontend. Skip the technology question and ask me only for a one-sentence project description, then call oz_create_project directly.':"This folder does NOT contain an OZmoz project yet (no .env, no svro.schema.json). "+s;return"Use OZmoz as the backend of my app. You are in the project folder ("+r+"). Follow your OZmoz local instructions (do NOT run bash commands or web searches to inspect instruction files, they are already active). "+f}function Ie(){let e=process.env;if(e.CLAUDECODE==="1"||e.GEMINI_CLI||e.CODEX_CLI||e.AI_AGENT||e.CURSOR_AGENT||e.ANTIGRAVITY_CLI)return!0;if(process.platform==="win32")return!1;try{let t=x("ps",["-A","-o","pid=,ppid=,args="],{encoding:"utf8"});if(t.status!==0)return!1;let r=new Map;t.stdout.split(`
14
+ `).forEach(s=>{let o=s.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);o&&r.set(Number(o[1]),{ppid:Number(o[2]),args:o[3]})});let n=process.ppid;for(let s=0;n>1&&s<20&&r.has(n);s++){let{ppid:o,args:l}=r.get(n);if(l.split(/\s+/).slice(0,2).some(m=>/(^|\/)(gemini|claude|codex|antigravity|agy)$/.test(m))||/@google\/gemini-cli|@anthropic-ai\/claude-code|@openai\/codex/.test(l))return!0;n=o}}catch{}return!1}function ke(e){let t=process.platform==="win32"?"where":"which";return x(t,[e],{stdio:"ignore"}).status===0}function xe(e,t){let r=t.slice(1).filter(f=>!f.startsWith("--")),n=(r[0]||"").toLowerCase(),s=r.slice(1).join(" "),o=Te[n];o||(O('Usage: npx ozmoz start <claude|gemini|codex> ["your app idea"]'),O('Cursor, Windsurf, Devin and GitHub Copilot have no terminal agent to launch: run "npx ozmoz mcp --agent=<cursor|windsurf|devin|copilot>" instead.'),process.exit(1));let l=!1;try{l=!!JSON.parse(i.readFileSync(c.join(b.homedir(),".fleetbo","credentials.json"),"utf8")).devToken}catch{}l||(d("[OZmoz] First use on this machine: sign in (your browser opens, approve once)."),x(process.execPath,[__filename,"login"],{stdio:"inherit",cwd:e,env:Object.assign({},process.env,{FLEETBO_START:"1"})}).status!==0&&(O('Sign-in did not complete. Run "npx ozmoz start '+n+'" again.'),process.exit(1))),x(process.execPath,[__filename,"mcp","--agent="+n],{stdio:"inherit",cwd:e,env:Object.assign({},process.env,{FLEETBO_START:"1"})}).status!==0&&(O("Could not configure "+o.bin+'. Run "npx ozmoz mcp --agent='+n+'" to see why.'),process.exit(1)),Ie()&&(d(`
15
+ [OZmoz] OZmoz is set up in this folder (instruction file + MCP server).
16
+ `),process.exit(0)),ke(o.bin)||(O('"'+o.bin+'" is not installed or not in your PATH. Install it, then run: npx ozmoz start '+n),process.exit(1));let m=Ce(o.rules,s,e);d(`
17
17
  [OZmoz] Launching `+o.bin+` in this folder...
18
- `);let u=j(o.bin,o.launch(process.platform==="win32"?'"'+p+'"':p),{stdio:"inherit",cwd:e,shell:process.platform==="win32"});process.exit(u.status===null?1:u.status)}async function ee(e,t){let s=t.includes("--dry-run"),n=t.find(h=>h.startsWith("--agent=")),i=n&&n.slice(8).trim()?n.slice(8).split(",").map(h=>h.trim().toLowerCase()).filter(Boolean):null,o=null;if(i){o=i.includes("all")?Object.keys(R):i;let h=o.filter(E=>!R[E]);h.length&&(y("Unknown agent(s): "+h.join(", ")+". Valid values: "+Object.keys(R).join(", ")+", all."),process.exit(1))}let l=t.find(h=>h.startsWith("--scope=")),a=l?l.slice(8).trim().toLowerCase():"project";["project","user","local"].includes(a)||(y("Unknown scope: "+a+". Valid values for Claude Code: project (default), user, local."),process.exit(1));let p=Te(e),u=o||Object.keys(R).filter(h=>p[h]),m=fe();d(`
19
- [OZmoz] Configuring your AI agents`+(s?" (dry run: nothing is written)":"")+"...");let f=await X(),g=f.version||m,v=`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
18
+ `);let u=x(o.bin,o.launch(process.platform==="win32"?'"'+m+'"':m),{stdio:"inherit",cwd:e,shell:process.platform==="win32"});process.exit(u.status===null?1:u.status)}async function ee(e,t){let r=t.includes("--dry-run"),n=t.find(g=>g.startsWith("--agent=")),s=n&&n.slice(8).trim()?n.slice(8).split(",").map(g=>g.trim().toLowerCase()).filter(Boolean):null,o=null;if(s){o=s.includes("all")?Object.keys(F):s;let g=o.filter(E=>!F[E]);g.length&&(O("Unknown agent(s): "+g.join(", ")+". Valid values: "+Object.keys(F).join(", ")+", all."),process.exit(1))}let l=t.find(g=>g.startsWith("--scope=")),a=l?l.slice(8).trim().toLowerCase():"project";["project","user","local"].includes(a)||(O("Unknown scope: "+a+". Valid values for Claude Code: project (default), user, local."),process.exit(1));let m=be(e),u=o||Object.keys(F).filter(g=>m[g]),f=he();d(`
19
+ [OZmoz] Configuring your AI agents`+(r?" (dry run: nothing is written)":"")+"...");let p=await X(),h=p.version||f,v=`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
20
20
 
21
- `+(f.directives||f.guidelines||"")+`
21
+ `+(p.directives||p.guidelines||"")+`
22
22
 
23
23
  ## PROTOCOLE DONN\xC9ES : QUI FAIT QUOI (AGENT FRONTEND \u2194 ALEX AI)
24
24
 
25
- `+(f.protocol||""),O=V(g,v),S=[["AGENTS.md",O],["GEMINI.md",O],["CLAUDE.md",V(g,`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
26
- @AGENTS.md`)]],z=c.join(e,".cursorrules");if(r.existsSync(z)){let h=r.readFileSync(z,"utf8");(J.test(h)||h.includes(H))&&S.push([".cursorrules",O])}for(let h of S)d("\u2192 "+h[0]+": "+D[ze(c.join(e,h[0]),h[1],s)]);for(let h of u){let E=R[h];if(h==="cursor")d("\u2192 "+E+" MCP (.cursor/mcp.json): "+D[Z(c.join(e,".cursor","mcp.json"),s)]);else if(h==="windsurf")d("\u2192 "+E+" MCP (~/.codeium/windsurf/mcp_config.json): "+D[Z(c.join(w.homedir(),".codeium","windsurf","mcp_config.json"),s)]);else if(h==="copilot")d("\u2192 "+E+" MCP (~/.copilot/mcp-config.json): "+D[Z(c.join(w.homedir(),".copilot","mcp-config.json"),s,{type:"local",tools:["*"]})]);else if(h==="claude"&&a==="project"){let b=Z(c.join(e,".mcp.json"),s);d("\u2192 "+E+" MCP (.mcp.json, project scope): "+D[b]),(b==="created"||b==="updated")&&d(" Claude Code asks you to approve a project server the first time you launch it. Commit .mcp.json to share it with your team (it contains no token)."),Ee(e)}else if(h==="gemini"){let b=[c.join(w.homedir(),".gemini","settings.json"),c.join(e,".gemini","settings.json"),c.join(e,".mcp.json")],T="unchanged";b.forEach($=>{let I=Z($,s);(I==="created"||I==="updated")&&(T=I)}),d("\u2192 "+E+" MCP (settings.json & .mcp.json): "+D[T])}else if(h==="claude"||h==="codex"||h==="antigravity"){let b=h==="antigravity"?"agy":h,T=Se(b,s,a);T.status==="manual"?d("\u2192 "+E+": '"+b+"' not found or not scriptable. Run manually: "+T.detail):T.status==="planned"?d("\u2192 "+E+" MCP: would run: "+T.detail):T.status==="failed"?y("\u2192 "+E+" MCP: registration failed ("+T.message+"). Run manually: "+T.detail):d("\u2192 "+E+" MCP"+(h==="claude"?" ("+a+" scope)":"")+": "+D[T.status]),T.legacy&&d(" \u26A0\uFE0F An old MCP entry named 'fleetbo' exists. Remove it: "+b+" mcp remove fleetbo")}else h==="devin"&&d("\u2192 "+E+": reads AGENTS.md. Devin runs in its own environment: add the Fleetbo MCP server from Devin's settings (not automated).")}!o&&u.length===0&&d("\u2192 No agent detected: instruction files were written; re-run with --agent=<name> to register the MCP server.");let C=!!(U(e).FLEETBO_DEV_TOKEN||process.env.FLEETBO_DEV_TOKEN),N=c.join(w.homedir(),".fleetbo","credentials.json");if(r.existsSync(N))try{C=C||!!JSON.parse(r.readFileSync(N,"utf8")).devToken}catch{}C||y('\u26A0\uFE0F No developer token found. Run "npx ozmoz login" once.'),process.env.FLEETBO_START||d(`
27
- [OZmoz] Done. Restart your agent so it reloads the tools and instruction files.
28
- `)}function je(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";oe(`${t} "${e}"`)}function _e(e){return new Promise((t,s)=>{let n=ne.createServer((i,o)=>{if(o.setHeader("Access-Control-Allow-Origin","*"),o.setHeader("Access-Control-Allow-Methods","GET, OPTIONS"),o.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),o.setHeader("Access-Control-Allow-Private-Network","true"),i.method==="OPTIONS"){o.writeHead(204),o.end();return}let l=new URL(i.url,"http://127.0.0.1");if(l.pathname==="/callback"){let a=l.searchParams.get("token"),p=l.searchParams.get("refresh");if(!a){o.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),o.end("<h3>Error: Missing token.</h3>");return}let u=c.join(w.homedir(),".fleetbo");r.existsSync(u)||r.mkdirSync(u,{recursive:!0}),r.writeFileSync(c.join(u,"credentials.json"),JSON.stringify({devToken:a,refreshToken:p||null,updatedAt:new Date().toISOString()},null,2));let m=c.join(e,".env");if(r.existsSync(m)){let f=r.readFileSync(m,"utf8");f.includes("FLEETBO_DEV_TOKEN=")?f=f.replace(/FLEETBO_DEV_TOKEN=.*/g,`FLEETBO_DEV_TOKEN=${a}`):f+=`
25
+ `+(p.protocol||""),y=G(h,v),S=[["AGENTS.md",y],["GEMINI.md",y],["CLAUDE.md",G(h,`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
26
+ @AGENTS.md`)]],z=c.join(e,".cursorrules");if(i.existsSync(z)){let g=i.readFileSync(z,"utf8");(V.test(g)||g.includes(H))&&S.push([".cursorrules",y])}for(let g of S)d("\u2192 "+g[0]+": "+P[ve(c.join(e,g[0]),g[1],r)]);for(let g of u){let E=F[g];if(g==="cursor")d("\u2192 "+E+" MCP (.cursor/mcp.json): "+P[U(c.join(e,".cursor","mcp.json"),r)]);else if(g==="windsurf")d("\u2192 "+E+" MCP (~/.codeium/windsurf/mcp_config.json): "+P[U(c.join(b.homedir(),".codeium","windsurf","mcp_config.json"),r)]);else if(g==="copilot")d("\u2192 "+E+" MCP (~/.copilot/mcp-config.json): "+P[U(c.join(b.homedir(),".copilot","mcp-config.json"),r,{type:"local",tools:["*"]})]);else if(g==="claude"&&a==="project"){let T=U(c.join(e,".mcp.json"),r);d("\u2192 "+E+" MCP (.mcp.json, project scope): "+P[T]),(T==="created"||T==="updated")&&d(" Claude Code asks you to approve a project server the first time you launch it. Commit .mcp.json to share it with your team (it contains no token)."),we(e)}else if(g==="gemini"){let T=[c.join(b.homedir(),".gemini","settings.json"),c.join(e,".gemini","settings.json"),c.join(e,".mcp.json")],w="unchanged";T.forEach(B=>{let D=U(B,r);(D==="created"||D==="updated")&&(w=D)}),d("\u2192 "+E+" MCP (settings.json & .mcp.json): "+P[w])}else if(g==="claude"||g==="codex"||g==="antigravity"){let T=g==="antigravity"?"agy":g,w=Se(T,r,a);w.status==="manual"?d("\u2192 "+E+": '"+T+"' not found or not scriptable. Run manually: "+w.detail):w.status==="planned"?d("\u2192 "+E+" MCP: would run: "+w.detail):w.status==="failed"?O("\u2192 "+E+" MCP: registration failed ("+w.message+"). Run manually: "+w.detail):d("\u2192 "+E+" MCP"+(g==="claude"?" ("+a+" scope)":"")+": "+P[w.status]),w.legacy&&d(" \u26A0\uFE0F An old MCP entry named 'fleetbo' exists. Remove it: "+T+" mcp remove fleetbo")}else g==="devin"&&d("\u2192 "+E+": reads AGENTS.md. Devin runs in its own environment: add the OZmoz MCP server from Devin's settings (not automated).")}!o&&u.length===0&&d("\u2192 No agent detected: instruction files were written; re-run with --agent=<name> to register the MCP server.");let C=!!(Z(e).FLEETBO_DEV_TOKEN||process.env.FLEETBO_DEV_TOKEN),j=c.join(b.homedir(),".fleetbo","credentials.json");if(i.existsSync(j))try{C=C||!!JSON.parse(i.readFileSync(j,"utf8")).devToken}catch{}C||O('\u26A0\uFE0F No developer token found. Run "npx ozmoz login" once.'),process.env.FLEETBO_START||d(`
27
+ [OZmoz] Done.
28
+ `)}function Ne(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";oe(`${t} "${e}"`)}function je(e){return new Promise((t,r)=>{let n=ne.createServer((s,o)=>{if(o.setHeader("Access-Control-Allow-Origin","*"),o.setHeader("Access-Control-Allow-Methods","GET, OPTIONS"),o.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),o.setHeader("Access-Control-Allow-Private-Network","true"),s.method==="OPTIONS"){o.writeHead(204),o.end();return}let l=new URL(s.url,"http://127.0.0.1");if(l.pathname==="/callback"){let a=l.searchParams.get("token"),m=l.searchParams.get("refresh");if(!a){o.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),o.end("<h3>Error: Missing token.</h3>");return}let u=c.join(b.homedir(),".fleetbo");i.existsSync(u)||i.mkdirSync(u,{recursive:!0}),i.writeFileSync(c.join(u,"credentials.json"),JSON.stringify({devToken:a,refreshToken:m||null,updatedAt:new Date().toISOString()},null,2));let f=c.join(e,".env");if(i.existsSync(f)){let p=i.readFileSync(f,"utf8");p.includes("FLEETBO_DEV_TOKEN=")?p=p.replace(/FLEETBO_DEV_TOKEN=.*/g,`FLEETBO_DEV_TOKEN=${a}`):p+=`
29
29
  FLEETBO_DEV_TOKEN=${a}
30
- `,r.writeFileSync(m,f,"utf8")}o.writeHead(200,{"Content-Type":"text/html; charset=utf-8",Connection:"close"}),o.end(`
30
+ `,i.writeFileSync(f,p,"utf8")}o.writeHead(200,{"Content-Type":"text/html; charset=utf-8",Connection:"close"}),o.end(`
31
31
  <!DOCTYPE html>
32
32
  <html>
33
33
  <head>
@@ -46,27 +46,27 @@ FLEETBO_DEV_TOKEN=${a}
46
46
  </body>
47
47
  </html>
48
48
  `),d(`
49
- [OZmoz] Developer token received and stored successfully!`),!process.env.FLEETBO_START&&!["AGENTS.md","CLAUDE.md","GEMINI.md"].some(f=>r.existsSync(c.join(e,f)))&&(d(`
49
+ [OZmoz] Developer token received and stored successfully!`),!process.env.FLEETBO_START&&!["AGENTS.md","CLAUDE.md","GEMINI.md"].some(p=>i.existsSync(c.join(e,p)))&&(d(`
50
50
  Next step to connect your AI agents:`),d(` npx ozmoz mcp (Configure Claude Code, Cursor, Windsurf, Devin, Codex CLI, Gemini CLI, Antigravity CLI, GitHub Copilot)
51
51
  `)),typeof n.closeAllConnections=="function"&&n.closeAllConnections(),n.close(()=>t()),setTimeout(()=>t(),300)}});n.listen(0,"127.0.0.1",()=>{let o=`https://ozmoz.io/cli-auth?port=${n.address().port}`;d(`
52
- [OZmoz] Waiting for authentication...`),d(`If your browser does not open automatically, visit: ${o}`),je(o);let l=Number(process.env.FLEETBO_LOGIN_TIMEOUT_MS)||12e4;setTimeout(()=>{try{typeof n.closeAllConnections=="function"&&n.closeAllConnections()}catch{}n.close(),s(new Error(`Login timed out after ${Math.round(l/1e3)}s: browser approval not received. Run "npx ozmoz login" once more and approve in the browser.`))},l).unref()}),n.on("error",i=>s(i))})}function Ne(e,t,s){return new Promise((n,i)=>{let o=JSON.stringify({enterpriseID:e,schema:t,workflow:s}),l={hostname:"fleetbo-gatekeeper.fleetbo.workers.dev",path:"/sync-schema",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(o)}},a=W.request(l,p=>{let u="";p.on("data",m=>{u+=m}),p.on("end",()=>{p.statusCode>=200&&p.statusCode<300?n(JSON.parse(u)):i(new Error(`Edge sync failed with HTTP ${p.statusCode}`))})});a.on("error",p=>i(p)),a.write(o),a.end()})}function U(e){let t=c.join(e,".env");if(!r.existsSync(t))return{};let s=r.readFileSync(t,"utf8"),n={};return s.split(`
53
- `).forEach(i=>{let[o,...l]=i.split("=");o&&l.length>0&&(n[o.trim()]=l.join("=").trim())}),n}function G(e,t){return new Promise((s,n)=>{let i=JSON.stringify({projectId:e,moduleName:t}),o={hostname:"getmodulecache-jqycakhlxa-uc.a.run.app",path:"/",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(i)}},l=W.request(o,a=>{let p="";a.on("data",u=>{p+=u}),a.on("end",()=>{if(a.statusCode>=200&&a.statusCode<300)try{let u=JSON.parse(p);if(u.success&&u.found&&u.module){let m=u.module.code||u.module.mockCode;s(typeof m=="string"?JSON.parse(m):m)}else s(null)}catch{n(new Error(`Invalid JSON response for ${t}.`))}else n(new Error(`Server error ${a.statusCode} while fetching ${t}`))})});l.on("error",a=>n(a)),l.write(i),l.end()})}var x=process.argv.slice(2),k=x[0],Ie=["id","_id","userId","author","dateCreated","createdAt","_schema_version"],te=e=>Ie.includes(e)||/^_/.test(e)||/^(created|updated|modified|deleted)(At|By)$/i.test(e);function M(e){return!e||typeof e!="object"?null:e.fields&&typeof e.fields=="object"?e.fields:e.schema&&typeof e.schema=="object"?e.schema:null}function Pe(e){let t=[];if(!e||typeof e!="object"||!e.collections)return{schema:e,changed:!1,notes:t};let s=JSON.parse(JSON.stringify(e));return Object.entries(s.collections).forEach(([n,i])=>{let o=M(i);o&&Object.keys(o).forEach(l=>{te(l)&&o[l]&&typeof o[l]=="object"&&o[l].required===!0&&(o[l].required=!1,t.push(n+"."+l))})}),{schema:s,changed:t.length>0,notes:t}}function De(e){let t=String(typeof e=="string"?e:e&&e.type||"").toLowerCase(),s=e&&(e.enum||e.values||e.options);return Array.isArray(s)&&s.length?JSON.stringify(s[0]):t==="number"||t==="integer"||t==="float"?"0":t==="boolean"||t==="toggle"?"false":t==="date"||t==="datetime"||t==="timestamp"?"new Date().toISOString()":t==="reference"?"'<id du document li\xE9>'":t==="media"?"null /* image/fichier : oz.addWithMedia */":t==="array"?"[]":"'\u2026'"}function Fe(e){let s=Object.entries(e&&e.collections||{}),n=`## \u{1F4E5} CE QUE LE CODE DOIT ENVOYER (MOD\xC8LES D'\xC9CRITURE)
52
+ [OZmoz] Waiting for authentication...`),d(`If your browser does not open automatically, visit: ${o}`),Ne(o);let l=Number(process.env.FLEETBO_LOGIN_TIMEOUT_MS)||12e4;setTimeout(()=>{try{typeof n.closeAllConnections=="function"&&n.closeAllConnections()}catch{}n.close(),r(new Error(`Login timed out after ${Math.round(l/1e3)}s: browser approval not received. Run "npx ozmoz login" once more and approve in the browser.`))},l).unref()}),n.on("error",s=>r(s))})}function De(e,t,r){return new Promise((n,s)=>{let o=JSON.stringify({enterpriseID:e,schema:t,workflow:r}),l={hostname:"fleetbo-gatekeeper.fleetbo.workers.dev",path:"/sync-schema",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(o)}},a=W.request(l,m=>{let u="";m.on("data",f=>{u+=f}),m.on("end",()=>{m.statusCode>=200&&m.statusCode<300?n(JSON.parse(u)):s(new Error(`Edge sync failed with HTTP ${m.statusCode}`))})});a.on("error",m=>s(m)),a.write(o),a.end()})}function Z(e){let t=c.join(e,".env");if(!i.existsSync(t))return{};let r=i.readFileSync(t,"utf8"),n={};return r.split(`
53
+ `).forEach(s=>{let[o,...l]=s.split("=");o&&l.length>0&&(n[o.trim()]=l.join("=").trim())}),n}function J(e,t){return new Promise((r,n)=>{let s=JSON.stringify({projectId:e,moduleName:t}),o={hostname:"getmodulecache-jqycakhlxa-uc.a.run.app",path:"/",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(s)}},l=W.request(o,a=>{let m="";a.on("data",u=>{m+=u}),a.on("end",()=>{if(a.statusCode>=200&&a.statusCode<300)try{let u=JSON.parse(m);if(u.success&&u.found&&u.module){let f=u.module.code||u.module.mockCode;r(typeof f=="string"?JSON.parse(f):f)}else r(null)}catch{n(new Error(`Invalid JSON response for ${t}.`))}else n(new Error(`Server error ${a.statusCode} while fetching ${t}`))})});l.on("error",a=>n(a)),l.write(s),l.end()})}var A=process.argv.slice(2),I=A[0],_e=["id","_id","userId","author","dateCreated","createdAt","_schema_version"],te=e=>_e.includes(e)||/^_/.test(e)||/^(created|updated|modified|deleted)(At|By)$/i.test(e);function M(e){return!e||typeof e!="object"?null:e.fields&&typeof e.fields=="object"?e.fields:e.schema&&typeof e.schema=="object"?e.schema:null}function Pe(e){let t=[];if(!e||typeof e!="object"||!e.collections)return{schema:e,changed:!1,notes:t};let r=JSON.parse(JSON.stringify(e));return Object.entries(r.collections).forEach(([n,s])=>{let o=M(s);o&&Object.keys(o).forEach(l=>{te(l)&&o[l]&&typeof o[l]=="object"&&o[l].required===!0&&(o[l].required=!1,t.push(n+"."+l))})}),{schema:r,changed:t.length>0,notes:t}}function Re(e){let t=String(typeof e=="string"?e:e&&e.type||"").toLowerCase(),r=e&&(e.enum||e.values||e.options);return Array.isArray(r)&&r.length?JSON.stringify(r[0]):t==="number"||t==="integer"||t==="float"?"0":t==="boolean"||t==="toggle"?"false":t==="date"||t==="datetime"||t==="timestamp"?"new Date().toISOString()":t==="reference"?"'<id du document li\xE9>'":t==="media"?"null /* image/fichier : oz.addWithMedia */":t==="array"?"[]":"'\u2026'"}function Le(e){let r=Object.entries(e&&e.collections||{}),n=`## \u{1F4E5} CE QUE LE CODE DOIT ENVOYER (MOD\xC8LES D'\xC9CRITURE)
54
54
 
55
55
  `;n+=`### \u{1F194} Identifiants
56
- `,n+="* OZmoz attribue lui-m\xEAme `_id` (cha\xEEne) \xE0 chaque document. Utilise `doc._id` partout ; \xE0 la lecture, `doc.id` existe comme alias de `_id` (m\xEAme valeur), en prototype comme en production, mais la r\xE9f\xE9rence est `_id`.\n",n+="* N'envoie **jamais** `id` ni `_id` dans `oz.add` : `oz.add` renvoie `{ success, documentId }` (`documentId` = `_id`).\n",n+="* Pour lire, modifier ou supprimer un document : `oz.getDoc(table, doc._id)`, `oz.update(table, doc._id, {\u2026})`, `oz.delete(table, doc._id)`. Pour relier deux collections, stocke le `_id` du document li\xE9 dans un champ (ex. `playlistId`).\n",n+="* `userId`, `createdAt` et les autres champs de tra\xE7abilit\xE9 sont renseign\xE9s par le moteur : ne les envoie pas.\n\n";let i=s.filter(([,o])=>M(o)&&Object.keys(M(o)).length>0);return i.length===0?n+`_Aucune collection scell\xE9e pour l'instant : les mod\xE8les appara\xEEtront apr\xE8s la mod\xE9lisation d'Alex._
57
- `:(i.forEach(([o,l])=>{let a=M(l),p=Object.entries(a).filter(([f])=>!te(f));n+="### `"+o+`\`
56
+ `,n+="* OZmoz attribue lui-m\xEAme `_id` (cha\xEEne) \xE0 chaque document. Utilise `doc._id` partout ; \xE0 la lecture, `doc.id` existe comme alias de `_id` (m\xEAme valeur), en prototype comme en production, mais la r\xE9f\xE9rence est `_id`.\n",n+="* N'envoie **jamais** `id` ni `_id` dans `oz.add` : `oz.add` renvoie `{ success, documentId }` (`documentId` = `_id`).\n",n+="* Pour lire, modifier ou supprimer un document : `oz.getDoc(table, doc._id)`, `oz.update(table, doc._id, {\u2026})`, `oz.delete(table, doc._id)`. Pour relier deux collections, stocke le `_id` du document li\xE9 dans un champ (ex. `playlistId`).\n",n+="* `userId`, `createdAt` et les autres champs de tra\xE7abilit\xE9 sont renseign\xE9s par le moteur : ne les envoie pas.\n\n";let s=r.filter(([,o])=>M(o)&&Object.keys(M(o)).length>0);return s.length===0?n+`_Aucune collection scell\xE9e pour l'instant : les mod\xE8les appara\xEEtront apr\xE8s la mod\xE9lisation d'Alex._
57
+ `:(s.forEach(([o,l])=>{let a=M(l),m=Object.entries(a).filter(([p])=>!te(p));n+="### `"+o+`\`
58
58
 
59
59
  | Champ | Type | Obligatoire | Valeurs / remarques |
60
60
  |---|---|---|---|
61
- `,p.forEach(([f,g])=>{let v=typeof g=="string"?g:g&&g.type||"any",O=g&&(g.enum||g.values||g.options),S=Array.isArray(O)&&O.length?"parmi : "+O.map(z=>"`"+z+"`").join(", "):"";n+="| `"+f+"` | "+v+" | "+(g&&g.required===!0?"\u2705 oui":"non")+" | "+S+` |
62
- `});let u=p.filter(([,f])=>f&&f.required===!0),m=p.filter(([,f])=>!(f&&f.required===!0));n+="\nInsertion valide :\n```js\nawait oz.add('"+o+`', {
63
- `,u.forEach(([f,g])=>{n+=" "+f+": "+De(g)+`,
64
- `}),m.length&&(n+=" // optionnels : "+m.map(([f])=>f).join(", ")+`
61
+ `,m.forEach(([p,h])=>{let v=typeof h=="string"?h:h&&h.type||"any",y=h&&(h.enum||h.values||h.options),S=Array.isArray(y)&&y.length?"parmi : "+y.map(z=>"`"+z+"`").join(", "):"";n+="| `"+p+"` | "+v+" | "+(h&&h.required===!0?"\u2705 oui":"non")+" | "+S+` |
62
+ `});let u=m.filter(([,p])=>p&&p.required===!0),f=m.filter(([,p])=>!(p&&p.required===!0));n+="\nInsertion valide :\n```js\nawait oz.add('"+o+`', {
63
+ `,u.forEach(([p,h])=>{n+=" "+p+": "+Re(h)+`,
64
+ `}),f.length&&(n+=" // optionnels : "+f.map(([p])=>p).join(", ")+`
65
65
  `),n+=`}, {
66
66
  `,n+=" desc: 'Cr\xE9ation d\\'un \xE9l\xE9ment dans "+o+`',
67
67
  `,n+=` role: 'AUTHENTICATED' // ou 'ANONYMOUS', 'ADMIN'
68
68
  `,n+=` // guard: 'condition sur les donn\xE9es' (optionnel)
69
- `,n+="});\n```\n\n"}),n)}function Le(e,t,s=""){let n=e?.context||t?.context||"No written specifications provided.";return`# THE OZMOZ DATA CONTRACT (SVRO DATA CONTRACT)
69
+ `,n+="});\n```\n\n"}),n)}function Fe(e,t,r=""){let n=e?.context||t?.context||"No written specifications provided.";return`# THE OZMOZ DATA CONTRACT (SVRO DATA CONTRACT)
70
70
 
71
71
  ### \u{1F6A8} MANDATORY CODE RULES (READ BEFORE WRITING ANY VIEW)
72
72
  1. **Identifiers:** the database generates \`_id\` (string) for each document. Use \`doc._id\` for \`key={doc._id}\`, for \`oz.getDoc/update/delete\`, and to link two collections (store the linked document's \`_id\` in a field, e.g., \`playlistId\`). \`doc.id\` exists on read as an alias (same value), but the canonical reference is \`_id\`.
@@ -80,6 +80,77 @@ Next step to connect your AI agents:`),d(` npx ozmoz mcp (Configure Claude C
80
80
  6. **Display:** for any field that can be empty or requires formatting, use exclusively native \`<oz-*>\` tags.
81
81
  ---
82
82
 
83
+ ### \u{1F3AF} OZMOZ SDK DECISION MATRIX
84
+ | Application Need | Official SDK Solution | STRICTLY FORBIDDEN |
85
+ |---|---|---|
86
+ | Create / Insert document | \`const res = await oz.add('table', data, { desc, role, guard })\` | Inventing \`fetch('/api/table', { method: 'POST' })\` |
87
+ | Update document | \`const res = await oz.update('table', id, data, { desc, role, guard })\` | Inventing \`fetch('/api/table/' + id, { method: 'PUT' })\` |
88
+ | Delete document | \`const res = await oz.delete('table', id, { desc, role })\` | Inventing \`fetch('/api/table/' + id, { method: 'DELETE' })\` |
89
+ | Read all documents (global) | \`const list = await oz.getDocsG('table', { desc, role })\` | Inventing \`fetch('/api/table')\` |
90
+ | Read user-owned documents | \`const list = await oz.getDocsU('table', { desc, role })\` | Manually filtering the global array on client side |
91
+ | Read single document | \`const doc = await oz.getDoc('table', id, { desc, role })\` | Inventing a single-item REST endpoint |
92
+ | Create with file / image | \`const res = await oz.addWithMedia('table', data, fileBase64, fileName, { desc, role })\` | Storing raw Base64 strings in DB fields |
93
+ | Relational join | \`const res = await oz.join('table', options, { desc, role })\` | Writing nested \`getDoc\` loops |
94
+ | Sign-out session | \`await oz.logout()\` | Calling non-existent \`oz.signOut()\` |
95
+ | 3rd-party APIs (Stripe, Weather) | \`fetch('https://api.stripe.com/...')\` | Allowed exclusively for external services |
96
+
97
+
98
+ ### \u{1F510} AUTHENTICATION ENGINE (PASSWORDLESS OTP, PHONE & SSO)
99
+
100
+ OZmoz automatically attaches an anonymous session on initial load 8, 10, 13]. NEVER check \`oz.getUser() !== null\` to verify if a user is logged in 13].
101
+
102
+ #### 1. Check Authentication Status
103
+ \`\`\`javascript
104
+ // Verify active authenticated session (returns true only for real signed-in users)
105
+ const isLogged = Boolean(await oz.isAuthenticated());
106
+
107
+ // Current auth user info ({ uid, email, isAnonymous })
108
+ const currentUser = await oz.getUser();
109
+
110
+ // Complete user document profile fetched from the database
111
+ const userProfile = await oz.getAuthUser();
112
+ \`\`\`
113
+
114
+ #### 2. Email OTP Authentication (Passwordless)
115
+ \`\`\`javascript
116
+ // Step 1: Send OTP code (In trial mode OZ_PROTOTYPE=true, code "0000" always succeeds)
117
+ await oz.sendotpsvro('user@example.com');
118
+
119
+ // Optional branded format
120
+ await oz.sendotpsvro({
121
+ email: 'user@example.com',
122
+ appName: 'My App',
123
+ subject: 'Your login verification code',
124
+ message: 'Here is your one-time verification code:'
125
+ });
126
+
127
+ // Step 2: Verify OTP code & establish session
128
+ const authRes = await oz.verifyotpsvro('user@example.com', '123456');
129
+ if (authRes.success) {
130
+ console.log('Signed-in user:', authRes.user);
131
+ }
132
+ \`\`\`
133
+
134
+ #### 3. Phone OTP Authentication (SMS)
135
+ \`\`\`javascript
136
+ // Step 1: Send OTP via SMS (E.164 international format required)
137
+ await oz.sendOtpByPhone('+12025550123');
138
+
139
+ // Step 2: Verify SMS OTP code
140
+ const phoneAuth = await oz.verifyOtpPhoneSvro('+12025550123', '123456');
141
+ if (phoneAuth.success) {
142
+ console.log('Phone user authenticated:', phoneAuth.user);
143
+ }
144
+ \`\`\`
145
+
146
+
147
+ #### 5. Session Termination (Sign-Out)
148
+ \`\`\`javascript
149
+ // Official SDK method to log out (cleanly reverts to anonymous session)
150
+ await oz.logout();
151
+ // ABSOLUTELY FORBIDDEN: never call oz.signOut() (it does not exist).
152
+ \`\`\`
153
+
83
154
  This document constitutes the **Official Specifications and Bilateral Integrity Contract** binding client code (developer or AI agent) and the OZmoz SVRO Data OS engine.
84
155
 
85
156
  ### Why do we call it a "Contract"?
@@ -91,6 +162,355 @@ This document constitutes the **Official Specifications and Bilateral Integrity
91
162
 
92
163
  ---
93
164
 
165
+ ### \u{1F6E1}\uFE0F DYNAMIC REBAC ACCESS CONTROL (oz.acl) & CLOUD RUN ROUTER (oz.call)
166
+
167
+ #### 1. Dynamic Relationship-Based Access Control (ReBAC)
168
+ Verify, grant, or revoke fine-grained runtime permissions on specific collections and document IDs.
169
+
170
+ \`\`\`javascript
171
+ // Check if the current authenticated user has permission to perform an action ('read' | 'write' | 'delete')
172
+ const canEdit = await oz.acl.can('write', 'documents', doc._id);
173
+ if (!canEdit) {
174
+ console.warn('Access denied: current user cannot modify this document.');
175
+ }
176
+
177
+ // Grant granular access on a document to a specific target user
178
+ await oz.acl.grant(targetUserId, 'write', 'documents', doc._id);
179
+
180
+ // Revoke previously granted access from a user
181
+ await oz.acl.revoke(targetUserId, 'write', 'documents', doc._id);
182
+ \`\`\`
183
+
184
+ #### 2. Serverless Edge Functions (oz.call)
185
+ Execute secure background computation, sensitive workflows, or 3rd-party integrations (e.g. Stripe checkout, batch tasks) using the dynamic \`oz.call\` proxy 8, 12].
186
+
187
+ \`\`\`javascript
188
+ // Invocates an isolated cloud function '$processCheckout' (registered via oz_publish_function)
189
+ const response = await oz.call.processCheckout({
190
+ orderId: 'order_abc123',
191
+ amount: 49.99
192
+ });
193
+
194
+ if (response.success) {
195
+ console.log('Function executed successfully:', response.data);
196
+ } else {
197
+ console.error('Execution error:', response.error);
198
+ }
199
+ \`\`\`
200
+
201
+ ---
202
+
203
+ ### \u{1F4E6} ADVANCED MUTATIONS & RELATIONAL QUERIES (oz.join)
204
+
205
+ #### 1. File & Media Uploads (oz.addWithMedia)
206
+ Upload images, PDFs, or media directly to Cloud Storage with automatic compression and optimization (Sharp) 6, 8]. The resulting URL is automatically mapped into \`mediaUrl\` / \`image\` 6, 8].
207
+
208
+ \`\`\`javascript
209
+ // data: document payload
210
+ // fileBase64: base64-encoded string ('data:image/png;base64,...')
211
+ // fileName: original filename with extension ('avatar.png')
212
+ const res = await oz.addWithMedia('users', {
213
+ fullName: 'Alexandre Dupont'
214
+ }, base64Data, 'profile.png', {
215
+ desc: 'User registration with profile avatar upload',
216
+ role: 'ANONYMOUS'
217
+ });
218
+
219
+ if (res.success) {
220
+ console.log('Document created with ID:', res.id);
221
+ console.log('Public CDN Media URL:', res.mediaUrl);
222
+ }
223
+ \`\`\`
224
+
225
+ #### 2. Upsert with Deterministic Document ID (oz.addWithId & oz.addWithUserId)
226
+ Use when an entity must possess a specific or pre-determined unique key 8, 9].
227
+
228
+ \`\`\`javascript
229
+ // A. Custom string ID (e.g. settings, singletons, slugs)
230
+ const res = await oz.addWithId('configurations', {
231
+ maintenanceMode: false,
232
+ allowedRegistrations: true
233
+ }, 'global_settings', {
234
+ desc: 'Save global system configuration',
235
+ role: 'ADMIN'
236
+ });
237
+
238
+ // B. Bind document ID strictly to the current user's UID (1:1 user profile pattern)
239
+ const profileRes = await oz.addWithUserId('profiles', {
240
+ bio: 'Fullstack developer & vibe-coder',
241
+ theme: 'dark'
242
+ }, {
243
+ desc: 'Create or update authenticated user profile',
244
+ role: 'AUTHENTICATED'
245
+ });
246
+ \`\`\`
247
+
248
+ #### 3. Serverless Relational Join (oz.join)
249
+ Perform atomic MongoDB aggregation lookups between collections without writing custom backend endpoints or nested loops 6, 8].
250
+
251
+ \`\`\`javascript
252
+ // Fetch orders and dynamically join the related user record
253
+ const ordersWithCustomers = await oz.join('orders', {
254
+ innerJoin: {
255
+ collection: 'users', // Target collection to join
256
+ on: ['userId', '==', '_id'], // Local field vs Foreign field
257
+ as: 'customer', // Output property name
258
+ select: ['fullName', 'email'] // Optional field projection
259
+ }
260
+ }, {
261
+ desc: 'Retrieve customer orders with populated buyer details',
262
+ role: 'STAFF'
263
+ });
264
+ \`\`\`
265
+
266
+ ---
267
+
268
+ ### \u{1F3D7}\uFE0F CANONICAL CRUD BLUEPRINTS (REACT & VUE 3)
269
+
270
+ #### Golden Rules for Components:
271
+ 1. **Canonical Identifier:** Always resolve and target documents by \`_id\` (e.g. \`item._id\`).
272
+ 2. **Explicit Type Casting:** Always convert form strings to target schema types (\`Number(val)\`, \`String(val).trim()\`, \`Boolean(val)\`) 12].
273
+ 3. **Inspect Mutation Returns:** Always check \`if (!res.success)\` after mutations 12, 14].
274
+ 4. **Defensive UI Tags:** Use \`<oz-*>\` tags with fallbacks instead of raw template interpolations 12, 14].
275
+
276
+ ---
277
+
278
+ #### 1. Complete React Blueprint
279
+
280
+ \`\`\`javascript
281
+ import React, { useState, useEffect } from 'react';
282
+
283
+ export default function ProductsModule() {
284
+ const [items, setItems] = useState([]);
285
+ const [formData, setFormData] = useState({ name: '', price: '' });
286
+ const [loading, setLoading] = useState(true);
287
+ const [submitting, setSubmitting] = useState(false);
288
+
289
+ const fetchItems = async () => {
290
+ try {
291
+ const data = await oz.getDocsG('products', {
292
+ desc: 'Retrieve active product catalog',
293
+ role: 'AUTHENTICATED'
294
+ });
295
+ setItems(Array.isArray(data) ? data : []);
296
+ } catch (error) {
297
+ console.error('[OZmoz Read Error]:', error);
298
+ setItems([]);
299
+ } finally {
300
+ setLoading(false);
301
+ }
302
+ };
303
+
304
+ useEffect(() => {
305
+ fetchItems();
306
+ }, []);
307
+
308
+ const handleCreate = async (e) => {
309
+ e.preventDefault();
310
+ if (!formData.name || !formData.price) return;
311
+
312
+ setSubmitting(true);
313
+ try {
314
+ const res = await oz.add('products', {
315
+ name: String(formData.name).trim(),
316
+ price: Number(formData.price)
317
+ }, {
318
+ desc: 'Create new catalog item',
319
+ guard: 'price > 0 && name.length > 0',
320
+ role: 'MANAGER'
321
+ });
322
+
323
+ if (!res.success) {
324
+ console.error('[OZmoz Edge Rejection]:', res.error);
325
+ return;
326
+ }
327
+
328
+ setFormData({ name: '', price: '' });
329
+ await fetchItems();
330
+ } catch (error) {
331
+ console.error('[OZmoz Write Error]:', error);
332
+ } finally {
333
+ setSubmitting(false);
334
+ }
335
+ };
336
+
337
+ const handleUpdatePrice = async (docId, currentPrice) => {
338
+ try {
339
+ const newPrice = Number((currentPrice + 1.00).toFixed(2));
340
+ const res = await oz.update('products', docId, { price: newPrice }, {
341
+ desc: 'Increment product price by 1 unit',
342
+ guard: 'price > 0',
343
+ role: 'MANAGER'
344
+ });
345
+
346
+ if (!res.success) {
347
+ console.error('[OZmoz Update Error]:', res.error);
348
+ return;
349
+ }
350
+ await fetchItems();
351
+ } catch (error) {
352
+ console.error('[OZmoz Update Error]:', error);
353
+ }
354
+ };
355
+
356
+ const handleDelete = async (docId) => {
357
+ try {
358
+ const res = await oz.delete('products', docId, {
359
+ desc: 'Delete product entry',
360
+ role: 'MANAGER'
361
+ });
362
+
363
+ if (!res.success) {
364
+ console.error('[OZmoz Delete Error]:', res.error);
365
+ return;
366
+ }
367
+ await fetchItems();
368
+ } catch (error) {
369
+ console.error('[OZmoz Delete Error]:', error);
370
+ }
371
+ };
372
+
373
+ if (loading) return <div>Loading records...</div>;
374
+
375
+ return (
376
+ <div>
377
+ <form onSubmit={handleCreate}>
378
+ <input
379
+ type="text"
380
+ value={formData.name}
381
+ onChange={(e) => setFormData({ ...formData, name: e.target.value })}
382
+ placeholder="Product name"
383
+ required
384
+ />
385
+ <input
386
+ type="number"
387
+ step="0.01"
388
+ value={formData.price}
389
+ onChange={(e) => setFormData({ ...formData, price: e.target.value })}
390
+ placeholder="Price"
391
+ required
392
+ />
393
+ <button type="submit" disabled={submitting}>
394
+ {submitting ? 'Adding...' : 'Create'}
395
+ </button>
396
+ </form>
397
+
398
+ <ul>
399
+ {items.map((item) => (
400
+ <li key={item._id}>
401
+ <oz-text value={item.name} fallback="Unnamed" /> \u2014{' '}
402
+ <oz-number value={item.price} currency="EUR" invalid-fallback="0" />
403
+ <button onClick={() => handleUpdatePrice(item._id, item.price)}>+1\u20AC</button>
404
+ <button onClick={() => handleDelete(item._id)}>Delete</button>
405
+ </li>
406
+ ))}
407
+ </ul>
408
+ </div>
409
+ );
410
+ }
411
+ \`\`\`
412
+
413
+ ---
414
+
415
+ #### 2. Complete Vue 3 Blueprint (\`<script setup>\`)
416
+
417
+ \`\`\`vue
418
+ <script setup>
419
+ import { ref, onMounted } from 'vue';
420
+
421
+ const items = ref([]);
422
+ const formData = ref({ name: '', price: '' });
423
+ const loading = ref(true);
424
+ const submitting = ref(false);
425
+
426
+ const fetchItems = async () => {
427
+ try {
428
+ const data = await oz.getDocsG('products', {
429
+ desc: 'Retrieve active product catalog',
430
+ role: 'AUTHENTICATED'
431
+ });
432
+ items.value = Array.isArray(data) ? data : [];
433
+ } catch (error) {
434
+ console.error('[OZmoz Read Error]:', error);
435
+ items.value = [];
436
+ } finally {
437
+ loading.value = false;
438
+ }
439
+ };
440
+
441
+ onMounted(fetchItems);
442
+
443
+ const handleCreate = async () => {
444
+ if (!formData.value.name || !formData.value.price) return;
445
+
446
+ submitting.value = true;
447
+ try {
448
+ const res = await oz.add('products', {
449
+ name: String(formData.value.name).trim(),
450
+ price: Number(formData.value.price)
451
+ }, {
452
+ desc: 'Create new catalog item',
453
+ guard: 'price > 0 && name.length > 0',
454
+ role: 'MANAGER'
455
+ });
456
+
457
+ if (!res.success) {
458
+ console.error('[OZmoz Edge Rejection]:', res.error);
459
+ return;
460
+ }
461
+
462
+ formData.value = { name: '', price: '' };
463
+ await fetchItems();
464
+ } catch (error) {
465
+ console.error('[OZmoz Write Error]:', error);
466
+ } finally {
467
+ submitting.value = false;
468
+ }
469
+ };
470
+
471
+ const handleDelete = async (docId) => {
472
+ try {
473
+ const res = await oz.delete('products', docId, {
474
+ desc: 'Delete product entry',
475
+ role: 'MANAGER'
476
+ });
477
+
478
+ if (!res.success) {
479
+ console.error('[OZmoz Delete Error]:', res.error);
480
+ return;
481
+ }
482
+ await fetchItems();
483
+ } catch (error) {
484
+ console.error('[OZmoz Delete Error]:', error);
485
+ }
486
+ };
487
+ </script>
488
+
489
+ <template>
490
+ <div v-if="loading">Loading records...</div>
491
+ <div v-else>
492
+ <form @submit.prevent="handleCreate">
493
+ <input v-model="formData.name" type="text" placeholder="Product name" required />
494
+ <input v-model="formData.price" type="number" step="0.01" placeholder="Price" required />
495
+ <button type="submit" :disabled="submitting">{{ submitting ? 'Adding...' : 'Create' }}</button>
496
+ </form>
497
+
498
+ <ul>
499
+ <li v-for="item in items" :key="item._id">
500
+ <oz-text :value="item.name" fallback="Unnamed" /> \u2014
501
+ <oz-number :value="item.price" currency="EUR" invalid-fallback="0" />
502
+ <button @click="handleDelete(item._id)">Delete</button>
503
+ </li>
504
+ </ul>
505
+ </div>
506
+ </template>
507
+ \`\`\`
508
+
509
+ ---
510
+
511
+
512
+
513
+
94
514
  ### \u{1F7E2} THE MASTER SWITCH: OZ_PROTOTYPE (ZERO-REWRITE PATTERN)
95
515
 
96
516
  #### 1. If OZ_PROTOTYPE=true (PROTOTYPE MODE & UX VALIDATION)
@@ -107,7 +527,7 @@ This document constitutes the **Official Specifications and Bilateral Integrity
107
527
  ---
108
528
 
109
529
  ### \u{1F9ED} DATA PROTOCOL: WHO DOES WHAT (FRONTEND AGENT \u2194 ALEX AI)
110
- ${s}
530
+ ${r}
111
531
 
112
532
  ---
113
533
 
@@ -193,7 +613,7 @@ ${n}
193
613
 
194
614
  ---
195
615
 
196
- ${Fe(e)}
616
+ ${Le(e)}
197
617
 
198
618
  ---
199
619
 
@@ -208,27 +628,27 @@ ${JSON.stringify(e||{},null,2)}
208
628
  \`\`\`json
209
629
  ${JSON.stringify(t||{},null,2)}
210
630
  \`\`\`
211
- `}function Re(e){return String(e).toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[^a-z0-9]/g,"_").replace(/^_+|_+$/g,"").slice(0,30)||"app"}async function Ze(e,t){let s=U(e),n=r.existsSync(c.join(e,"svro.schema.json"));(s.OZ_DB_KEY||n)&&(y("Cannot create project: an OZmoz project already exists in this folder."),d('\u2192 Use "npx ozmoz sync" or evolve the existing contract instead.'),process.exit(1));let i=(t||"").trim();i||(y('Project name is required. Usage: npx ozmoz create "<name>"'),process.exit(1));let o=c.join(e,".ozmoz.lock");if(r.existsSync(o)){let a=!1;try{let p=Number(r.readFileSync(o,"utf8"));Date.now()-p>6e4&&(a=!0)}catch{a=!0}a||(y("A project creation is already running in this folder."),process.exit(1)),r.unlinkSync(o)}r.writeFileSync(o,String(Date.now()));let l=()=>{if(r.existsSync(o))try{r.unlinkSync(o)}catch{}};try{let a=process.env.FLEETBO_DEV_TOKEN;if(!a){let O=c.join(w.homedir(),".fleetbo","credentials.json");if(r.existsSync(O))try{a=JSON.parse(r.readFileSync(O,"utf8")).devToken}catch{}}a||(l(),y('Missing developer token. Please run "npx ozmoz login" first.'),process.exit(1)),d(`[OZmoz] Creating project "${i}" on Cloud...`);let p=Re(i),u=[p,`${p.slice(0,24)}_${Math.random().toString(36).slice(2,6)}`,`${p.slice(0,24)}_${Math.random().toString(36).slice(2,6)}`],m=null,f=null;for(let O of u)try{let S=await fetch("https://createprojectlight-jqycakhlxa-uc.a.run.app",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${a}`},body:JSON.stringify({data:{name:i,keyApp:O}})}),z=await S.json();if(S.ok&&!z.error){m={keyApp:O,data:z.result?.data||z.data||{}};break}else f=z.error?.message||`HTTP ${S.status}`}catch(S){f=S.message}m||(l(),y(`Failed to create project on Cloud: ${f||"Unknown error"}`),process.exit(1));let g=m.data.bootstrapToken;await q(e,[`--keyApp=${m.keyApp}`,`--token=${g}`]);let v=c.join(e,"package.json");K(e,v),await ee(e,[]),d(`
212
- [OZmoz] Project "${i}" (${m.keyApp}) created and configured successfully.`),d(`Next step: scaffold the frontend if needed, then run "npx ozmoz sync".
213
- `)}finally{if(r.existsSync(o))try{r.unlinkSync(o)}catch{}}}async function Me(e){let t=process.env.FLEETBO_DEV_TOKEN;if(!t){let O=c.join(w.homedir(),".fleetbo","credentials.json");if(r.existsSync(O))try{t=JSON.parse(r.readFileSync(O,"utf8")).devToken}catch{}}let n=U(e).OZ_KEY_APP;(!n||!t)&&(y("Cannot update: project uninitialized or dev token missing."),process.exit(1));let i=r.existsSync(c.join(e,"src"))?c.join(e,"src"):e,o=new Set([".jsx",".tsx",".vue",".svelte",".js",".ts",".html"]),l=[],a=0;function p(O){let S=[];try{S=r.readdirSync(O,{withFileTypes:!0})}catch{return}for(let z of S){if(/^(node_modules|\.git|dist|build|\.next|\.svelte-kit)$/.test(z.name))continue;let _=c.join(O,z.name);if(z.isDirectory())p(_);else if(o.has(c.extname(z.name))&&!z.name.endsWith(".d.ts"))try{let C=r.statSync(_);if(C.size>3e5)continue;let N=r.readFileSync(_,"utf8");/oz\.|<oz-/i.test(N)&&(a+=C.size,l.push({name:c.relative(e,_).split(c.sep).join("/"),content:N}))}catch{}}}p(i),l.length===0&&(y("Cannot update: no components using oz.* found."),process.exit(1)),a>8*1024*1024&&(y("Payload too large: total UI source files exceed 8 MB limit."),process.exit(1));let u=x.find(O=>O.startsWith("--rules=")),m=u?u.slice(8).trim():"",f=x.find(O=>O.startsWith("--reasoning=")),g=f?f.slice(12).trim().toLowerCase():void 0;g!=="standard"&&g!=="high"&&(y("Missing or invalid --reasoning=<standard|high>."),y("If you are an AI agent: ask the user which analysis depth they want (numbered [1]/[2] choice, recommended option first) before running this command, then pass --reasoning=standard or --reasoning=high accordingly. Never pick it yourself."),process.exit(1)),d(`[OZmoz] Sending ${l.length} component(s) to Cloud Engine for modeling...`);try{let O=await fetch("https://updateprojectlight-jqycakhlxa-uc.a.run.app",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({data:{keyApp:n,name:n,newViewFiles:l,fleetbo_rules:m,reasoning:g}})}),S=await O.json();(!O.ok||S.error)&&(y(`Update failed: ${S.error?.message||S.message||"Server error"}`),process.exit(1))}catch(O){y(`Network error: ${O.message}`),process.exit(1)}d("\u2192 Structure modeled. Sealing into SVRO Kernel..."),j(process.execPath,[__filename,"sync"],{stdio:"inherit",cwd:e}).status===0?d(`
631
+ `}function Ue(e){return String(e).toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[^a-z0-9]/g,"_").replace(/^_+|_+$/g,"").slice(0,30)||"app"}async function Me(e,t){let r=Z(e),n=i.existsSync(c.join(e,"svro.schema.json"));(r.OZ_DB_KEY||n)&&(O("Cannot create project: an OZmoz project already exists in this folder."),d('\u2192 Use "npx ozmoz sync" or evolve the existing contract instead.'),process.exit(1));let s=(t||"").trim();s||(O('Project name is required. Usage: npx ozmoz create "<name>"'),process.exit(1));let o=c.join(e,".ozmoz.lock");if(i.existsSync(o)){let a=!1;try{let m=Number(i.readFileSync(o,"utf8"));Date.now()-m>6e4&&(a=!0)}catch{a=!0}a||(O("A project creation is already running in this folder."),process.exit(1)),i.unlinkSync(o)}i.writeFileSync(o,String(Date.now()));let l=()=>{if(i.existsSync(o))try{i.unlinkSync(o)}catch{}};try{let a=process.env.FLEETBO_DEV_TOKEN;if(!a){let y=c.join(b.homedir(),".fleetbo","credentials.json");if(i.existsSync(y))try{a=JSON.parse(i.readFileSync(y,"utf8")).devToken}catch{}}a||(l(),O('Missing developer token. Please run "npx ozmoz login" first.'),process.exit(1)),d(`[OZmoz] Creating project "${s}" on Cloud...`);let m=Ue(s),u=[m,`${m.slice(0,24)}_${Math.random().toString(36).slice(2,6)}`,`${m.slice(0,24)}_${Math.random().toString(36).slice(2,6)}`],f=null,p=null;for(let y of u)try{let S=await fetch("https://createprojectlight-jqycakhlxa-uc.a.run.app",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${a}`},body:JSON.stringify({data:{name:s,keyApp:y}})}),z=await S.json();if(S.ok&&!z.error){f={keyApp:y,data:z.result?.data||z.data||{}};break}else p=z.error?.message||`HTTP ${S.status}`}catch(S){p=S.message}f||(l(),O(`Failed to create project on Cloud: ${p||"Unknown error"}`),process.exit(1));let h=f.data.bootstrapToken;await K(e,[`--keyApp=${f.keyApp}`,`--token=${h}`]);let v=c.join(e,"package.json");Y(e,v),await ee(e,[]),d(`
632
+ [OZmoz] Project "${s}" (${f.keyApp}) created and configured successfully.`),d(`Next step: scaffold the frontend if needed, then run "npx ozmoz sync".
633
+ `)}finally{if(i.existsSync(o))try{i.unlinkSync(o)}catch{}}}async function Ze(e){let t=process.env.FLEETBO_DEV_TOKEN;if(!t){let y=c.join(b.homedir(),".fleetbo","credentials.json");if(i.existsSync(y))try{t=JSON.parse(i.readFileSync(y,"utf8")).devToken}catch{}}let n=Z(e).OZ_KEY_APP;(!n||!t)&&(O("Cannot update: project uninitialized or dev token missing."),process.exit(1));let s=i.existsSync(c.join(e,"src"))?c.join(e,"src"):e,o=new Set([".jsx",".tsx",".vue",".svelte",".js",".ts",".html"]),l=[],a=0;function m(y){let S=[];try{S=i.readdirSync(y,{withFileTypes:!0})}catch{return}for(let z of S){if(/^(node_modules|\.git|dist|build|\.next|\.svelte-kit)$/.test(z.name))continue;let N=c.join(y,z.name);if(z.isDirectory())m(N);else if(o.has(c.extname(z.name))&&!z.name.endsWith(".d.ts"))try{let C=i.statSync(N);if(C.size>3e5)continue;let j=i.readFileSync(N,"utf8");/oz\.|<oz-/i.test(j)&&(a+=C.size,l.push({name:c.relative(e,N).split(c.sep).join("/"),content:j}))}catch{}}}m(s),l.length===0&&(O("Cannot update: no components using oz.* found."),process.exit(1)),a>8*1024*1024&&(O("Payload too large: total UI source files exceed 8 MB limit."),process.exit(1));let u=A.find(y=>y.startsWith("--rules=")),f=u?u.slice(8).trim():"",p=A.find(y=>y.startsWith("--reasoning=")),h=p?p.slice(12).trim().toLowerCase():void 0;h!=="standard"&&h!=="high"&&(O("Missing or invalid --reasoning=<standard|high>."),O("If you are an AI agent: ask the user which analysis depth they want (numbered [1]/[2] choice, recommended option first) before running this command, then pass --reasoning=standard or --reasoning=high accordingly. Never pick it yourself."),process.exit(1)),d(`[OZmoz] Sending ${l.length} component(s) to Cloud Engine for modeling...`);try{let y=await fetch("https://updateprojectlight-jqycakhlxa-uc.a.run.app",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({data:{keyApp:n,name:n,newViewFiles:l,oz_rules:f,reasoning:h}})}),S=await y.json();(!y.ok||S.error)&&(O(`Update failed: ${S.error?.message||S.message||"Server error"}`),process.exit(1))}catch(y){O(`Network error: ${y.message}`),process.exit(1)}d("\u2192 Structure modeled. Sealing into SVRO Kernel..."),x(process.execPath,[__filename,"sync"],{stdio:"inherit",cwd:e}).status===0?d(`
214
634
  [OZmoz] Contract successfully locked into SVRO Kernel.
215
- `):(y(`
635
+ `):(O(`
216
636
  [OZmoz] Kernel sync failed. Run "npx ozmoz sync" manually.
217
- `),process.exit(1))}async function Ue(){let e=process.cwd(),t=c.join(e,"package.json");if(k==="init"||k==="doctor")d(`
218
- [OZmoz] Initializing and configuring OZmoz...`),await q(e,x),K(e,t),d(`
637
+ `),process.exit(1))}async function Be(){let e=process.cwd(),t=c.join(e,"package.json");if(I==="init"||I==="doctor")d(`
638
+ [OZmoz] Initializing and configuring OZmoz...`),await K(e,A),Y(e,t),d(`
219
639
  [OZmoz] Configuration completed successfully!
220
640
  `),d(`
221
641
  Next step:`),d(` npx ozmoz sync (Sync cloud schema & generate IDE types)
222
- `);else if(k==="sync"){let s=x.includes("--dry-run"),n=x.includes("--check-only");d(`[OZmoz] Syncing schema...${s?" (dry-run)":""}${n?" (check-only, no network)":""}`),s||le(e);let i=c.join(e,"svro.schema.json"),o=c.join(e,"svro.workflow.json"),l=c.join(e,"ozmoz_contract.md"),a=c.join(e,"src","ozmoz.d.ts"),u=U(e).OZ_ENTERPRISE_ID,m=null,f=null;if(n)d("\u2192 Mode check-only : Local contract used, no cloud fetch..");else if(u)try{d("\u2192 Fetching latest contracts from Cloud..."),m=await G(u,"svro.schema.json"),m&&(r.writeFileSync(i,JSON.stringify(m,null,2)+`
223
- `),d("\u2192 Local svro.schema.json updated.")),f=await G(u,"svro.workflow.json"),f&&(r.writeFileSync(o,JSON.stringify(f,null,2)+`
224
- `),d("\u2192 Local svro.workflow.json updated."))}catch(z){y(`\u26A0\uFE0F Cloud fetch bypassed: ${z.message}. Using local file fallback.`)}else y("\u26A0\uFE0F OZ_ENTERPRISE_ID missing in .env. Skipping cloud fetch.");let g=m;if(!g&&r.existsSync(i))try{g=JSON.parse(r.readFileSync(i,"utf8"))}catch{}g||(g={context:"Application en cours de mod\xE9lisation initiale.",collections:{}},r.writeFileSync(i,JSON.stringify(g,null,2)+`
225
- `,"utf8"),d("\u2192 Initial blank svro.schema.json created."));let v=f;if(!v&&r.existsSync(o))try{v=JSON.parse(r.readFileSync(o,"utf8"))}catch{}v||(v={actors:{},sequences:[]},r.writeFileSync(o,JSON.stringify(v,null,2)+`
226
- `,"utf8"),d("\u2192 Initial blank svro.workflow.json created."));{let z=Pe(g);z.changed&&(g=z.schema,r.writeFileSync(i,JSON.stringify(g,null,2)+`
227
- `,"utf8"),d("\u2192 Managed by system, no longer required from your code: "+z.notes.join(", ")+"."))}let{protocol:O}=await X(),S=Le(g,v,O);r.writeFileSync(l,S,"utf8"),d("\u2192 Contract markdown successfully generated at project root.");try{let z=Object.keys(g.collections||{});if(u&&!n)try{await Ne(u,g,v),d("\u2192 Schema successfully sealed into SVRO Kernel (O(1)).")}catch(h){y(`\u26A0\uFE0F Kernel Shield sync warning: ${h.message}`)}let _=g.collections||{},C=Object.entries(_).map(([h,E])=>{let b=E.fields||E.schema||{},T=Object.entries(b).map(([$,I])=>{let L="any",P=String(typeof I=="string"?I:I.type||"").toLowerCase();return P==="string"||P==="text"||P==="media"?L="string":P==="number"?L="number":P==="boolean"||P==="toggle"?L="boolean":P==="array"&&(L="any[]"),` ${$}?:${L};`}).join(`
228
- `);return` ${h}: {
229
- ${T}
642
+ `);else if(I==="sync"){let r=A.includes("--dry-run"),n=A.includes("--check-only");d(`[OZmoz] Syncing schema...${r?" (dry-run)":""}${n?" (check-only, no network)":""}`),r||le(e);let s=c.join(e,"svro.schema.json"),o=c.join(e,"svro.workflow.json"),l=c.join(e,"ozmoz_contract.md"),a=c.join(e,"src","ozmoz.d.ts"),u=Z(e).OZ_ENTERPRISE_ID,f=null,p=null;if(n)d("\u2192 Mode check-only : Local contract used, no cloud fetch..");else if(u)try{d("\u2192 Fetching latest contracts from Cloud..."),f=await J(u,"svro.schema.json"),f&&(i.writeFileSync(s,JSON.stringify(f,null,2)+`
643
+ `),d("\u2192 Local svro.schema.json updated.")),p=await J(u,"svro.workflow.json"),p&&(i.writeFileSync(o,JSON.stringify(p,null,2)+`
644
+ `),d("\u2192 Local svro.workflow.json updated."))}catch(z){O(`\u26A0\uFE0F Cloud fetch bypassed: ${z.message}. Using local file fallback.`)}else O("\u26A0\uFE0F OZ_ENTERPRISE_ID missing in .env. Skipping cloud fetch.");let h=f;if(!h&&i.existsSync(s))try{h=JSON.parse(i.readFileSync(s,"utf8"))}catch{}h||(h={context:"Application en cours de mod\xE9lisation initiale.",collections:{}},i.writeFileSync(s,JSON.stringify(h,null,2)+`
645
+ `,"utf8"),d("\u2192 Initial blank svro.schema.json created."));let v=p;if(!v&&i.existsSync(o))try{v=JSON.parse(i.readFileSync(o,"utf8"))}catch{}v||(v={actors:{},sequences:[]},i.writeFileSync(o,JSON.stringify(v,null,2)+`
646
+ `,"utf8"),d("\u2192 Initial blank svro.workflow.json created."));{let z=Pe(h);z.changed&&(h=z.schema,i.writeFileSync(s,JSON.stringify(h,null,2)+`
647
+ `,"utf8"),d("\u2192 Managed by system, no longer required from your code: "+z.notes.join(", ")+"."))}let{protocol:y}=await X(),S=Fe(h,v,y);i.writeFileSync(l,S,"utf8"),d("\u2192 Contract markdown successfully generated at project root.");try{let z=Object.keys(h.collections||{});if(u&&!n)try{await De(u,h,v),d("\u2192 Schema successfully sealed into SVRO Kernel (O(1)).")}catch(g){O(`\u26A0\uFE0F Kernel Shield sync warning: ${g.message}`)}let N=h.collections||{},C=Object.entries(N).map(([g,E])=>{let T=E.fields||E.schema||{},w=Object.entries(T).map(([B,D])=>{let L="any",_=String(typeof D=="string"?D:D.type||"").toLowerCase();return _==="string"||_==="text"||_==="media"?L="string":_==="number"?L="number":_==="boolean"||_==="toggle"?L="boolean":_==="array"&&(L="any[]"),` ${B}?:${L};`}).join(`
648
+ `);return` ${g}: {
649
+ ${w}
230
650
  };`}).join(`
231
- `),N=z.length>0?z.map(h=>`'${h}'`).join(" | "):"string";if(r.existsSync(c.dirname(a))){let h=`/* eslint-disable */
651
+ `),j=z.length>0?z.map(g=>`'${g}'`).join(" | "):"string";if(i.existsSync(c.dirname(a))){let g=`/* eslint-disable */
232
652
  /* prettier-ignore */
233
653
  // @ts-nocheck
234
654
  // Generated by OZmoz \u2014 Updated via sync
@@ -261,7 +681,7 @@ ${C}
261
681
  }
262
682
 
263
683
  declare global {
264
- type KnownOzTables = ${N};
684
+ type KnownOzTables = ${j};
265
685
  type OzTables = KnownOzTables | (string & { _ozPending?: never });
266
686
  type OzData<T extends string> = T extends KnownOzTables
267
687
  ? Partial<OzSchemaMap[T]>
@@ -364,7 +784,7 @@ declare module 'svelte/elements' {
364
784
  'oz-reference': OzProp;
365
785
  }
366
786
  }
367
- `;r.writeFileSync(a,h)}re(e),ae(e,t),ce(e),de(e),d(`[OZmoz] Schema synced successfully (${z.length} collection(s)).`),s&&d("\u2192 [Dry-run] Schema is valid.")}catch(z){y(`Error during synchronization: ${z.message}`),process.exit(1)}}else if(k==="create"){let s=x.slice(1).filter(n=>!n.startsWith("--")).join(" ");await Ze(e,s),process.exit(0)}else if(k==="update")await Me(e),process.exit(0);else if(k==="mcp"){let s=x.includes("--run"),n=!1;if(!s&&!process.stdin.isTTY&&(s=await new Promise(i=>{let o=process.stdin,l=null,a=m=>{clearTimeout(l),o.removeListener("data",p),o.removeListener("end",u),o.removeListener("error",u),i(m)},p=m=>{o.pause(),o.unshift(m),n=!0,a(!0)},u=()=>a(!1);l=setTimeout(()=>{o.pause(),a(!1)},1500),o.on("data",p),o.once("end",u),o.once("error",u)})),s){try{await import(`file://${Q()}`),n&&process.stdin.resume()}catch(i){y(`Failed to start MCP server: ${i.message}`),process.exit(1)}return}await ee(e,x),process.exit(0)}else k==="login"?(await _e(e),process.exit(0)):k==="start"?Ae(e,x):["--help","-h","help"].includes(k)?(d(`OZmoz CLI
787
+ `;i.writeFileSync(a,g)}ie(e),ae(e,t),ce(e),de(e),d(`[OZmoz] Schema synced successfully (${z.length} collection(s)).`),r&&d("\u2192 [Dry-run] Schema is valid.")}catch(z){O(`Error during synchronization: ${z.message}`),process.exit(1)}}else if(I==="create"){let r=A.slice(1).filter(n=>!n.startsWith("--")).join(" ");await Me(e,r),process.exit(0)}else if(I==="update")await Ze(e),process.exit(0);else if(I==="mcp"){let r=A.includes("--run"),n=!1;if(!r&&!process.stdin.isTTY&&(r=await new Promise(s=>{let o=process.stdin,l=null,a=f=>{clearTimeout(l),o.removeListener("data",m),o.removeListener("end",u),o.removeListener("error",u),s(f)},m=f=>{o.pause(),o.unshift(f),n=!0,a(!0)},u=()=>a(!1);l=setTimeout(()=>{o.pause(),a(!1)},1500),o.on("data",m),o.once("end",u),o.once("error",u)})),r){try{await import(`file://${Q()}`),n&&process.stdin.resume()}catch(s){O(`Failed to start MCP server: ${s.message}`),process.exit(1)}return}await ee(e,A),process.exit(0)}else I==="login"?(await je(e),process.exit(0)):I==="start"?xe(e,A):["--help","-h","help"].includes(I)?(d(`OZmoz CLI
368
788
 
369
789
  Commands:
370
790
  login Authenticate this machine (opens the browser: approve once, the command exits by itself)
@@ -380,4 +800,4 @@ Commands:
380
800
 
381
801
  AI agents: to create a project, call the MCP tool "oz_create_project".
382
802
  To evolve schema/workflow from UI files, call the MCP tool "oz_update_project", then run "sync".
383
- `),process.exit(0)):(y('Unknown command. Run "npx ozmoz --help".'),process.exit(1))}Ue().catch(e=>{y(`OZmoz CLI Error: ${e.message}`),process.exit(1)});
803
+ `),process.exit(0)):(O('Unknown command. Run "npx ozmoz --help".'),process.exit(1))}Be().catch(e=>{O(`OZmoz CLI Error: ${e.message}`),process.exit(1)});