ozmoz 0.1.41 → 0.1.43

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 s=require("fs"),a=require("path"),W=require("https"),oe=require("http"),A=require("os"),{exec:re,spawnSync:_}=require("child_process"),se=[a.join(__dirname,"..","scripts","setup-lib.cjs"),a.join(__dirname,"..","..","scripts","setup-lib.cjs"),a.join(__dirname,"scripts","setup-lib.cjs")],ie=se.find(s.existsSync)||a.join(__dirname,"..","scripts","setup-lib.cjs"),{runFullSetup:Y,handleAuthAndEnv:K,touchTsConfig:ae,attemptViteAutoImportPatch:ce,injectUniversalRuntime:le,writeBrowserConfig:de,patchAllowScripts:ue}=require(ie),me=!!(process.stdout&&process.stdout.isTTY&&typeof process.stdout.hasColors=="function"&&process.stdout.hasColors(16777216)),pe=me?"\x1B[38;2;15;156;140m":"\x1B[36m",fe="\x1B[31m",q="\x1B[0m";function u(e){console.log(e.replace(/OZmoz|\[|\]|→/g,t=>`${pe}${t}${q}`))}function y(e){console.error(`${fe}${e}${q}`)}var x="ozmoz",G=/<!--\s*(?:ozmoz|fleetbo|OZmoz):start[^>]*-->[\s\S]*?<!--\s*(?:ozmoz|fleetbo|OZmoz):end\s*-->/i,he="<!-- OZmoz:end -->",H="# OZMOZ DATA OS \u2014 DIRECTIVES SYST\xC8ME",M={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 ge(){try{return JSON.parse(s.readFileSync(a.join(__dirname,"..","package.json"),"utf8")).version||"dev"}catch{return"dev"}}var ye=Buffer.from("QUl6YVN5QUM1Uk94STNibklPMUR5TmZsTWhGUnJ0blItNDVwNFJF","base64").toString("utf8");function Oe(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 ze(e,t){let r=await fetch(`https://securetoken.googleapis.com/v1/token?key=${ye}`,{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?(s.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 X(){if(process.env.FLEETBO_DEV_TOKEN)return process.env.FLEETBO_DEV_TOKEN;try{let e=a.join(A.homedir(),".fleetbo","credentials.json");if(s.existsSync(e)){let t=JSON.parse(s.readFileSync(e,"utf8"));if(t.devToken&&!Oe(t.devToken))return t.devToken;if(t.refreshToken)try{let r=await ze(e,t.refreshToken);if(r)return r}catch{}}}catch{}return null}async function Q(){let e=a.join(A.homedir(),".fleetbo","guidelines.json"),t=await X();t||y('[OZmoz] Not logged in: run "npx ozmoz login" first to load the full instructions. Using local cache if available.');try{u("[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)y("[OZmoz] Cloud error HTTP "+r.status);else{let n=await r.json(),i=n.result?.data||n.result||n.data;if(i&&i.protocol&&i.directives)return u("[OZmoz] Instructions loaded successfully."),s.existsSync(a.dirname(e))||s.mkdirSync(a.dirname(e),{recursive:!0}),s.writeFileSync(e,JSON.stringify(i,null,2),"utf8"),i;y("[OZmoz] Empty Cloud response.")}}catch(r){y("[OZmoz] Network error: "+r.message)}if(s.existsSync(e)){u("[OZmoz] Using local cache (~/.fleetbo/guidelines.json)");try{return JSON.parse(s.readFileSync(e,"utf8"))}catch{}}return{protocol:"",directives:"",version:"1.0.0"}}function J(e,t){return"<!-- ozmoz:start v"+e+` -->
2
+ var i=require("fs"),a=require("path"),Y=require("https"),oe=require("http"),A=require("os"),{exec:re,spawnSync:N}=require("child_process"),se=[a.join(__dirname,"..","scripts","setup-lib.cjs"),a.join(__dirname,"..","..","scripts","setup-lib.cjs"),a.join(__dirname,"scripts","setup-lib.cjs")],ie=se.find(i.existsSync)||a.join(__dirname,"..","scripts","setup-lib.cjs"),{runFullSetup:K,handleAuthAndEnv:q,touchTsConfig:ae,attemptViteAutoImportPatch:ce,injectUniversalRuntime:le,writeBrowserConfig:de,patchAllowScripts:ue}=require(ie),me=!!(process.stdout&&process.stdout.isTTY&&typeof process.stdout.hasColors=="function"&&process.stdout.hasColors(16777216)),pe=me?"\x1B[38;2;15;156;140m":"\x1B[36m",fe="\x1B[31m",H="\x1B[0m";function u(e){console.log(e.replace(/OZmoz|\[|\]|→/g,t=>`${pe}${t}${H}`))}function y(e){console.error(`${fe}${e}${H}`)}var x="ozmoz",G=/<!--\s*(?:ozmoz|fleetbo|OZmoz):start[^>]*-->[\s\S]*?<!--\s*(?:ozmoz|fleetbo|OZmoz):end\s*-->/i,he="<!-- OZmoz:end -->",X="# OZMOZ DATA OS \u2014 DIRECTIVES SYST\xC8ME",M={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 ge(){try{return JSON.parse(i.readFileSync(a.join(__dirname,"..","package.json"),"utf8")).version||"dev"}catch{return"dev"}}var ye=Buffer.from("QUl6YVN5QUM1Uk94STNibklPMUR5TmZsTWhGUnJ0blItNDVwNFJF","base64").toString("utf8");function Oe(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 ze(e,t){let r=await fetch(`https://securetoken.googleapis.com/v1/token?key=${ye}`,{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 o=await r.json();return o.id_token?(i.writeFileSync(e,JSON.stringify({devToken:o.id_token,refreshToken:o.refresh_token||t,updatedAt:new Date().toISOString()},null,2)),o.id_token):null}async function J(){if(process.env.FLEETBO_DEV_TOKEN)return process.env.FLEETBO_DEV_TOKEN;try{let e=a.join(A.homedir(),".fleetbo","credentials.json");if(i.existsSync(e)){let t=JSON.parse(i.readFileSync(e,"utf8"));if(t.devToken&&!Oe(t.devToken))return t.devToken;if(t.refreshToken)try{let r=await ze(e,t.refreshToken);if(r)return r}catch{}}}catch{}return null}async function Q(){let e=a.join(A.homedir(),".fleetbo","guidelines.json"),t=await J();t||y('[OZmoz] Not logged in: run "npx ozmoz login" first to load the full instructions. Using local cache if available.');try{u("[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)y("[OZmoz] Cloud error HTTP "+r.status);else{let o=await r.json(),s=o.result?.data||o.result||o.data;if(s&&s.protocol&&s.directives)return u("[OZmoz] Instructions loaded successfully."),i.existsSync(a.dirname(e))||i.mkdirSync(a.dirname(e),{recursive:!0}),i.writeFileSync(e,JSON.stringify(s,null,2),"utf8"),s;y("[OZmoz] Empty Cloud response.")}}catch(r){y("[OZmoz] Network error: "+r.message)}if(i.existsSync(e)){u("[OZmoz] Using local cache (~/.fleetbo/guidelines.json)");try{return JSON.parse(i.readFileSync(e,"utf8"))}catch{}}return{protocol:"",directives:"",version:"1.0.0"}}function V(e,t){return"<!-- ozmoz:start v"+e+` -->
3
3
  `+t.trim()+`
4
4
  `+he+`
5
- `}function ve(e,t,r){let n=s.existsSync(e)?s.readFileSync(e,"utf8"):null,i,o;return n===null?(i="created",o=t):G.test(n)?(o=n.replace(G,()=>t.trimEnd()),i=o===n?"unchanged":"updated"):n.includes(H)?(i="migrated",o=t):(i="appended",o=n.replace(/\s*$/,`
5
+ `}function ve(e,t,r){let o=i.existsSync(e)?i.readFileSync(e,"utf8"):null,s,n;return o===null?(s="created",n=t):G.test(o)?(n=o.replace(G,()=>t.trimEnd()),s=n===o?"unchanged":"updated"):o.includes(X)?(s="migrated",n=t):(s="appended",n=o.replace(/\s*$/,`
6
6
 
7
- `)+t),!r&&i!=="unchanged"&&(i==="migrated"&&s.writeFileSync(e+".ozmoz-legacy.bak",n,"utf8"),s.mkdirSync(a.dirname(e),{recursive:!0}),s.writeFileSync(e,o,"utf8")),i}function ee(){return[a.join(__dirname,"ozmoz-mcp.js"),a.join(__dirname,"..","bin","ozmoz-mcp.js"),a.join(__dirname,"bin","ozmoz-mcp.js"),a.join(__dirname,"..","src","bin","ozmoz-mcp.js")].find(t=>s.existsSync(t))||a.resolve(__dirname,"ozmoz-mcp.js")}function Z(e,t,r){let n=Object.assign({command:process.execPath,args:[__filename,"mcp","--run"]},r||{}),i={};if(s.existsSync(e))try{let l=JSON.parse(s.readFileSync(e,"utf8"));if(!l||typeof l!="object"||Array.isArray(l))return"invalid";i=l}catch{return"invalid"}let o=i.mcpServers&&i.mcpServers[x];return o&&JSON.stringify(o)===JSON.stringify(n)?"unchanged":(i.mcpServers=i.mcpServers||{},i.mcpServers[x]=n,t||(s.mkdirSync(a.dirname(e),{recursive:!0}),s.writeFileSync(e,JSON.stringify(i,null,2)+`
8
- `,"utf8")),o?"updated":"created")}function R(e){let t=process.platform==="win32"?"where":"which";return _(t,[e],{stdio:"ignore"}).status===0}function $(e,t,r){let n=_(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"]:[],i=ee(),o=["mcp","add"].concat(n,[x,"--",process.execPath,i]),l=["mcp","remove",x].concat(n),c=e+" "+o.join(" ");if(!R(e))return{status:"manual",detail:c};if(t)return{status:"planned",detail:c};let h=$(e,["mcp","list"],6e4),m=h.ok?h.out.split(`
9
- `):[],f=m.find(E=>/^[\s|│┃]*ozmoz(?![\w@-])/.test(E)),p=m.some(E=>/^\s*(?:fleetbo|ozmoz):\s/.test(E));if(f&&f.includes("ozmoz@latest"))return{status:"unchanged",legacy:p};if(f&&!$(e,l).ok)return{status:"manual",detail:e+" "+l.join(" ")+" && "+c,legacy:p};let g=$(e,o);return g.ok?{status:f?"updated":"created",legacy:p}:{status:"failed",detail:c,message:g.out.trim().split(`
10
- `).slice(-2).join(" "),legacy:p}}function Ee(e){let t={user:!1,local:!1,others:[]};try{let r=JSON.parse(s.readFileSync(a.join(A.homedir(),".claude.json"),"utf8")),n=c=>!!c&&typeof c=="object"&&/ozmoz|ozmoz/.test(String(c.command||"")+" "+JSON.stringify(c.args||[])),i=(c,h)=>{!c||typeof c!="object"||Object.keys(c).forEach(m=>{m===x?t[h]=!0:n(c[m])&&t.others.push({name:m,where:h})})};i(r.mcpServers,"user");let o=e;try{o=s.realpathSync(e)}catch{}let l=r.projects||{};Array.from(new Set([e,o])).forEach(c=>i((l[c]||{}).mcpServers,"local"))}catch{}return t}function we(e){let t=Ee(e);t.user&&u(" \u26A0\uFE0F A global (user-scope) '"+x+"' entry from a previous version also exists: the tools appear in every project. To keep them in OZmoz projects only: claude mcp remove "+x+" --scope user"),t.local&&u(" \u26A0\uFE0F A local-scope '"+x+"' entry exists for this folder and takes precedence over .mcp.json. Remove it: claude mcp remove "+x+" --scope local"),t.others.forEach(r=>{u(" \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 Te(e){let t=A.homedir(),r=n=>s.existsSync(n);return{claude:R("claude")||r(a.join(t,".claude")),cursor:r(a.join(e,".cursor"))||r(a.join(t,".cursor"))||R("cursor"),windsurf:r(a.join(t,".codeium","windsurf"))||r(a.join(e,".windsurf")),devin:r(a.join(e,".devin")),codex:R("codex")||r(a.join(t,".codex")),gemini:R("gemini")||r(a.join(t,".gemini")),antigravity:R("agy")||r(a.join(t,".antigravity"))||r(a.join(e,".antigravity")),copilot:R("copilot")||r(a.join(t,".copilot"))}}var be={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),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",o,"utf8"),i.mkdirSync(a.dirname(e),{recursive:!0}),i.writeFileSync(e,n,"utf8")),s}function ee(){return[a.join(__dirname,"ozmoz-mcp.js"),a.join(__dirname,"..","bin","ozmoz-mcp.js"),a.join(__dirname,"bin","ozmoz-mcp.js"),a.join(__dirname,"..","src","bin","ozmoz-mcp.js")].find(t=>i.existsSync(t))||a.resolve(__dirname,"ozmoz-mcp.js")}function Z(e,t,r){let o=Object.assign({command:process.execPath,args:[__filename,"mcp","--run"]},r||{}),s={};if(i.existsSync(e))try{let d=JSON.parse(i.readFileSync(e,"utf8"));if(!d||typeof d!="object"||Array.isArray(d))return"invalid";s=d}catch{return"invalid"}let n=s.mcpServers&&s.mcpServers[x];return n&&JSON.stringify(n)===JSON.stringify(o)?"unchanged":(s.mcpServers=s.mcpServers||{},s.mcpServers[x]=o,t||(i.mkdirSync(a.dirname(e),{recursive:!0}),i.writeFileSync(e,JSON.stringify(s,null,2)+`
8
+ `,"utf8")),n?"updated":"created")}function R(e){let t=process.platform==="win32"?"where":"which";return N(t,[e],{stdio:"ignore"}).status===0}function $(e,t,r){let o=N(e,t,{encoding:"utf8",timeout:r||3e4,shell:process.platform==="win32"});return{ok:o.status===0,out:(o.stdout||"")+(o.stderr||"")}}function Se(e,t,r){let o=e==="claude"?["--scope",r||"user"]:[],s=ee(),n=["mcp","add"].concat(o,[x,"--",process.execPath,s]),d=["mcp","remove",x].concat(o),c=e+" "+n.join(" ");if(!R(e))return{status:"manual",detail:c};if(t)return{status:"planned",detail:c};let h=$(e,["mcp","list"],6e4),f=h.ok?h.out.split(`
9
+ `):[],p=f.find(w=>/^[\s|│┃]*ozmoz(?![\w@-])/.test(w)),m=f.some(w=>/^\s*(?:fleetbo|ozmoz):\s/.test(w));if(p&&p.includes("ozmoz@latest"))return{status:"unchanged",legacy:m};if(p&&!$(e,d).ok)return{status:"manual",detail:e+" "+d.join(" ")+" && "+c,legacy:m};let g=$(e,n);return g.ok?{status:p?"updated":"created",legacy:m}:{status:"failed",detail:c,message:g.out.trim().split(`
10
+ `).slice(-2).join(" "),legacy:m}}function we(e){let t={user:!1,local:!1,others:[]};try{let r=JSON.parse(i.readFileSync(a.join(A.homedir(),".claude.json"),"utf8")),o=c=>!!c&&typeof c=="object"&&/fleetbo|ozmoz/.test(String(c.command||"")+" "+JSON.stringify(c.args||[])),s=(c,h)=>{!c||typeof c!="object"||Object.keys(c).forEach(f=>{f===x?t[h]=!0:o(c[f])&&t.others.push({name:f,where:h})})};s(r.mcpServers,"user");let n=e;try{n=i.realpathSync(e)}catch{}let d=r.projects||{};Array.from(new Set([e,n])).forEach(c=>s((d[c]||{}).mcpServers,"local"))}catch{}return t}function Ee(e){let t=we(e);t.user&&u(" \u26A0\uFE0F A global (user-scope) '"+x+"' entry from a previous version also exists: the tools appear in every project. To keep them in OZmoz projects only: claude mcp remove "+x+" --scope user"),t.local&&u(" \u26A0\uFE0F A local-scope '"+x+"' entry exists for this folder and takes precedence over .mcp.json. Remove it: claude mcp remove "+x+" --scope local"),t.others.forEach(r=>{u(" \u26A0\uFE0F An old MCP entry named '"+r.name+"' ("+r.where+" scope) points to OZmoz. Remove it: claude mcp remove "+r.name+" --scope "+r.where)})}function Te(e){let t=A.homedir(),r=o=>i.existsSync(o);return{claude:R("claude")||r(a.join(t,".claude")),cursor:r(a.join(e,".cursor"))||r(a.join(t,".cursor"))||R("cursor"),windsurf:r(a.join(t,".codeium","windsurf"))||r(a.join(e,".windsurf")),devin:r(a.join(e,".devin")),codex:R("codex")||r(a.join(t,".codex")),gemini:R("gemini")||r(a.join(t,".gemini")),antigravity:R("agy")||r(a.join(t,".antigravity"))||r(a.join(e,".antigravity")),copilot:R("copilot")||r(a.join(t,".copilot"))}}var be={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 o=Ae(t),s=o?`The user already provided their project description and technical choices: "${o}".
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,l=!0;try{let p=a.join(r,".env");if(s.existsSync(p)){let g=s.readFileSync(p,"utf8"),E=g.match(/^\s*OZ_DB_KEY\s*=\s*(.+?)\s*$/m);E&&(o=E[1].trim());let w=g.match(/^\s*OZ_PROTOTYPE\s*=\s*(.+?)\s*$/m);w&&(l=w[1].trim().toLowerCase()==="true")}}catch{}let c=s.existsSync(a.join(r,"svro.schema.json")),h=s.existsSync(a.join(r,"index.html"))||s.existsSync(a.join(r,"package.json")),m=l?"OZ_PROTOTYPE=true (mode essai / local sandbox)":"OZ_PROTOTYPE=false (mode r\xE9el / live database)",f=o||c?"This folder ALREADY contains an OZmoz project (OZ_DB_KEY="+o+", "+m+"). 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.":h?'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 ("+r+`). Your OZmoz instructions are already loaded: they are in AGENTS.md / GEMINI.md at the project root and in the OZmoz MCP server (prompt "oz_contract_rules", tool "oz_get_contract"). Never try to read files inside an mcp/ folder or in the agent's own configuration folders, and do not run bash commands or web searches to look for them. If you do not have them in context, call the MCP tool "oz_get_contract" once before answering. `+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=_("ps",["-A","-o","pid=,ppid=,args="],{encoding:"utf8"});if(t.status!==0)return!1;let r=new Map;t.stdout.split(`
14
- `).forEach(i=>{let o=i.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 i=0;n>1&&i<20&&r.has(n);i++){let{ppid:o,args:l}=r.get(n);if(l.split(/\s+/).slice(0,2).some(h=>/(^|\/)(gemini|claude|codex|antigravity|agy)$/.test(h))||/@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 _(t,[e],{stdio:"ignore"}).status===0}function xe(e,t){let r=t.slice(1).filter(f=>!f.startsWith("--")),n=(r[0]||"").toLowerCase(),i=r.slice(1).join(" "),o=be[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(s.readFileSync(a.join(A.homedir(),".fleetbo","credentials.json"),"utf8")).devToken}catch{}l||(u("[OZmoz] First use on this machine: sign in (your browser opens, approve once)."),_(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))),_(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)),Ie()&&(u(`
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.",n=null,d=!0;try{let m=a.join(r,".env");if(i.existsSync(m)){let g=i.readFileSync(m,"utf8"),w=g.match(/^\s*OZ_DB_KEY\s*=\s*(.+?)\s*$/m);w&&(n=w[1].trim());let E=g.match(/^\s*OZ_PROTOTYPE\s*=\s*(.+?)\s*$/m);E&&(d=E[1].trim().toLowerCase()==="true")}}catch{}let c=i.existsSync(a.join(r,"svro.schema.json")),h=i.existsSync(a.join(r,"index.html"))||i.existsSync(a.join(r,"package.json")),f=d?"OZ_PROTOTYPE=true (mode essai / local sandbox)":"OZ_PROTOTYPE=false (mode r\xE9el / live database)",p=n||c?"This folder ALREADY contains an OZmoz project (OZ_DB_KEY="+n+", "+f+"). 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.":h?'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+`). Your OZmoz instructions are already loaded: they are in AGENTS.md / GEMINI.md at the project root and in the OZmoz MCP server (prompt "oz_contract_rules", tool "oz_get_contract"). Never try to read files inside an mcp/ folder or in the agent's own configuration folders, and do not run bash commands or web searches to look for them. If you do not have them in context, call the MCP tool "oz_get_contract" once before answering. `+p}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=N("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 n=s.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);n&&r.set(Number(n[1]),{ppid:Number(n[2]),args:n[3]})});let o=process.ppid;for(let s=0;o>1&&s<20&&r.has(o);s++){let{ppid:n,args:d}=r.get(o);if(d.split(/\s+/).slice(0,2).some(h=>/(^|\/)(gemini|claude|codex|antigravity|agy)$/.test(h))||/@google\/gemini-cli|@anthropic-ai\/claude-code|@openai\/codex/.test(d))return!0;o=n}}catch{}return!1}function ke(e){let t=process.platform==="win32"?"where":"which";return N(t,[e],{stdio:"ignore"}).status===0}function xe(e,t){let r=t.slice(1).filter(p=>!p.startsWith("--")),o=(r[0]||"").toLowerCase(),s=r.slice(1).join(" "),n=be[o];n||(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 d=!1;try{d=!!JSON.parse(i.readFileSync(a.join(A.homedir(),".fleetbo","credentials.json"),"utf8")).devToken}catch{}d||(u("[OZmoz] First use on this machine: sign in (your browser opens, approve once)."),N(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 '+o+'" again.'),process.exit(1))),N(process.execPath,[__filename,"mcp","--agent="+o],{stdio:"inherit",cwd:e,env:Object.assign({},process.env,{FLEETBO_START:"1"})}).status!==0&&(y("Could not configure "+n.bin+'. Run "npx ozmoz mcp --agent='+o+'" to see why.'),process.exit(1)),Ie()&&(u(`
15
15
  [OZmoz] OZmoz is set up in this folder (instruction file + MCP server).
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 h=Ce(o.rules,i,e);u(`
17
- [OZmoz] Launching `+o.bin+` in this folder...
18
- `);let m=_(o.bin,o.launch(process.platform==="win32"?'"'+h+'"':h),{stdio:"inherit",cwd:e,shell:process.platform==="win32"});process.exit(m.status===null?1:m.status)}async function te(e,t){let r=t.includes("--dry-run"),n=t.find(d=>d.startsWith("--agent=")),i=n&&n.slice(8).trim()?n.slice(8).split(",").map(d=>d.trim().toLowerCase()).filter(Boolean):null,o=null;if(i){o=i.includes("all")?Object.keys(M):i;let d=o.filter(z=>!M[z]);d.length&&(y("Unknown agent(s): "+d.join(", ")+". Valid values: "+Object.keys(M).join(", ")+", all."),process.exit(1))}let l=t.find(d=>d.startsWith("--scope=")),c=l?l.slice(8).trim().toLowerCase():"project";["project","user","local"].includes(c)||(y("Unknown scope: "+c+". Valid values for Claude Code: project (default), user, local."),process.exit(1));let h=Te(e),m=o||Object.keys(M).filter(d=>h[d]),f=ge();u(`
19
- [OZmoz] Configuring your AI agents`+(r?" (dry run: nothing is written)":"")+"...");let p=await Q(),g=p.version||f,E=`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
16
+ `),process.exit(0)),ke(n.bin)||(y('"'+n.bin+'" is not installed or not in your PATH. Install it, then run: npx ozmoz start '+o),process.exit(1));let h=Ce(n.rules,s,e);u(`
17
+ [OZmoz] Launching `+n.bin+` in this folder...
18
+ `);let f=N(n.bin,n.launch(process.platform==="win32"?'"'+h+'"':h),{stdio:"inherit",cwd:e,shell:process.platform==="win32"});process.exit(f.status===null?1:f.status)}async function te(e,t){let r=t.includes("--dry-run"),o=t.find(l=>l.startsWith("--agent=")),s=o&&o.slice(8).trim()?o.slice(8).split(",").map(l=>l.trim().toLowerCase()).filter(Boolean):null,n=null;if(s){n=s.includes("all")?Object.keys(M):s;let l=n.filter(z=>!M[z]);l.length&&(y("Unknown agent(s): "+l.join(", ")+". Valid values: "+Object.keys(M).join(", ")+", all."),process.exit(1))}let d=t.find(l=>l.startsWith("--scope=")),c=d?d.slice(8).trim().toLowerCase():"project";["project","user","local"].includes(c)||(y("Unknown scope: "+c+". Valid values for Claude Code: project (default), user, local."),process.exit(1));let h=Te(e),f=n||Object.keys(M).filter(l=>h[l]),p=ge();u(`
19
+ [OZmoz] Configuring your AI agents`+(r?" (dry run: nothing is written)":"")+"...");let m=await Q(),g=m.version||p,w=`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
20
20
 
21
- `+(p.directives||p.guidelines||"")+`
21
+ `+(m.directives||m.guidelines||"")+`
22
22
 
23
23
  ## PROTOCOLE DONN\xC9ES : QUI FAIT QUOI (AGENT FRONTEND \u2194 ALEX AI)
24
24
 
25
- `+(p.protocol||""),w=J(g,E),b=[["AGENTS.md",w],["GEMINI.md",w],["CLAUDE.md",J(g,`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
26
- @AGENTS.md`)]],v=a.join(e,".cursorrules");if(s.existsSync(v)){let d=s.readFileSync(v,"utf8");(G.test(d)||d.includes(H))&&b.push([".cursorrules",w])}for(let d of b)u("\u2192 "+d[0]+": "+D[ve(a.join(e,d[0]),d[1],r)]);for(let d of m){let z=M[d];if(d==="cursor")u("\u2192 "+z+" MCP (.cursor/mcp.json): "+D[Z(a.join(e,".cursor","mcp.json"),r)]);else if(d==="windsurf")u("\u2192 "+z+" MCP (~/.codeium/windsurf/mcp_config.json): "+D[Z(a.join(A.homedir(),".codeium","windsurf","mcp_config.json"),r)]);else if(d==="copilot")u("\u2192 "+z+" MCP (~/.copilot/mcp-config.json): "+D[Z(a.join(A.homedir(),".copilot","mcp-config.json"),r,{type:"local",tools:["*"]})]);else if(d==="claude"&&c==="project"){let S=Z(a.join(e,".mcp.json"),r);u("\u2192 "+z+" MCP (.mcp.json, project scope): "+D[S]),(S==="created"||S==="updated")&&u(" 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(d==="gemini"){let S=[a.join(A.homedir(),".gemini","settings.json"),a.join(e,".gemini","settings.json"),a.join(e,".mcp.json")],T="unchanged";S.forEach(F=>{let P=Z(F,r);(P==="created"||P==="updated")&&(T=P)}),u("\u2192 "+z+" MCP (settings.json & .mcp.json): "+D[T])}else if(d==="claude"||d==="codex"||d==="antigravity"){let S=d==="antigravity"?"agy":d,T=Se(S,r,c);T.status==="manual"?u("\u2192 "+z+": '"+S+"' not found or not scriptable. Run manually: "+T.detail):T.status==="planned"?u("\u2192 "+z+" MCP: would run: "+T.detail):T.status==="failed"?y("\u2192 "+z+" MCP: registration failed ("+T.message+"). Run manually: "+T.detail):u("\u2192 "+z+" MCP"+(d==="claude"?" ("+c+" scope)":"")+": "+D[T.status]),T.legacy&&u(" \u26A0\uFE0F An old MCP entry named 'fleetbo' exists. Remove it: "+S+" mcp remove fleetbo")}else d==="devin"&&u("\u2192 "+z+": reads AGENTS.md. Devin runs in its own environment: add the OZmoz MCP server from Devin's settings (not automated).")}!o&&m.length===0&&u("\u2192 No agent detected: instruction files were written; re-run with --agent=<name> to register the MCP server.");let I=!!(B(e).FLEETBO_DEV_TOKEN||process.env.FLEETBO_DEV_TOKEN),O=a.join(A.homedir(),".fleetbo","credentials.json");if(s.existsSync(O))try{I=I||!!JSON.parse(s.readFileSync(O,"utf8")).devToken}catch{}I||y('\u26A0\uFE0F No developer token found. Run "npx ozmoz login" once.'),process.env.FLEETBO_START||u(`
25
+ `+(m.protocol||""),E=V(g,w),b=[["AGENTS.md",E],["GEMINI.md",E],["CLAUDE.md",V(g,`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
26
+ @AGENTS.md`)]],v=a.join(e,".cursorrules");if(i.existsSync(v)){let l=i.readFileSync(v,"utf8");(G.test(l)||l.includes(X))&&b.push([".cursorrules",E])}for(let l of b)u("\u2192 "+l[0]+": "+D[ve(a.join(e,l[0]),l[1],r)]);for(let l of f){let z=M[l];if(l==="cursor")u("\u2192 "+z+" MCP (.cursor/mcp.json): "+D[Z(a.join(e,".cursor","mcp.json"),r)]);else if(l==="windsurf")u("\u2192 "+z+" MCP (~/.codeium/windsurf/mcp_config.json): "+D[Z(a.join(A.homedir(),".codeium","windsurf","mcp_config.json"),r)]);else if(l==="copilot")u("\u2192 "+z+" MCP (~/.copilot/mcp-config.json): "+D[Z(a.join(A.homedir(),".copilot","mcp-config.json"),r,{type:"local",tools:["*"]})]);else if(l==="claude"&&c==="project"){let S=Z(a.join(e,".mcp.json"),r);u("\u2192 "+z+" MCP (.mcp.json, project scope): "+D[S]),(S==="created"||S==="updated")&&u(" 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(l==="gemini"){let S=[a.join(A.homedir(),".gemini","settings.json"),a.join(e,".gemini","settings.json"),a.join(e,".mcp.json")],T="unchanged";S.forEach(F=>{let P=Z(F,r);(P==="created"||P==="updated")&&(T=P)}),u("\u2192 "+z+" MCP (settings.json & .mcp.json): "+D[T])}else if(l==="claude"||l==="codex"||l==="antigravity"){let S=l==="antigravity"?"agy":l,T=Se(S,r,c);T.status==="manual"?u("\u2192 "+z+": '"+S+"' not found or not scriptable. Run manually: "+T.detail):T.status==="planned"?u("\u2192 "+z+" MCP: would run: "+T.detail):T.status==="failed"?y("\u2192 "+z+" MCP: registration failed ("+T.message+"). Run manually: "+T.detail):u("\u2192 "+z+" MCP"+(l==="claude"?" ("+c+" scope)":"")+": "+D[T.status]),T.legacy&&u(" \u26A0\uFE0F An old MCP entry named 'fleetbo' exists. Remove it: "+S+" mcp remove fleetbo")}else l==="devin"&&u("\u2192 "+z+": reads AGENTS.md. Devin runs in its own environment: add the OZmoz MCP server from Devin's settings (not automated).")}!n&&f.length===0&&u("\u2192 No agent detected: instruction files were written; re-run with --agent=<name> to register the MCP server.");let I=!!(B(e).FLEETBO_DEV_TOKEN||process.env.FLEETBO_DEV_TOKEN),O=a.join(A.homedir(),".fleetbo","credentials.json");if(i.existsSync(O))try{I=I||!!JSON.parse(i.readFileSync(O,"utf8")).devToken}catch{}I||y('\u26A0\uFE0F No developer token found. Run "npx ozmoz login" once.'),process.env.FLEETBO_START||u(`
27
27
  [OZmoz] Done.
28
- `)}function _e(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";re(`${t} "${e}"`)}function Ne(e){return new Promise((t,r)=>{let n=oe.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 c=l.searchParams.get("token"),h=l.searchParams.get("refresh");if(!c){o.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),o.end("<h3>Error: Missing token.</h3>");return}let m=a.join(A.homedir(),".fleetbo");s.existsSync(m)||s.mkdirSync(m,{recursive:!0}),s.writeFileSync(a.join(m,"credentials.json"),JSON.stringify({devToken:c,refreshToken:h||null,updatedAt:new Date().toISOString()},null,2));let f=a.join(e,".env");if(s.existsSync(f)){let p=s.readFileSync(f,"utf8");p.includes("FLEETBO_DEV_TOKEN=")?p=p.replace(/FLEETBO_DEV_TOKEN=.*/g,`FLEETBO_DEV_TOKEN=${c}`):p+=`
28
+ `)}function Ne(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";re(`${t} "${e}"`)}function _e(e){return new Promise((t,r)=>{let o=oe.createServer((s,n)=>{if(n.setHeader("Access-Control-Allow-Origin","*"),n.setHeader("Access-Control-Allow-Methods","GET, OPTIONS"),n.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),n.setHeader("Access-Control-Allow-Private-Network","true"),s.method==="OPTIONS"){n.writeHead(204),n.end();return}let d=new URL(s.url,"http://127.0.0.1");if(d.pathname==="/callback"){let c=d.searchParams.get("token"),h=d.searchParams.get("refresh");if(!c){n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h3>Error: Missing token.</h3>");return}let f=a.join(A.homedir(),".fleetbo");i.existsSync(f)||i.mkdirSync(f,{recursive:!0}),i.writeFileSync(a.join(f,"credentials.json"),JSON.stringify({devToken:c,refreshToken:h||null,updatedAt:new Date().toISOString()},null,2));let p=a.join(e,".env");if(i.existsSync(p)){let m=i.readFileSync(p,"utf8");m.includes("FLEETBO_DEV_TOKEN=")?m=m.replace(/FLEETBO_DEV_TOKEN=.*/g,`FLEETBO_DEV_TOKEN=${c}`):m+=`
29
29
  FLEETBO_DEV_TOKEN=${c}
30
- `,s.writeFileSync(f,p,"utf8")}o.writeHead(200,{"Content-Type":"text/html; charset=utf-8",Connection:"close"}),o.end(`
30
+ `,i.writeFileSync(p,m,"utf8")}n.writeHead(200,{"Content-Type":"text/html; charset=utf-8",Connection:"close"}),n.end(`
31
31
  <!DOCTYPE html>
32
32
  <html>
33
33
  <head>
@@ -46,27 +46,27 @@ FLEETBO_DEV_TOKEN=${c}
46
46
  </body>
47
47
  </html>
48
48
  `),u(`
49
- [OZmoz] Developer token received and stored successfully!`),!process.env.FLEETBO_START&&!["AGENTS.md","CLAUDE.md","GEMINI.md"].some(p=>s.existsSync(a.join(e,p)))&&(u(`
49
+ [OZmoz] Developer token received and stored successfully!`),!process.env.FLEETBO_START&&!["AGENTS.md","CLAUDE.md","GEMINI.md"].some(m=>i.existsSync(a.join(e,m)))&&(u(`
50
50
  Next step to connect your AI agents:`),u(` npx ozmoz mcp (Configure Claude Code, Cursor, Windsurf, Devin, Codex CLI, Gemini CLI, Antigravity CLI, GitHub Copilot)
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}`;u(`
52
- [OZmoz] Waiting for authentication...`),u(`If your browser does not open automatically, visit: ${o}`),_e(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",i=>r(i))})}async function Pe(e,t,r){let n=await X();return new Promise((i,o)=>{let l=JSON.stringify({enterpriseID:e,schema:t,workflow:r}),c={hostname:"api.ozmoz.io",path:"/sync-schema",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(l),...n?{Authorization:`Bearer ${n}`}:{}}},h=W.request(c,m=>{let f="";m.on("data",p=>{f+=p}),m.on("end",()=>{m.statusCode>=200&&m.statusCode<300?i(JSON.parse(f)):m.statusCode===401||m.statusCode===403?o(new Error('Please sign in first: run "npx ozmoz login".')):o(new Error(`Edge sync failed with HTTP ${m.statusCode}`))})});h.on("error",m=>o(m)),h.write(l),h.end()})}function B(e){let t=a.join(e,".env");if(!s.existsSync(t))return{};let r=s.readFileSync(t,"utf8"),n={};return r.split(`
53
- `).forEach(i=>{let[o,...l]=i.split("=");o&&l.length>0&&(n[o.trim()]=l.join("=").trim())}),n}function V(e,t){return new Promise((r,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,c=>{let h="";c.on("data",m=>{h+=m}),c.on("end",()=>{if(c.statusCode>=200&&c.statusCode<300)try{let m=JSON.parse(h);if(m.success&&m.found&&m.module){let f=m.module.code||m.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 ${c.statusCode} while fetching ${t}`))})});l.on("error",c=>n(c)),l.write(i),l.end()})}var C=process.argv.slice(2),k=C[0],je=["id","_id","userId","author","dateCreated","createdAt","_schema_version"],ne=e=>je.includes(e)||/^_/.test(e)||/^(created|updated|modified|deleted)(At|By)$/i.test(e);function U(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 De(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,i])=>{let o=U(i);o&&Object.keys(o).forEach(l=>{ne(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 Fe(e){let r=Object.entries(e&&e.collections||{}),n=`## \u{1F4E5} CE QUE LE CODE DOIT ENVOYER (MOD\xC8LES D'\xC9CRITURE)
51
+ `)),typeof o.closeAllConnections=="function"&&o.closeAllConnections(),o.close(()=>t()),setTimeout(()=>t(),300)}});o.listen(0,"127.0.0.1",()=>{let n=`https://ozmoz.io/cli-auth?port=${o.address().port}`;u(`
52
+ [OZmoz] Waiting for authentication...`),u(`If your browser does not open automatically, visit: ${n}`),Ne(n);let d=Number(process.env.FLEETBO_LOGIN_TIMEOUT_MS)||12e4;setTimeout(()=>{try{typeof o.closeAllConnections=="function"&&o.closeAllConnections()}catch{}o.close(),r(new Error(`Login timed out after ${Math.round(d/1e3)}s: browser approval not received. Run "npx ozmoz login" once more and approve in the browser.`))},d).unref()}),o.on("error",s=>r(s))})}async function Pe(e,t,r){let o=await J();return new Promise((s,n)=>{let d=JSON.stringify({enterpriseID:e,schema:t,workflow:r}),c={hostname:"api.ozmoz.io",path:"/sync-schema",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(d),...o?{Authorization:`Bearer ${o}`}:{}}},h=Y.request(c,f=>{let p="";f.on("data",m=>{p+=m}),f.on("end",()=>{f.statusCode>=200&&f.statusCode<300?s(JSON.parse(p)):f.statusCode===401?n(new Error('Please sign in first: run "npx ozmoz login".')):f.statusCode===403?n(new Error("Access denied: your account does not have access to this project.")):n(new Error(`OZmoz sync failed with HTTP ${f.statusCode}`))})});h.on("error",f=>n(f)),h.write(d),h.end()})}function B(e){let t=a.join(e,".env");if(!i.existsSync(t))return{};let r=i.readFileSync(t,"utf8"),o={};return r.split(`
53
+ `).forEach(s=>{let[n,...d]=s.split("=");n&&d.length>0&&(o[n.trim()]=d.join("=").trim())}),o}async function W(e,t){let r=await J();return new Promise((o,s)=>{let n=JSON.stringify({projectId:e,moduleName:t}),d={hostname:"getmodulecache-jqycakhlxa-uc.a.run.app",path:"/",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(n),...r?{Authorization:`Bearer ${r}`}:{}}},c=Y.request(d,h=>{let f="";h.on("data",p=>{f+=p}),h.on("end",()=>{if(h.statusCode>=200&&h.statusCode<300)try{let p=JSON.parse(f);if(p.success&&p.found&&p.module){let m=p.module.code||p.module.mockCode;o(typeof m=="string"?JSON.parse(m):m)}else o(null)}catch{s(new Error(`Invalid JSON response for ${t}.`))}else h.statusCode===401||h.statusCode===403?s(new Error('Access denied. Run "npx ozmoz login" with an account that has access to this project.')):s(new Error(`Server error ${h.statusCode} while fetching ${t}`))})});c.on("error",h=>s(h)),c.write(n),c.end()})}var C=process.argv.slice(2),k=C[0],je=["id","_id","userId","author","dateCreated","createdAt","_schema_version"],ne=e=>je.includes(e)||/^_/.test(e)||/^(created|updated|modified|deleted)(At|By)$/i.test(e);function U(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 De(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(([o,s])=>{let n=U(s);n&&Object.keys(n).forEach(d=>{ne(d)&&n[d]&&typeof n[d]=="object"&&n[d].required===!0&&(n[d].required=!1,t.push(o+"."+d))})}),{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 Fe(e){let r=Object.entries(e&&e.collections||{}),o=`## \u{1F4E5} CE QUE LE CODE DOIT ENVOYER (MOD\xC8LES D'\xC9CRITURE)
54
54
 
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=r.filter(([,o])=>U(o)&&Object.keys(U(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 c=U(l),h=Object.entries(c).filter(([p])=>!ne(p));n+="### `"+o+`\`
55
+ `;o+=`### \u{1F194} Identifiants
56
+ `,o+="* 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",o+="* N'envoie **jamais** `id` ni `_id` dans `oz.add` : `oz.add` renvoie `{ success, documentId }` (`documentId` = `_id`).\n",o+="* 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",o+="* `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(([,n])=>U(n)&&Object.keys(U(n)).length>0);return s.length===0?o+`_Aucune collection scell\xE9e pour l'instant : les mod\xE8les appara\xEEtront apr\xE8s la mod\xE9lisation d'Alex._
57
+ `:(s.forEach(([n,d])=>{let c=U(d),h=Object.entries(c).filter(([m])=>!ne(m));o+="### `"+n+`\`
58
58
 
59
59
  | Champ | Type | Obligatoire | Valeurs / remarques |
60
60
  |---|---|---|---|
61
- `,h.forEach(([p,g])=>{let E=typeof g=="string"?g:g&&g.type||"any",w=g&&(g.enum||g.values||g.options),b=Array.isArray(w)&&w.length?"parmi : "+w.map(v=>"`"+v+"`").join(", "):"";n+="| `"+p+"` | "+E+" | "+(g&&g.required===!0?"\u2705 oui":"non")+" | "+b+` |
62
- `});let m=h.filter(([,p])=>p&&p.required===!0),f=h.filter(([,p])=>!(p&&p.required===!0));n+="\nInsertion valide :\n```js\nawait oz.add('"+o+`', {
63
- `,m.forEach(([p,g])=>{n+=" "+p+": "+Re(g)+`,
64
- `}),f.length&&(n+=" // optionnels : "+f.map(([p])=>p).join(", ")+`
65
- `),n+=`}, {
66
- `,n+=" desc: 'Cr\xE9ation d\\'un \xE9l\xE9ment dans "+o+`',
67
- `,n+=` role: 'AUTHENTICATED' // ou 'ANONYMOUS', 'ADMIN'
68
- `,n+=` // guard: 'condition sur les donn\xE9es' (optionnel)
69
- `,n+="});\n```\n\n"}),n)}function Le(e,t,r=""){return`# THE OZMOZ DATA CONTRACT (SVRO DATA CONTRACT)
61
+ `,h.forEach(([m,g])=>{let w=typeof g=="string"?g:g&&g.type||"any",E=g&&(g.enum||g.values||g.options),b=Array.isArray(E)&&E.length?"parmi : "+E.map(v=>"`"+v+"`").join(", "):"";o+="| `"+m+"` | "+w+" | "+(g&&g.required===!0?"\u2705 oui":"non")+" | "+b+` |
62
+ `});let f=h.filter(([,m])=>m&&m.required===!0),p=h.filter(([,m])=>!(m&&m.required===!0));o+="\nInsertion valide :\n```js\nawait oz.add('"+n+`', {
63
+ `,f.forEach(([m,g])=>{o+=" "+m+": "+Re(g)+`,
64
+ `}),p.length&&(o+=" // optionnels : "+p.map(([m])=>m).join(", ")+`
65
+ `),o+=`}, {
66
+ `,o+=" desc: 'Cr\xE9ation d\\'un \xE9l\xE9ment dans "+n+`',
67
+ `,o+=` role: 'AUTHENTICATED' // ou 'ANONYMOUS', 'ADMIN'
68
+ `,o+=` // guard: 'condition sur les donn\xE9es' (optionnel)
69
+ `,o+="});\n```\n\n"}),o)}function Le(e,t,r=""){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\`.
@@ -89,6 +89,7 @@ Next step to connect your AI agents:`),u(` npx ozmoz mcp (Configure Claude C
89
89
  | Read all documents (global) | \`const list = await oz.getDocsG('table', { desc, role })\` | Inventing \`fetch('/api/table')\` |
90
90
  | Read user-owned documents | \`const list = await oz.getDocsU('table', { desc, role })\` | Manually filtering the global array on client side |
91
91
  | Read single document | \`const doc = await oz.getDoc('table', id, { desc, role })\` | Inventing a single-item REST endpoint |
92
+ | Live updates on shared data (read-only) | \`const stop = oz.watch('table', { desc, role }, (list) => setItems(list))\` ; for a server function: \`oz.watch({ call: 'name', payload }, { desc, role }, (result) => ...)\` ; always call \`stop()\` when the component unmounts | Polling with \`setInterval\` |
92
93
  | Create with file / image | \`const res = await oz.addWithMedia('table', data, fileBase64, fileName, { desc, role })\` | Storing raw Base64 strings in DB fields |
93
94
  | Relational join | \`const res = await oz.join('table', options, { desc, role })\` | Writing nested \`getDoc\` loops |
94
95
  | Sign-out session | \`await oz.logout()\` | Calling non-existent \`oz.signOut()\` |
@@ -162,7 +163,7 @@ This document constitutes the **Official Specifications and Bilateral Integrity
162
163
 
163
164
  ---
164
165
 
165
- ### \u{1F6E1}\uFE0F DYNAMIC REBAC ACCESS CONTROL (oz.acl) & CLOUD RUN ROUTER (oz.call)
166
+ ### \u{1F6E1}\uFE0F DYNAMIC REBAC ACCESS CONTROL (oz.acl) & SERVER FUNCTIONS (oz.call)
166
167
 
167
168
  #### 1. Dynamic Relationship-Based Access Control (ReBAC)
168
169
  Verify, grant, or revoke fine-grained runtime permissions on specific collections and document IDs.
@@ -203,7 +204,7 @@ if (response.success) {
203
204
  ### \u{1F4E6} ADVANCED MUTATIONS & RELATIONAL QUERIES (oz.join)
204
205
 
205
206
  #### 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
+ Upload images, PDFs, or media directly to file storage with automatic compression and optimization. The resulting URL is automatically mapped into \`mediaUrl\` / \`image\`.
207
208
 
208
209
  \`\`\`javascript
209
210
  // data: document payload
@@ -246,7 +247,7 @@ const profileRes = await oz.addWithUserId('profiles', {
246
247
  \`\`\`
247
248
 
248
249
  #### 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
+ Perform atomic relational lookups between collections without writing custom backend endpoints or nested loops 6, 8].
250
251
 
251
252
  \`\`\`javascript
252
253
  // Fetch orders and dynamically join the related user record
@@ -626,31 +627,31 @@ ${JSON.stringify({...e||{},context:void 0},null,2)}
626
627
  \`\`\`json
627
628
  ${JSON.stringify(t||{},null,2)}
628
629
  \`\`\`
629
- `}function Me(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 r=B(e),n=s.existsSync(a.join(e,"svro.schema.json"));(r.OZ_DB_KEY||n)&&(y("Cannot create project: an OZmoz project already exists in this folder."),u('\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=a.join(e,".ozmoz.lock");if(s.existsSync(o)){let c=!1;try{let h=Number(s.readFileSync(o,"utf8"));Date.now()-h>6e4&&(c=!0)}catch{c=!0}c||(y("A project creation is already running in this folder."),process.exit(1)),s.unlinkSync(o)}s.writeFileSync(o,String(Date.now()));let l=()=>{if(s.existsSync(o))try{s.unlinkSync(o)}catch{}};try{let c=process.env.FLEETBO_DEV_TOKEN;if(!c){let w=a.join(A.homedir(),".fleetbo","credentials.json");if(s.existsSync(w))try{c=JSON.parse(s.readFileSync(w,"utf8")).devToken}catch{}}c||(l(),y('Missing developer token. Please run "npx ozmoz login" first.'),process.exit(1)),u(`[OZmoz] Creating project "${i}" on Cloud...`);let h=Me(i),m=[h,`${h.slice(0,24)}_${Math.random().toString(36).slice(2,6)}`,`${h.slice(0,24)}_${Math.random().toString(36).slice(2,6)}`],f=null,p=null;for(let w of m)try{let b=await fetch("https://createprojectlight-jqycakhlxa-uc.a.run.app",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${c}`},body:JSON.stringify({data:{name:i,keyApp:w}})}),v=await b.json();if(b.ok&&!v.error){f={keyApp:w,data:v.result?.data||v.data||{}};break}else p=v.error?.message||`HTTP ${b.status}`}catch(b){p=b.message}f||(l(),y(`Failed to create project on Cloud: ${p||"Unknown error"}`),process.exit(1));let g=f.data.bootstrapToken;await K(e,[`--keyApp=${f.keyApp}`,`--token=${g}`]);let E=a.join(e,"package.json");Y(e,E),await te(e,[]),u(`
630
- [OZmoz] Project "${i}" (${f.keyApp}) created and configured successfully.`),u(`AI AGENTS: do NOT stop here and do NOT ask the user to restart. Continue NOW in the same turn: scaffold the frontend if missing, run "npx ozmoz sync", read ozmoz_contract.md, write ALL views in trial mode (OZ_PROTOTYPE=true), then start the dev server and ask the user to validate.
631
- `)}finally{if(s.existsSync(o))try{s.unlinkSync(o)}catch{}}}async function Ue(e){let t=process.env.FLEETBO_DEV_TOKEN;if(!t){let O=a.join(A.homedir(),".fleetbo","credentials.json");if(s.existsSync(O))try{t=JSON.parse(s.readFileSync(O,"utf8")).devToken}catch{}}let n=B(e).OZ_KEY_APP;(!n||!t)&&(y("Cannot update: project uninitialized or dev token missing."),process.exit(1));let i=s.existsSync(a.join(e,"src"))?a.join(e,"src"):e,o=new Set([".jsx",".tsx",".vue",".svelte",".js",".ts",".html"]),l=[],c=0;function h(O){let d=[];try{d=s.readdirSync(O,{withFileTypes:!0})}catch{return}for(let z of d){if(/^(node_modules|\.git|dist|build|\.next|\.svelte-kit)$/.test(z.name))continue;let S=a.join(O,z.name);if(z.isDirectory())h(S);else if(o.has(a.extname(z.name))&&!z.name.endsWith(".d.ts"))try{let T=s.statSync(S);if(T.size>3e5)continue;let F=s.readFileSync(S,"utf8");/oz\.|<oz-/i.test(F)&&(c+=T.size,l.push({name:a.relative(e,S).split(a.sep).join("/"),content:F}))}catch{}}}let m=C.find(O=>O.startsWith("--files=")),f=m?m.slice(8).split(",").map(O=>O.trim()).filter(Boolean):null;if(f&&f.length>0)for(let O of f){let d=a.resolve(e,O);if(s.existsSync(d)){let z=s.readFileSync(d,"utf8");c+=s.statSync(d).size,l.push({name:a.relative(e,d).split(a.sep).join("/"),content:z})}}else h(i);l.length===0&&(y("Cannot update: no components using oz.* found."),process.exit(1)),c>8*1024*1024&&(y("Payload too large: total UI source files exceed 8 MB limit."),process.exit(1));let p=C.find(O=>O.startsWith("--rules=")),g=p?p.slice(8).trim():"",E=C.find(O=>O.startsWith("--reasoning=")),w=E?E.slice(12).trim().toLowerCase():void 0;w!=="standard"&&w!=="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)),u(`[OZmoz] Sending ${l.length} component(s) to Cloud Engine for modeling...`);try{let O,d,z;for(let S=1;S<=3&&(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,oz_rules:g,reasoning:w}})}),d=await O.json().catch(()=>({})),z=d.result?.data||d.data||d,!(O.status<500||S===3));S++)u("\u2192 The modeling service is busy (attempt "+S+"/3). Retrying in 20s..."),await new Promise(T=>setTimeout(T,2e4));if(!O.ok||d.error||z.success===!1){let S=d.error?.message||z.warnings?.join(", ")||d.message||"Server error";y(`Update failed: ${S}`),process.exit(1)}u("\u2192 Cloud modeling response: "+JSON.stringify(d).slice(0,800))}catch(O){y(`Network error: ${O.message}`),process.exit(1)}u("\u2192 Structure modeled. Sealing into OZmoz SVRO Kernel...");let b=_(process.execPath,[__filename,"sync"],{stdio:"inherit",cwd:e}),v=Date.now();for(let O=1;O<=5&&b.status===0;O++){let d=!1;try{let z=JSON.parse(s.readFileSync(a.join(e,"svro.schema.json"),"utf8")),S=JSON.parse(s.readFileSync(a.join(e,"svro.workflow.json"),"utf8"));d=Object.keys(z.collections||{}).length>0&&(S.sequences||[]).length>0}catch{}if(d)break;u("\u2192 Contract still empty, waiting for the cloud (attempt "+O+"/5, "+Math.round((Date.now()-v)/1e3)+"s elapsed)..."),await new Promise(z=>setTimeout(z,6e3)),b=_(process.execPath,[__filename,"sync"],{stdio:"inherit",cwd:e})}let N=!1,I=!1;try{let O=JSON.parse(s.readFileSync(a.join(e,"svro.schema.json"),"utf8"));N=Object.keys(O.collections||{}).length>0,I=(JSON.parse(s.readFileSync(a.join(e,"svro.workflow.json"),"utf8")).sequences||[]).length>0}catch{}b.status===0&&N&&I?u(`
630
+ `}function Me(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 r=B(e),o=i.existsSync(a.join(e,"svro.schema.json"));(r.OZ_DB_KEY||o)&&(y("Cannot create project: an OZmoz project already exists in this folder."),u('\u2192 Use "npx ozmoz sync" or evolve the existing contract instead.'),process.exit(1));let s=(t||"").trim();s||(y('Project name is required. Usage: npx ozmoz create "<name>"'),process.exit(1));let n=a.join(e,".ozmoz.lock");if(i.existsSync(n)){let c=!1;try{let h=Number(i.readFileSync(n,"utf8"));Date.now()-h>6e4&&(c=!0)}catch{c=!0}c||(y("A project creation is already running in this folder."),process.exit(1)),i.unlinkSync(n)}i.writeFileSync(n,String(Date.now()));let d=()=>{if(i.existsSync(n))try{i.unlinkSync(n)}catch{}};try{let c=process.env.FLEETBO_DEV_TOKEN;if(!c){let E=a.join(A.homedir(),".fleetbo","credentials.json");if(i.existsSync(E))try{c=JSON.parse(i.readFileSync(E,"utf8")).devToken}catch{}}c||(d(),y('Missing developer token. Please run "npx ozmoz login" first.'),process.exit(1)),u(`[OZmoz] Creating project "${s}" on Cloud...`);let h=Me(s),f=[h,`${h.slice(0,24)}_${Math.random().toString(36).slice(2,6)}`,`${h.slice(0,24)}_${Math.random().toString(36).slice(2,6)}`],p=null,m=null;for(let E of f)try{let b=await fetch("https://createprojectlight-jqycakhlxa-uc.a.run.app",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${c}`},body:JSON.stringify({data:{name:s,keyApp:E}})}),v=await b.json();if(b.ok&&!v.error){p={keyApp:E,data:v.result?.data||v.data||{}};break}else m=v.error?.message||`HTTP ${b.status}`}catch(b){m=b.message}p||(d(),y(`Failed to create project on Cloud: ${m||"Unknown error"}`),process.exit(1));let g=p.data.bootstrapToken;await q(e,[`--keyApp=${p.keyApp}`,`--token=${g}`]);let w=a.join(e,"package.json");K(e,w),await te(e,[]),u(`
631
+ [OZmoz] Project "${s}" (${p.keyApp}) created and configured successfully.`),u(`AI AGENTS: do NOT stop here and do NOT ask the user to restart. Continue NOW in the same turn: scaffold the frontend if missing, run "npx ozmoz sync", read ozmoz_contract.md, write ALL views in trial mode (OZ_PROTOTYPE=true), then start the dev server and ask the user to validate.
632
+ `)}finally{if(i.existsSync(n))try{i.unlinkSync(n)}catch{}}}async function Ue(e){let t=process.env.FLEETBO_DEV_TOKEN;if(!t){let O=a.join(A.homedir(),".fleetbo","credentials.json");if(i.existsSync(O))try{t=JSON.parse(i.readFileSync(O,"utf8")).devToken}catch{}}let o=B(e).OZ_KEY_APP;(!o||!t)&&(y("Cannot update: project uninitialized or dev token missing."),process.exit(1));let s=i.existsSync(a.join(e,"src"))?a.join(e,"src"):e,n=new Set([".jsx",".tsx",".vue",".svelte",".js",".ts",".html"]),d=[],c=0;function h(O){let l=[];try{l=i.readdirSync(O,{withFileTypes:!0})}catch{return}for(let z of l){if(/^(node_modules|\.git|dist|build|\.next|\.svelte-kit)$/.test(z.name))continue;let S=a.join(O,z.name);if(z.isDirectory())h(S);else if(n.has(a.extname(z.name))&&!z.name.endsWith(".d.ts"))try{let T=i.statSync(S);if(T.size>3e5)continue;let F=i.readFileSync(S,"utf8");/oz\.|<oz-/i.test(F)&&(c+=T.size,d.push({name:a.relative(e,S).split(a.sep).join("/"),content:F}))}catch{}}}let f=C.find(O=>O.startsWith("--files=")),p=f?f.slice(8).split(",").map(O=>O.trim()).filter(Boolean):null;if(p&&p.length>0)for(let O of p){let l=a.resolve(e,O);if(i.existsSync(l)){let z=i.readFileSync(l,"utf8");c+=i.statSync(l).size,d.push({name:a.relative(e,l).split(a.sep).join("/"),content:z})}}else h(s);d.length===0&&(y("Cannot update: no components using oz.* found."),process.exit(1)),c>8*1024*1024&&(y("Payload too large: total UI source files exceed 8 MB limit."),process.exit(1));let m=C.find(O=>O.startsWith("--rules=")),g=m?m.slice(8).trim():"",w=C.find(O=>O.startsWith("--reasoning=")),E=w?w.slice(12).trim().toLowerCase():void 0;E!=="standard"&&E!=="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)),u(`[OZmoz] Sending ${d.length} component(s) to Cloud Engine for modeling...`);try{let O,l,z;for(let S=1;S<=3&&(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:o,name:o,newViewFiles:d,oz_rules:g,reasoning:E}})}),l=await O.json().catch(()=>({})),z=l.result?.data||l.data||l,!(O.status<500||S===3));S++)u("\u2192 The modeling service is busy (attempt "+S+"/3). Retrying in 20s..."),await new Promise(T=>setTimeout(T,2e4));if(!O.ok||l.error||z.success===!1){let S=l.error?.message||z.warnings?.join(", ")||l.message||"Server error";y(`Update failed: ${S}`),process.exit(1)}u("\u2192 Cloud modeling response: "+JSON.stringify(l).slice(0,800))}catch(O){y(`Network error: ${O.message}`),process.exit(1)}u("\u2192 Structure modeled. Sealing into OZmoz SVRO Kernel...");let b=N(process.execPath,[__filename,"sync"],{stdio:"inherit",cwd:e}),v=Date.now();for(let O=1;O<=5&&b.status===0;O++){let l=!1;try{let z=JSON.parse(i.readFileSync(a.join(e,"svro.schema.json"),"utf8")),S=JSON.parse(i.readFileSync(a.join(e,"svro.workflow.json"),"utf8"));l=Object.keys(z.collections||{}).length>0&&(S.sequences||[]).length>0}catch{}if(l)break;u("\u2192 Contract still empty, waiting for the cloud (attempt "+O+"/5, "+Math.round((Date.now()-v)/1e3)+"s elapsed)..."),await new Promise(z=>setTimeout(z,6e3)),b=N(process.execPath,[__filename,"sync"],{stdio:"inherit",cwd:e})}let _=!1,I=!1;try{let O=JSON.parse(i.readFileSync(a.join(e,"svro.schema.json"),"utf8"));_=Object.keys(O.collections||{}).length>0,I=(JSON.parse(i.readFileSync(a.join(e,"svro.workflow.json"),"utf8")).sequences||[]).length>0}catch{}b.status===0&&_&&I?u(`
632
633
  [OZmoz] Contract locked into SVRO Kernel.
633
- `):b.status===0&&N&&!I?(y(`
634
+ `):b.status===0&&_&&!I?(y(`
634
635
  [OZmoz] Contract incomplete: the workflow is empty. Rerun the update before writing any code.
635
- `),process.exit(1)):b.status===0&&!N?(y(`
636
+ `),process.exit(1)):b.status===0&&!_?(y(`
636
637
  [OZmoz] Sync completed with 0 collections. Rerun with --reasoning=high.
637
638
  `),process.exit(1)):(y(`
638
639
  [OZmoz] Sync failed. Run "npx ozmoz sync".
639
640
  `),process.exit(1))}async function Be(){let e=process.cwd(),t=a.join(e,"package.json");if(k==="init"||k==="doctor")u(`
640
- [OZmoz] Initializing and configuring OZmoz...`),await K(e,C),Y(e,t),u(`
641
+ [OZmoz] Initializing and configuring OZmoz...`),await q(e,C),K(e,t),u(`
641
642
  [OZmoz] Configuration completed successfully!
642
643
  `),u(`
643
644
  Next step:`),u(` npx ozmoz sync (Sync cloud schema & generate IDE types)
644
- `);else if(k==="sync"){let r=C.includes("--dry-run"),n=C.includes("--check-only");u(`[OZmoz] Syncing schema...${r?" (dry-run)":""}${n?" (check-only, no network)":""}`),r||de(e);let i=a.join(e,"svro.schema.json"),o=a.join(e,"svro.workflow.json"),l=a.join(e,"ozmoz_contract.md"),c=a.join(e,"src","ozmoz.d.ts"),m=B(e).OZ_ENTERPRISE_ID,f=null,p=null;if(n)u("\u2192 Mode check-only : Local contract used, no cloud fetch..");else if(m)try{u("\u2192 Fetching latest contracts from Cloud..."),f=await V(m,"svro.schema.json"),f&&(s.writeFileSync(i,JSON.stringify(f,null,2)+`
645
- `),u("\u2192 Local svro.schema.json updated.")),p=await V(m,"svro.workflow.json"),p&&(s.writeFileSync(o,JSON.stringify(p,null,2)+`
646
- `),u("\u2192 Local svro.workflow.json updated."))}catch(v){y(`\u26A0\uFE0F Cloud fetch bypassed: ${v.message}. Using local file fallback.`)}else y("\u26A0\uFE0F OZ_ENTERPRISE_ID missing in .env. Skipping cloud fetch.");let g=f;if(!g&&s.existsSync(i))try{g=JSON.parse(s.readFileSync(i,"utf8"))}catch{}g||(g={context:"Application en cours de mod\xE9lisation initiale.",collections:{}},s.writeFileSync(i,JSON.stringify(g,null,2)+`
647
- `,"utf8"),u("\u2192 Initial blank svro.schema.json created."));let E=p;if(!E&&s.existsSync(o))try{E=JSON.parse(s.readFileSync(o,"utf8"))}catch{}E||(E={actors:{},sequences:[]},s.writeFileSync(o,JSON.stringify(E,null,2)+`
648
- `,"utf8"),u("\u2192 Initial blank svro.workflow.json created."));{let v=De(g);v.changed&&(g=v.schema,s.writeFileSync(i,JSON.stringify(g,null,2)+`
649
- `,"utf8"),u("\u2192 Managed by system, no longer required from your code: "+v.notes.join(", ")+"."))}let{protocol:w}=await Q(),b=Le(g,E,w);s.writeFileSync(l,b,"utf8"),u("\u2192 Contract markdown successfully generated at project root.");try{let v=Object.keys(g.collections||{});if(m&&!n&&Object.keys(g.collections||{}).length>0)try{await Pe(m,g,E),u("\u2192 Schema successfully sealed into SVRO Kernel (O(1)).")}catch(d){y(`\u26A0\uFE0F Kernel Shield sync warning: ${d.message}`)}let N=g.collections||{},I=Object.entries(N).map(([d,z])=>{let S=z.fields||z.schema||{},T=Object.entries(S).map(([F,P])=>{let L="any",j=String(typeof P=="string"?P:P.type||"").toLowerCase();return j==="string"||j==="text"||j==="media"?L="string":j==="number"?L="number":j==="boolean"||j==="toggle"?L="boolean":j==="array"&&(L="any[]"),` ${F}?:${L};`}).join(`
650
- `);return` ${d}: {
645
+ `);else if(k==="sync"){let r=C.includes("--dry-run"),o=C.includes("--check-only");u(`[OZmoz] Syncing schema...${r?" (dry-run)":""}${o?" (check-only, no network)":""}`),r||de(e);let s=a.join(e,"svro.schema.json"),n=a.join(e,"svro.workflow.json"),d=a.join(e,"ozmoz_contract.md"),c=a.join(e,"src","ozmoz.d.ts"),f=B(e).OZ_ENTERPRISE_ID,p=null,m=null;if(o)u("\u2192 Mode check-only : Local contract used, no cloud fetch..");else if(f)try{u("\u2192 Fetching latest contracts from Cloud..."),p=await W(f,"svro.schema.json"),p&&(i.writeFileSync(s,JSON.stringify(p,null,2)+`
646
+ `),u("\u2192 Local svro.schema.json updated.")),m=await W(f,"svro.workflow.json"),m&&(i.writeFileSync(n,JSON.stringify(m,null,2)+`
647
+ `),u("\u2192 Local svro.workflow.json updated."))}catch(v){y(`\u26A0\uFE0F Cloud fetch bypassed: ${v.message}. Using local file fallback.`)}else y("\u26A0\uFE0F OZ_ENTERPRISE_ID missing in .env. Skipping cloud fetch.");let g=p;if(!g&&i.existsSync(s))try{g=JSON.parse(i.readFileSync(s,"utf8"))}catch{}g||(g={context:"Application en cours de mod\xE9lisation initiale.",collections:{}},i.writeFileSync(s,JSON.stringify(g,null,2)+`
648
+ `,"utf8"),u("\u2192 Initial blank svro.schema.json created."));let w=m;if(!w&&i.existsSync(n))try{w=JSON.parse(i.readFileSync(n,"utf8"))}catch{}w||(w={actors:{},sequences:[]},i.writeFileSync(n,JSON.stringify(w,null,2)+`
649
+ `,"utf8"),u("\u2192 Initial blank svro.workflow.json created."));{let v=De(g);v.changed&&(g=v.schema,i.writeFileSync(s,JSON.stringify(g,null,2)+`
650
+ `,"utf8"),u("\u2192 Managed by system, no longer required from your code: "+v.notes.join(", ")+"."))}let{protocol:E}=await Q(),b=Le(g,w,E);i.writeFileSync(d,b,"utf8"),u("\u2192 Contract markdown successfully generated at project root.");try{let v=Object.keys(g.collections||{});if(f&&!o&&Object.keys(g.collections||{}).length>0)try{await Pe(f,g,w),u("\u2192 Schema successfully sealed into OZmoz Kernel.")}catch(l){y(`\u26A0\uFE0F Kernel Shield sync warning: ${l.message}`)}let _=g.collections||{},I=Object.entries(_).map(([l,z])=>{let S=z.fields||z.schema||{},T=Object.entries(S).map(([F,P])=>{let L="any",j=String(typeof P=="string"?P:P.type||"").toLowerCase();return j==="string"||j==="text"||j==="media"?L="string":j==="number"?L="number":j==="boolean"||j==="toggle"?L="boolean":j==="array"&&(L="any[]"),` ${F}?:${L};`}).join(`
651
+ `);return` ${l}: {
651
652
  ${T}
652
653
  };`}).join(`
653
- `),O=v.length>0?v.map(d=>`'${d}'`).join(" | "):"string";if(s.existsSync(a.dirname(c))){let d=`/* eslint-disable */
654
+ `),O=v.length>0?v.map(l=>`'${l}'`).join(" | "):"string";if(i.existsSync(a.dirname(c))){let l=`/* eslint-disable */
654
655
  /* prettier-ignore */
655
656
  // @ts-nocheck
656
657
  // Generated by OZmoz \u2014 Updated via sync
@@ -798,7 +799,7 @@ declare module 'svelte/elements' {
798
799
  'oz-reference': OzProp;
799
800
  }
800
801
  }
801
- `;s.writeFileSync(c,d)}ae(e),ce(e,t),le(e),ue(e),u(` [OZmoz] Schema synced successfully (${v.length} collection(s)).`),r&&u("\u2192 [Dry-run] Schema is valid.")}catch(v){y(`Error during synchronization: ${v.message}`),process.exit(1)}}else if(k==="create"){let r=C.slice(1).filter(n=>!n.startsWith("--")).join(" ");await Ze(e,r),process.exit(0)}else if(k==="update")await Ue(e),process.exit(0);else if(k==="mcp"){let r=C.includes("--run"),n=!1;if(!r&&!process.stdin.isTTY&&(r=await new Promise(i=>{let o=process.stdin,l=null,c=f=>{clearTimeout(l),o.removeListener("data",h),o.removeListener("end",m),o.removeListener("error",m),i(f)},h=f=>{o.pause(),o.unshift(f),n=!0,c(!0)},m=()=>c(!1);l=setTimeout(()=>{o.pause(),c(!1)},1500),o.on("data",h),o.once("end",m),o.once("error",m)})),r){try{await import(`file://${ee()}`),n&&process.stdin.resume()}catch(i){y(`Failed to start MCP server: ${i.message}`),process.exit(1)}return}await te(e,C),process.exit(0)}else k==="login"?(await Ne(e),process.exit(0)):k==="start"?xe(e,C):["--help","-h","help"].includes(k)?(u(`OZmoz CLI
802
+ `;i.writeFileSync(c,l)}ae(e),ce(e,t),le(e),ue(e),u(` [OZmoz] Schema synced successfully (${v.length} collection(s)).`),r&&u("\u2192 [Dry-run] Schema is valid.")}catch(v){y(`Error during synchronization: ${v.message}`),process.exit(1)}}else if(k==="create"){let r=C.slice(1).filter(o=>!o.startsWith("--")).join(" ");await Ze(e,r),process.exit(0)}else if(k==="update")await Ue(e),process.exit(0);else if(k==="mcp"){let r=C.includes("--run"),o=!1;if(!r&&!process.stdin.isTTY&&(r=await new Promise(s=>{let n=process.stdin,d=null,c=p=>{clearTimeout(d),n.removeListener("data",h),n.removeListener("end",f),n.removeListener("error",f),s(p)},h=p=>{n.pause(),n.unshift(p),o=!0,c(!0)},f=()=>c(!1);d=setTimeout(()=>{n.pause(),c(!1)},1500),n.on("data",h),n.once("end",f),n.once("error",f)})),r){try{await import(`file://${ee()}`),o&&process.stdin.resume()}catch(s){y(`Failed to start MCP server: ${s.message}`),process.exit(1)}return}await te(e,C),process.exit(0)}else k==="login"?(await _e(e),process.exit(0)):k==="start"?xe(e,C):["--help","-h","help"].includes(k)?(u(`OZmoz CLI
802
803
 
803
804
  Commands:
804
805
  login Authenticate this machine (opens the browser: approve once, the command exits by itself)