ozmoz 0.1.12 → 0.1.15

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/README.md CHANGED
@@ -1,16 +1,16 @@
1
- # ozmoZ
1
+ # OZmoz
2
2
 
3
3
  ### The Client-Side Data OS for Modern Web Apps & AI Vibe-Coding
4
4
 
5
- ozmoZ manages the complete application data lifecycle: from AI-assisted schema modeling (Alex AI DBA) to deterministic Edge enforcement and seamless client-side execution.
5
+ OZmoz manages the complete application data lifecycle: from AI-assisted schema modeling (Alex AI DBA) to deterministic Edge enforcement and seamless client-side execution.
6
6
 
7
- Like an architect drafting blueprints before construction begins, Alex AI models your business domain and spins up an instant, production-ready backend. ozmoZ delivers relational integrity, strict typing, and Edge security to MongoDB Atlas without writing backend boilerplate.
7
+ Like an architect drafting blueprints before construction begins, Alex AI models your business domain and spins up an instant, production-ready backend. OZmoz delivers relational integrity, strict typing, and Edge security to MongoDB Atlas without writing backend boilerplate.
8
8
 
9
9
  ---
10
10
 
11
11
  <!-- STREAMING_CHUNK:Documenting core value propositions... -->
12
12
 
13
- ## Why ozmoZ?
13
+ ## Why OZmoz?
14
14
 
15
15
  - **100% Frontend Focus**: Zero servers, zero custom REST APIs, and zero SQL migrations. Build full-stack applications purely from the client.
16
16
  - **AI Agent Accelerator**: Eliminates hallucinations and cuts token usage by 90% via deterministic contracts (`svro.schema.json`, `svro.workflow.json`). Agents (Claude Code, Cursor, Windsurf) focus 100% of their reasoning on UX.
@@ -184,7 +184,7 @@ eof
184
184
  ### Résumé des éléments générés
185
185
 
186
186
  1. **`checklist_deploiement.md`** : Fournit le diagnostic complet, les points de vigilance sur les bundles et Cloud Functions, ainsi que les 3 commandes de smoke test à exécuter avant le déploiement.
187
- 2. **`README.md`** : Totalement unifié sous la marque **ozmoZ**, avec des exemples d'écriture conformes aux règles d'intégrité (gouvernance `{ desc, role }` et vérification de `res.success`).
187
+ 2. **`README.md`** : Totalement unifié sous la marque **OZmoz**, avec des exemples d'écriture conformes aux règles d'intégrité (gouvernance `{ desc, role }` et vérification de `res.success`).
188
188
 
189
189
 
190
190
  # ozmoz
@@ -193,7 +193,7 @@ eof
193
193
  npx ozmoz
194
194
  ```
195
195
 
196
- ozmoZ is the SDK and CLI behind the `oz.*` API and the `<oz-*>` tags.
196
+ OZmoz is the SDK and CLI behind the `oz.*` API and the `<oz-*>` tags.
197
197
 
198
198
  ## Quick start
199
199
 
package/dist/cli.cjs CHANGED
@@ -1,35 +1,33 @@
1
1
  #!/usr/bin/env node
2
- var i=require("fs"),a=require("path"),q=require("https"),ne=require("http"),w=require("os"),{exec:oe,spawnSync:j}=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:W,touchTsConfig:re,attemptViteAutoImportPatch:ae,injectUniversalRuntime:ce,writeBrowserConfig:le,patchAllowScripts:de}=require(ie),ue="\x1B[34m",pe="\x1B[31m",Y="\x1B[0m";function d(e){console.log(`${ue}${e}${Y}`)}function z(e){console.error(`${pe}${e}${Y}`)}var b="ozmoz",J=/<!-- (?:ozmoz|fleetbo):start[^>]*-->[\s\S]*?<!-- (?:ozmoz|fleetbo):end -->/,me="<!-- 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"},N={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(i.readFileSync(a.join(__dirname,"..","package.json"),"utf8")).version||"dev"}catch{return"dev"}}async function X(){let e=a.join(w.homedir(),".fleetbo","guidelines.json"),n=process.env.FLEETBO_DEV_TOKEN;if(!n){let s=a.join(w.homedir(),".fleetbo","credentials.json");if(i.existsSync(s))try{n=JSON.parse(i.readFileSync(s,"utf8")).devToken}catch{}}try{let s={"Content-Type":"application/json"};n&&(s.Authorization=`Bearer ${n}`);let r=await(await fetch("https://getagentdirectives-jqycakhlxa-uc.a.run.app",{method:"POST",headers:s,body:JSON.stringify({data:{}})})).json(),t=r.result?.data||r.result||r.data;if(t&&(t.protocol||t.directives))return i.existsSync(a.dirname(e))||i.mkdirSync(a.dirname(e),{recursive:!0}),i.writeFileSync(e,JSON.stringify(t,null,2),"utf8"),t}catch{}if(i.existsSync(e))try{return JSON.parse(i.readFileSync(e,"utf8"))}catch{}return{protocol:"",directives:"",version:"1.0.0"}}function V(e,n){return"<!-- ozmoz:start v"+e+` -->
3
- `+n.trim()+`
2
+ var r=require("fs"),c=require("path"),q=require("https"),ne=require("http"),b=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:W,handleAuthAndEnv:K,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 l(e){console.log(`${ue}${e}${Y}`)}function y(e){console.error(`${pe}${e}${Y}`)}var A="ozmoz",V=/<!--\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",L={claude:"Claude Code",cursor:"Cursor",windsurf:"Windsurf",devin:"Devin",codex:"Codex CLI",gemini:"Gemini CLI",antigravity:"Antigravity CLI"},N={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"}}async function X(){let e=c.join(b.homedir(),".fleetbo","guidelines.json");try{l("[OZmoz] Fetching instructions from Cloud...");let o=await fetch("https://getagentdirectives-jqycakhlxa-uc.a.run.app",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({data:{}})});if(!o.ok)y("[OZmoz] Cloud error HTTP "+o.status);else{let s=await o.json(),t=s.result?.data||s.result||s.data;if(t&&t.protocol&&t.directives)return l("[OZmoz] Instructions loaded successfully."),r.existsSync(c.dirname(e))||r.mkdirSync(c.dirname(e),{recursive:!0}),r.writeFileSync(e,JSON.stringify(t,null,2),"utf8"),t;y("[OZmoz] Empty Cloud response.")}}catch(o){y("[OZmoz] Network error: "+o.message)}if(r.existsSync(e)){l("[OZmoz] Using local cache (~/.fleetbo/guidelines.json)");try{return JSON.parse(r.readFileSync(e,"utf8"))}catch{}}return{protocol:"",directives:"",version:"1.0.0"}}function J(e,o){return"<!-- ozmoz:start v"+e+` -->
3
+ `+o.trim()+`
4
4
  `+me+`
5
- `}function he(e,n,s){let o=i.existsSync(e)?i.readFileSync(e,"utf8"):null,r,t;return o===null?(r="created",t=n):J.test(o)?(t=o.replace(J,()=>n.trimEnd()),r=t===o?"unchanged":"updated"):o.includes(H)?(r="migrated",t=n):(r="appended",t=o.replace(/\s*$/,`
5
+ `}function he(e,o,s){let t=r.existsSync(e)?r.readFileSync(e,"utf8"):null,a,n;return t===null?(a="created",n=o):V.test(t)?(n=t.replace(V,()=>o.trimEnd()),a=n===t?"unchanged":"updated"):t.includes(H)?(a="migrated",n=o):(a="appended",n=t.replace(/\s*$/,`
6
6
 
7
- `)+n),!s&&r!=="unchanged"&&(r==="migrated"&&i.writeFileSync(e+".ozmoz-legacy.bak",o,"utf8"),i.mkdirSync(a.dirname(e),{recursive:!0}),i.writeFileSync(e,t,"utf8")),r}function Q(){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(n=>i.existsSync(n))||a.resolve(__dirname,"ozmoz-mcp.js")}function I(e,n){let s={command:process.execPath,args:[__filename,"mcp","--run"]},o={};if(i.existsSync(e))try{let t=JSON.parse(i.readFileSync(e,"utf8"));if(!t||typeof t!="object"||Array.isArray(t))return"invalid";o=t}catch{return"invalid"}let r=o.mcpServers&&o.mcpServers[b];return r&&JSON.stringify(r)===JSON.stringify(s)?"unchanged":(o.mcpServers=o.mcpServers||{},o.mcpServers[b]=s,n||(i.mkdirSync(a.dirname(e),{recursive:!0}),i.writeFileSync(e,JSON.stringify(o,null,2)+`
8
- `,"utf8")),r?"updated":"created")}function ge(e){if(!i.existsSync(e))return"absent";let n;try{n=JSON.parse(i.readFileSync(e,"utf8"))}catch{return"invalid"}return!n||typeof n!="object"||!n.mcpServers||!n.mcpServers[b]?"absent":(delete n.mcpServers[b],i.writeFileSync(e,JSON.stringify(n,null,2)+`
9
- `,"utf8"),"removed")}function P(e){let n=process.platform==="win32"?"where":"which";return j(n,[e],{stdio:"ignore"}).status===0}function B(e,n,s){let o=j(e,n,{encoding:"utf8",timeout:s||3e4,shell:process.platform==="win32"});return{ok:o.status===0,out:(o.stdout||"")+(o.stderr||"")}}function ye(e,n,s){let o=e==="claude"?["--scope",s||"user"]:[],r=Q(),t=["mcp","add"].concat(o,[b,"--",process.execPath,r]),l=["mcp","remove",b].concat(o),c=e+" "+t.join(" ");if(!P(e))return{status:"manual",detail:c};if(n)return{status:"planned",detail:c};let m=B(e,["mcp","list"],6e4),u=m.ok?m.out.split(`
10
- `):[],f=u.find(O=>/^[\s|│┃]*ozmoz(?![\w@-])/.test(O)),h=u.some(O=>/^\s*(?:fleetbo|fleetbo-svro):\s/.test(O));if(f&&f.includes("ozmoz@latest"))return{status:"unchanged",legacy:h};if(f&&!B(e,l).ok)return{status:"manual",detail:e+" "+l.join(" ")+" && "+c,legacy:h};let p=B(e,t);return p.ok?{status:f?"updated":"created",legacy:h}:{status:"failed",detail:c,message:p.out.trim().split(`
11
- `).slice(-2).join(" "),legacy:h}}function ze(e){let n={user:!1,local:!1,others:[]};try{let s=JSON.parse(i.readFileSync(a.join(w.homedir(),".claude.json"),"utf8")),o=c=>!!c&&typeof c=="object"&&/fleetbo-svro|ozmoz/.test(String(c.command||"")+" "+JSON.stringify(c.args||[])),r=(c,m)=>{!c||typeof c!="object"||Object.keys(c).forEach(u=>{u===b?n[m]=!0:o(c[u])&&n.others.push({name:u,where:m})})};r(s.mcpServers,"user");let t=e;try{t=i.realpathSync(e)}catch{}let l=s.projects||{};Array.from(new Set([e,t])).forEach(c=>r((l[c]||{}).mcpServers,"local"))}catch{}return n}function Oe(e){let n=ze(e);n.user&&d(" \u26A0\uFE0F A global (user-scope) '"+b+"' entry from a previous version also exists: the tools appear in every project. To keep them in ozmoZ projects only: claude mcp remove "+b+" --scope user"),n.local&&d(" \u26A0\uFE0F A local-scope '"+b+"' entry exists for this folder and takes precedence over .mcp.json. Remove it: claude mcp remove "+b+" --scope local"),n.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 Se(e){let n=w.homedir(),s=o=>i.existsSync(o);return{claude:P("claude")||s(a.join(n,".claude")),cursor:s(a.join(e,".cursor"))||s(a.join(n,".cursor"))||P("cursor"),windsurf:s(a.join(n,".codeium","windsurf"))||s(a.join(e,".windsurf")),devin:s(a.join(e,".devin")),codex:P("codex")||s(a.join(n,".codex")),gemini:P("gemini")||s(a.join(n,".gemini")),antigravity:P("agy")||s(a.join(n,".antigravity"))||s(a.join(e,".antigravity"))}}var ve={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 Ee(e){return String(e||"").replace(/[^\p{L}\p{N} '.,:\-_]/gu," ").replace(/\s+/g," ").trim().slice(0,4e3)}function Te(e,n,s){let o=Ee(n),r=o?`The user already provided their project description and technical choices: "${o}".
7
+ `)+o),!s&&a!=="unchanged"&&(a==="migrated"&&r.writeFileSync(e+".ozmoz-legacy.bak",t,"utf8"),r.mkdirSync(c.dirname(e),{recursive:!0}),r.writeFileSync(e,n,"utf8")),a}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(o=>r.existsSync(o))||c.resolve(__dirname,"ozmoz-mcp.js")}function Z(e,o){let s={command:process.execPath,args:[__filename,"mcp","--run"]},t={};if(r.existsSync(e))try{let n=JSON.parse(r.readFileSync(e,"utf8"));if(!n||typeof n!="object"||Array.isArray(n))return"invalid";t=n}catch{return"invalid"}let a=t.mcpServers&&t.mcpServers[A];return a&&JSON.stringify(a)===JSON.stringify(s)?"unchanged":(t.mcpServers=t.mcpServers||{},t.mcpServers[A]=s,o||(r.mkdirSync(c.dirname(e),{recursive:!0}),r.writeFileSync(e,JSON.stringify(t,null,2)+`
8
+ `,"utf8")),a?"updated":"created")}function I(e){let o=process.platform==="win32"?"where":"which";return j(o,[e],{stdio:"ignore"}).status===0}function B(e,o,s){let t=j(e,o,{encoding:"utf8",timeout:s||3e4,shell:process.platform==="win32"});return{ok:t.status===0,out:(t.stdout||"")+(t.stderr||"")}}function ge(e,o,s){let t=e==="claude"?["--scope",s||"user"]:[],a=Q(),n=["mcp","add"].concat(t,[A,"--",process.execPath,a]),d=["mcp","remove",A].concat(t),i=e+" "+n.join(" ");if(!I(e))return{status:"manual",detail:i};if(o)return{status:"planned",detail:i};let m=B(e,["mcp","list"],6e4),u=m.ok?m.out.split(`
9
+ `):[],f=u.find(z=>/^[\s|│┃]*ozmoz(?![\w@-])/.test(z)),h=u.some(z=>/^\s*(?:fleetbo|fleetbo-svro):\s/.test(z));if(f&&f.includes("ozmoz@latest"))return{status:"unchanged",legacy:h};if(f&&!B(e,d).ok)return{status:"manual",detail:e+" "+d.join(" ")+" && "+i,legacy:h};let p=B(e,n);return p.ok?{status:f?"updated":"created",legacy:h}:{status:"failed",detail:i,message:p.out.trim().split(`
10
+ `).slice(-2).join(" "),legacy:h}}function ye(e){let o={user:!1,local:!1,others:[]};try{let s=JSON.parse(r.readFileSync(c.join(b.homedir(),".claude.json"),"utf8")),t=i=>!!i&&typeof i=="object"&&/fleetbo-svro|ozmoz/.test(String(i.command||"")+" "+JSON.stringify(i.args||[])),a=(i,m)=>{!i||typeof i!="object"||Object.keys(i).forEach(u=>{u===A?o[m]=!0:t(i[u])&&o.others.push({name:u,where:m})})};a(s.mcpServers,"user");let n=e;try{n=r.realpathSync(e)}catch{}let d=s.projects||{};Array.from(new Set([e,n])).forEach(i=>a((d[i]||{}).mcpServers,"local"))}catch{}return o}function Oe(e){let o=ye(e);o.user&&l(" \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"),o.local&&l(" \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"),o.others.forEach(s=>{l(" \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 ze(e){let o=b.homedir(),s=t=>r.existsSync(t);return{claude:I("claude")||s(c.join(o,".claude")),cursor:s(c.join(e,".cursor"))||s(c.join(o,".cursor"))||I("cursor"),windsurf:s(c.join(o,".codeium","windsurf"))||s(c.join(e,".windsurf")),devin:s(c.join(e,".devin")),codex:I("codex")||s(c.join(o,".codex")),gemini:I("gemini")||s(c.join(o,".gemini")),antigravity:I("agy")||s(c.join(o,".antigravity"))||s(c.join(e,".antigravity"))}}var Se={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 ve(e){return String(e||"").replace(/[^\p{L}\p{N} '.,:\-_]/gu," ").replace(/\s+/g," ").trim().slice(0,4e3)}function Ee(e,o,s){let t=ve(o),a=t?`The user already provided their project description and technical choices: "${t}".
12
11
  - Check if the framework (e.g. React, Vue) is already specified.
13
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.
14
- - If no technology was mentioned at all, ask the starter technology question from your ozmoZ instructions.
15
- Then proceed to build it.`:"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.",t=null;try{let u=a.join(s,".env");if(i.existsSync(u)){let f=i.readFileSync(u,"utf8").match(/^\s*OZ_DB_KEY\s*=\s*(.+?)\s*$/m);f&&(t=f[1].trim())}}catch{}let l=i.existsSync(a.join(s,"svro.schema.json")),c=i.existsSync(a.join(s,"index.html"))||i.existsSync(a.join(s,"package.json")),m=t||l?"This folder ALREADY contains an ozmoZ project"+(t?" (OZ_DB_KEY="+t+")":"")+" \u2014 do NOT read .env or svro.schema.json yourself, 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.":c?'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). "+r;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). "+m}function we(){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 n=j("ps",["-A","-o","pid=,ppid=,args="],{encoding:"utf8"});if(n.status!==0)return!1;let s=new Map;n.stdout.split(`
16
- `).forEach(r=>{let t=r.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);t&&s.set(Number(t[1]),{ppid:Number(t[2]),args:t[3]})});let o=process.ppid;for(let r=0;o>1&&r<20&&s.has(o);r++){let{ppid:t,args:l}=s.get(o);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;o=t}}catch{}return!1}function be(e){let n=process.platform==="win32"?"where":"which";return j(n,[e],{stdio:"ignore"}).status===0}function xe(e,n){let s=n.slice(1).filter(f=>!f.startsWith("--")),o=(s[0]||"").toLowerCase(),r=s.slice(1).join(" "),t=ve[o];t||(z('Usage: npx ozmoz start <claude|gemini|codex> ["your app idea"]'),z('Cursor, Windsurf and Devin have no terminal agent to launch: run "npx ozmoz mcp --agent=<cursor|windsurf|devin>" instead.'),process.exit(1));let l=!1;try{l=!!JSON.parse(i.readFileSync(a.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&&(z('Sign-in did not complete. Run "npx ozmoz start '+o+'" again.'),process.exit(1))),j(process.execPath,[__filename,"mcp","--agent="+o],{stdio:"inherit",cwd:e,env:Object.assign({},process.env,{FLEETBO_START:"1"})}).status!==0&&(z("Could not configure "+t.bin+'. Run "npx ozmoz mcp --agent='+o+'" to see why.'),process.exit(1)),we()&&(d(`
17
- [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 '+o+`" in a normal terminal), then to paste the message again. Do not run any other command.
18
- `),process.exit(0)),be(t.bin)||(z('"'+t.bin+'" is not installed or not in your PATH. Install it, then run: npx ozmoz start '+o),process.exit(1));let m=Te(t.rules,r,e);d(`
19
- [ozmoZ] Launching `+t.bin+` in this folder...
20
- `);let u=j(t.bin,t.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,n){let s=n.includes("--dry-run"),o=n.find(g=>g.startsWith("--agent=")),r=o&&o.slice(8).trim()?o.slice(8).split(",").map(g=>g.trim().toLowerCase()).filter(Boolean):null,t=null;if(r){t=r.includes("all")?Object.keys(M):r;let g=t.filter(T=>!M[T]);g.length&&(z("Unknown agent(s): "+g.join(", ")+". Valid values: "+Object.keys(M).join(", ")+", all."),process.exit(1))}let l=n.find(g=>g.startsWith("--scope=")),c=l?l.slice(8).trim().toLowerCase():"project";["project","user","local"].includes(c)||(z("Unknown scope: "+c+". Valid values for Claude Code: project (default), user, local."),process.exit(1));let m=Se(e),u=t||Object.keys(M).filter(g=>m[g]),f=fe();d(`
21
- [ozmoZ] Configuring your AI agents`+(s?" (dry run: nothing is written)":"")+"...");let h=await X(),p=h.version||f,O=`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
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;try{let u=c.join(s,".env");if(r.existsSync(u)){let f=r.readFileSync(u,"utf8").match(/^\s*OZ_DB_KEY\s*=\s*(.+?)\s*$/m);f&&(n=f[1].trim())}}catch{}let d=r.existsSync(c.join(s,"svro.schema.json")),i=r.existsSync(c.join(s,"index.html"))||r.existsSync(c.join(s,"package.json")),m=n||d?"This folder ALREADY contains an OZmoz project"+(n?" (OZ_DB_KEY="+n+")":"")+" \u2014 do NOT read .env or svro.schema.json yourself, 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.":i?'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). "+a;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). "+m}function Te(){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 o=j("ps",["-A","-o","pid=,ppid=,args="],{encoding:"utf8"});if(o.status!==0)return!1;let s=new Map;o.stdout.split(`
14
+ `).forEach(a=>{let n=a.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);n&&s.set(Number(n[1]),{ppid:Number(n[2]),args:n[3]})});let t=process.ppid;for(let a=0;t>1&&a<20&&s.has(t);a++){let{ppid:n,args:d}=s.get(t);if(d.split(/\s+/).slice(0,2).some(m=>/(^|\/)(gemini|claude|codex|antigravity|agy)$/.test(m))||/@google\/gemini-cli|@anthropic-ai\/claude-code|@openai\/codex/.test(d))return!0;t=n}}catch{}return!1}function we(e){let o=process.platform==="win32"?"where":"which";return j(o,[e],{stdio:"ignore"}).status===0}function be(e,o){let s=o.slice(1).filter(f=>!f.startsWith("--")),t=(s[0]||"").toLowerCase(),a=s.slice(1).join(" "),n=Se[t];n||(y('Usage: npx ozmoz start <claude|gemini|codex> ["your app idea"]'),y('Cursor, Windsurf and Devin have no terminal agent to launch: run "npx ozmoz mcp --agent=<cursor|windsurf|devin>" instead.'),process.exit(1));let d=!1;try{d=!!JSON.parse(r.readFileSync(c.join(b.homedir(),".fleetbo","credentials.json"),"utf8")).devToken}catch{}d||(l("[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 '+t+'" again.'),process.exit(1))),j(process.execPath,[__filename,"mcp","--agent="+t],{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='+t+'" to see why.'),process.exit(1)),Te()&&(l(`
15
+ [OZmoz] OZmoz is set up in this folder (instruction file + MCP server).`),l("[OZmoz] You are already inside an AI agent's shell, so no second agent is launched."),l('[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 '+t+`" in a normal terminal), then to paste the message again. Do not run any other command.
16
+ `),process.exit(0)),we(n.bin)||(y('"'+n.bin+'" is not installed or not in your PATH. Install it, then run: npx ozmoz start '+t),process.exit(1));let m=Ee(n.rules,a,e);l(`
17
+ [OZmoz] Launching `+n.bin+` in this folder...
18
+ `);let u=j(n.bin,n.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,o){let s=o.includes("--dry-run"),t=o.find(g=>g.startsWith("--agent=")),a=t&&t.slice(8).trim()?t.slice(8).split(",").map(g=>g.trim().toLowerCase()).filter(Boolean):null,n=null;if(a){n=a.includes("all")?Object.keys(L):a;let g=n.filter(E=>!L[E]);g.length&&(y("Unknown agent(s): "+g.join(", ")+". Valid values: "+Object.keys(L).join(", ")+", all."),process.exit(1))}let d=o.find(g=>g.startsWith("--scope=")),i=d?d.slice(8).trim().toLowerCase():"project";["project","user","local"].includes(i)||(y("Unknown scope: "+i+". Valid values for Claude Code: project (default), user, local."),process.exit(1));let m=ze(e),u=n||Object.keys(L).filter(g=>m[g]),f=fe();l(`
19
+ [OZmoz] Configuring your AI agents`+(s?" (dry run: nothing is written)":"")+"...");let h=await X(),p=h.version||f,z=`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
22
20
 
23
21
  `+(h.directives||h.guidelines||"")+`
24
22
 
25
23
  ## PROTOCOLE DONN\xC9ES : QUI FAIT QUOI (AGENT FRONTEND \u2194 ALEX AI)
26
24
 
27
- `+(h.protocol||""),v=V(p,O),E=[["AGENTS.md",v],["GEMINI.md",v],["CLAUDE.md",V(p,`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
28
- @AGENTS.md`)]],y=a.join(e,".cursorrules");if(i.existsSync(y)){let g=i.readFileSync(y,"utf8");(J.test(g)||g.includes(H))&&E.push([".cursorrules",v])}for(let g of E)d("\u2192 "+g[0]+": "+N[he(a.join(e,g[0]),g[1],s)]);for(let g of u){let T=M[g];if(g==="cursor")d("\u2192 "+T+" MCP (.cursor/mcp.json): "+N[I(a.join(e,".cursor","mcp.json"),s)]);else if(g==="windsurf")d("\u2192 "+T+" MCP (~/.codeium/windsurf/mcp_config.json): "+N[I(a.join(w.homedir(),".codeium","windsurf","mcp_config.json"),s)]);else if(g==="antigravity"){if(d("\u2192 "+T+" MCP (.agents/mcp_config.json): "+N[I(a.join(e,".agents","mcp_config.json"),s)]),I(a.join(e,".mcp.json"),s),!s){let S=[];u.includes("gemini")||(S.push(a.join(e,".gemini","settings.json")),S.push(a.join(w.homedir(),".gemini","settings.json"))),S.push(a.join(e,".antigravity","settings.json")),S.push(a.join(w.homedir(),".antigravity","settings.json")),S.push(a.join(e,".antigravity","mcp.json")),S.forEach(A=>{try{ge(A)==="removed"&&d("\u2192 Removed stale ozmoz entry: "+(a.relative(e,A)||A))}catch{}})}}else if(g==="gemini"){let S=[a.join(w.homedir(),".gemini","settings.json"),a.join(e,".gemini","settings.json"),a.join(e,".mcp.json")],A="unchanged";S.forEach(L=>{let k=I(L,s);(k==="created"||k==="updated")&&(A=k)}),d("\u2192 "+T+" MCP (settings.json & .mcp.json): "+N[A])}else if(g==="claude"&&c==="project"){let S=I(a.join(e,".mcp.json"),s);d("\u2192 "+T+" MCP (.mcp.json, project scope): "+N[S]),(S==="created"||S==="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)."),Oe(e)}else if(g==="claude"||g==="codex"){let S=ye(g,s,c);S.status==="manual"?d("\u2192 "+T+": '"+g+"' not found or not scriptable. Run manually: "+S.detail):S.status==="planned"?d("\u2192 "+T+" MCP: would run: "+S.detail):S.status==="failed"?z("\u2192 "+T+" MCP: registration failed ("+S.message+"). Run manually: "+S.detail):d("\u2192 "+T+" MCP"+(g==="claude"?" ("+c+" scope)":" (~/.codex/config.toml, global)")+": "+N[S.status]),S.legacy&&d(" \u26A0\uFE0F An old MCP entry named 'fleetbo' exists. Remove it: "+g+" mcp remove fleetbo")}else g==="devin"&&d("\u2192 "+T+": reads AGENTS.md. Devin runs in its own environment: add the Fleetbo MCP server from Devin's settings (not automated).")}!t&&u.length===0&&d("\u2192 No agent detected: instruction files were written; re-run with --agent=<name> to register the MCP server.");let F=!!($(e).FLEETBO_DEV_TOKEN||process.env.FLEETBO_DEV_TOKEN),Z=a.join(w.homedir(),".fleetbo","credentials.json");if(i.existsSync(Z))try{F=F||!!JSON.parse(i.readFileSync(Z,"utf8")).devToken}catch{}F||z('\u26A0\uFE0F No developer token found. Run "npx ozmoz login" once.'),process.env.FLEETBO_START||d(`
29
- [ozmoZ] Done. Restart your agent so it reloads the tools and instruction files.
30
- `)}function Ce(e){let n=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";oe(`${n} "${e}"`)}function Ae(e){return new Promise((n,s)=>{let o=ne.createServer((r,t)=>{if(t.setHeader("Access-Control-Allow-Origin","*"),t.setHeader("Access-Control-Allow-Methods","GET, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),t.setHeader("Access-Control-Allow-Private-Network","true"),r.method==="OPTIONS"){t.writeHead(204),t.end();return}let l=new URL(r.url,"http://127.0.0.1");if(l.pathname==="/callback"){let c=l.searchParams.get("token"),m=l.searchParams.get("refresh");if(!c){t.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),t.end("<h3>Error: Missing token.</h3>");return}let u=a.join(w.homedir(),".fleetbo");i.existsSync(u)||i.mkdirSync(u,{recursive:!0}),i.writeFileSync(a.join(u,"credentials.json"),JSON.stringify({devToken:c,refreshToken:m||null,updatedAt:new Date().toISOString()},null,2));let f=a.join(e,".env");if(i.existsSync(f)){let h=i.readFileSync(f,"utf8");h.includes("FLEETBO_DEV_TOKEN=")?h=h.replace(/FLEETBO_DEV_TOKEN=.*/g,`FLEETBO_DEV_TOKEN=${c}`):h+=`
31
- FLEETBO_DEV_TOKEN=${c}
32
- `,i.writeFileSync(f,h,"utf8")}t.writeHead(200,{"Content-Type":"text/html; charset=utf-8",Connection:"close"}),t.end(`
25
+ `+(h.protocol||""),S=J(p,z),v=[["AGENTS.md",S],["GEMINI.md",S],["CLAUDE.md",J(p,`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
26
+ @AGENTS.md`)]],O=c.join(e,".cursorrules");if(r.existsSync(O)){let g=r.readFileSync(O,"utf8");(V.test(g)||g.includes(H))&&v.push([".cursorrules",S])}for(let g of v)l("\u2192 "+g[0]+": "+N[he(c.join(e,g[0]),g[1],s)]);for(let g of u){let E=L[g];if(g==="cursor")l("\u2192 "+E+" MCP (.cursor/mcp.json): "+N[Z(c.join(e,".cursor","mcp.json"),s)]);else if(g==="windsurf")l("\u2192 "+E+" MCP (~/.codeium/windsurf/mcp_config.json): "+N[Z(c.join(b.homedir(),".codeium","windsurf","mcp_config.json"),s)]);else if(g==="claude"&&i==="project"){let w=Z(c.join(e,".mcp.json"),s);l("\u2192 "+E+" MCP (.mcp.json, project scope): "+N[w]),(w==="created"||w==="updated")&&l(" 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)."),Oe(e)}else if(g==="gemini"){let w=[c.join(b.homedir(),".gemini","settings.json"),c.join(e,".gemini","settings.json"),c.join(e,".mcp.json")],T="unchanged";w.forEach($=>{let k=Z($,s);(k==="created"||k==="updated")&&(T=k)}),l("\u2192 "+E+" MCP (settings.json & .mcp.json): "+N[T])}else if(g==="claude"||g==="codex"||g==="antigravity"){let w=g==="antigravity"?"agy":g,T=ge(w,s,i);T.status==="manual"?l("\u2192 "+E+": '"+w+"' not found or not scriptable. Run manually: "+T.detail):T.status==="planned"?l("\u2192 "+E+" MCP: would run: "+T.detail):T.status==="failed"?y("\u2192 "+E+" MCP: registration failed ("+T.message+"). Run manually: "+T.detail):l("\u2192 "+E+" MCP"+(g==="claude"?" ("+i+" scope)":"")+": "+N[T.status]),T.legacy&&l(" \u26A0\uFE0F An old MCP entry named 'fleetbo' exists. Remove it: "+w+" mcp remove fleetbo")}else g==="devin"&&l("\u2192 "+E+": reads AGENTS.md. Devin runs in its own environment: add the Fleetbo MCP server from Devin's settings (not automated).")}!n&&u.length===0&&l("\u2192 No agent detected: instruction files were written; re-run with --agent=<name> to register the MCP server.");let D=!!(U(e).FLEETBO_DEV_TOKEN||process.env.FLEETBO_DEV_TOKEN),R=c.join(b.homedir(),".fleetbo","credentials.json");if(r.existsSync(R))try{D=D||!!JSON.parse(r.readFileSync(R,"utf8")).devToken}catch{}D||y('\u26A0\uFE0F No developer token found. Run "npx ozmoz login" once.'),process.env.FLEETBO_START||l(`
27
+ [OZmoz] Done. Restart your agent so it reloads the tools and instruction files.
28
+ `)}function xe(e){let o=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";oe(`${o} "${e}"`)}function Ce(e){return new Promise((o,s)=>{let t=ne.createServer((a,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"),a.method==="OPTIONS"){n.writeHead(204),n.end();return}let d=new URL(a.url,"http://127.0.0.1");if(d.pathname==="/callback"){let i=d.searchParams.get("token"),m=d.searchParams.get("refresh");if(!i){n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h3>Error: Missing token.</h3>");return}let u=c.join(b.homedir(),".fleetbo");r.existsSync(u)||r.mkdirSync(u,{recursive:!0}),r.writeFileSync(c.join(u,"credentials.json"),JSON.stringify({devToken:i,refreshToken:m||null,updatedAt:new Date().toISOString()},null,2));let f=c.join(e,".env");if(r.existsSync(f)){let h=r.readFileSync(f,"utf8");h.includes("FLEETBO_DEV_TOKEN=")?h=h.replace(/FLEETBO_DEV_TOKEN=.*/g,`FLEETBO_DEV_TOKEN=${i}`):h+=`
29
+ FLEETBO_DEV_TOKEN=${i}
30
+ `,r.writeFileSync(f,h,"utf8")}n.writeHead(200,{"Content-Type":"text/html; charset=utf-8",Connection:"close"}),n.end(`
33
31
  <!DOCTYPE html>
34
32
  <html>
35
33
  <head>
@@ -47,47 +45,49 @@ FLEETBO_DEV_TOKEN=${c}
47
45
  </div>
48
46
  </body>
49
47
  </html>
50
- `),d(`
51
- [ozmoZ] Developer token received and stored successfully!`),!process.env.FLEETBO_START&&!["AGENTS.md","CLAUDE.md","GEMINI.md"].some(h=>i.existsSync(a.join(e,h)))&&(d(`
52
- Next step to connect your AI agents:`),d(` npx ozmoz mcp (Configure Claude Code, Cursor, Windsurf, Devin, Codex CLI, Gemini CLI)
53
- `)),typeof o.closeAllConnections=="function"&&o.closeAllConnections(),o.close(()=>n()),setTimeout(()=>n(),300)}});o.listen(0,"127.0.0.1",()=>{let t=`https://ozmoz.io/cli-auth?port=${o.address().port}`;d(`
54
- [ozmoZ] Waiting for authentication...`),d(`If your browser does not open automatically, visit: ${t}`),Ce(t);let l=Number(process.env.FLEETBO_LOGIN_TIMEOUT_MS)||12e4;setTimeout(()=>{try{typeof o.closeAllConnections=="function"&&o.closeAllConnections()}catch{}o.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()}),o.on("error",r=>s(r))})}function je(e,n,s){return new Promise((o,r)=>{let t=JSON.stringify({enterpriseID:e,schema:n,workflow:s}),l={hostname:"fleetbo-gatekeeper.fleetbo.workers.dev",path:"/sync-schema",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(t)}},c=q.request(l,m=>{let u="";m.on("data",f=>{u+=f}),m.on("end",()=>{m.statusCode>=200&&m.statusCode<300?o(JSON.parse(u)):r(new Error(`Edge sync failed with HTTP ${m.statusCode}`))})});c.on("error",m=>r(m)),c.write(t),c.end()})}function $(e){let n=a.join(e,".env");if(!i.existsSync(n))return{};let s=i.readFileSync(n,"utf8"),o={};return s.split(`
55
- `).forEach(r=>{let[t,...l]=r.split("=");t&&l.length>0&&(o[t.trim()]=l.join("=").trim())}),o}function G(e,n){return new Promise((s,o)=>{let r=JSON.stringify({projectId:e,moduleName:n}),t={hostname:"getmodulecache-jqycakhlxa-uc.a.run.app",path:"/",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(r)}},l=q.request(t,c=>{let m="";c.on("data",u=>{m+=u}),c.on("end",()=>{if(c.statusCode>=200&&c.statusCode<300)try{let u=JSON.parse(m);if(u.success&&u.found&&u.module){let f=u.module.code||u.module.mockCode;s(typeof f=="string"?JSON.parse(f):f)}else s(null)}catch{o(new Error(`Invalid JSON response for ${n}.`))}else o(new Error(`Server error ${c.statusCode} while fetching ${n}`))})});l.on("error",c=>o(c)),l.write(r),l.end()})}var C=process.argv.slice(2),x=C[0],ke=["id","_id","userId","author","dateCreated","createdAt","_schema_version"],te=e=>ke.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 _e(e){let n=[];if(!e||typeof e!="object"||!e.collections)return{schema:e,changed:!1,notes:n};let s=JSON.parse(JSON.stringify(e));return Object.entries(s.collections).forEach(([o,r])=>{let t=U(r);t&&Object.keys(t).forEach(l=>{te(l)&&t[l]&&typeof t[l]=="object"&&t[l].required===!0&&(t[l].required=!1,n.push(o+"."+l))})}),{schema:s,changed:n.length>0,notes:n}}function Ne(e){let n=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]):n==="number"||n==="integer"||n==="float"?"0":n==="boolean"||n==="toggle"?"false":n==="date"||n==="datetime"||n==="timestamp"?"new Date().toISOString()":n==="reference"?"'<id du document li\xE9>'":n==="media"?"null /* image/fichier : oz.addWithMedia */":n==="array"?"[]":"'\u2026'"}function Ie(e){let s=Object.entries(e&&e.collections||{}),o=`## \u{1F4E5} CE QUE LE CODE DOIT ENVOYER (MOD\xC8LES D'\xC9CRITURE)
48
+ `),l(`
49
+ [OZmoz] Developer token received and stored successfully!`),!process.env.FLEETBO_START&&!["AGENTS.md","CLAUDE.md","GEMINI.md"].some(h=>r.existsSync(c.join(e,h)))&&(l(`
50
+ Next step to connect your AI agents:`),l(` npx ozmoz mcp (Configure Claude Code, Cursor, Windsurf, Devin, Codex CLI, Gemini CLI)
51
+ `)),typeof t.closeAllConnections=="function"&&t.closeAllConnections(),t.close(()=>o()),setTimeout(()=>o(),300)}});t.listen(0,"127.0.0.1",()=>{let n=`https://ozmoz.io/cli-auth?port=${t.address().port}`;l(`
52
+ [OZmoz] Waiting for authentication...`),l(`If your browser does not open automatically, visit: ${n}`),xe(n);let d=Number(process.env.FLEETBO_LOGIN_TIMEOUT_MS)||12e4;setTimeout(()=>{try{typeof t.closeAllConnections=="function"&&t.closeAllConnections()}catch{}t.close(),s(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()}),t.on("error",a=>s(a))})}function Ae(e,o,s){return new Promise((t,a)=>{let n=JSON.stringify({enterpriseID:e,schema:o,workflow:s}),d={hostname:"fleetbo-gatekeeper.fleetbo.workers.dev",path:"/sync-schema",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(n)}},i=q.request(d,m=>{let u="";m.on("data",f=>{u+=f}),m.on("end",()=>{m.statusCode>=200&&m.statusCode<300?t(JSON.parse(u)):a(new Error(`Edge sync failed with HTTP ${m.statusCode}`))})});i.on("error",m=>a(m)),i.write(n),i.end()})}function U(e){let o=c.join(e,".env");if(!r.existsSync(o))return{};let s=r.readFileSync(o,"utf8"),t={};return s.split(`
53
+ `).forEach(a=>{let[n,...d]=a.split("=");n&&d.length>0&&(t[n.trim()]=d.join("=").trim())}),t}function G(e,o){return new Promise((s,t)=>{let a=JSON.stringify({projectId:e,moduleName:o}),n={hostname:"getmodulecache-jqycakhlxa-uc.a.run.app",path:"/",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(a)}},d=q.request(n,i=>{let m="";i.on("data",u=>{m+=u}),i.on("end",()=>{if(i.statusCode>=200&&i.statusCode<300)try{let u=JSON.parse(m);if(u.success&&u.found&&u.module){let f=u.module.code||u.module.mockCode;s(typeof f=="string"?JSON.parse(f):f)}else s(null)}catch{t(new Error(`Invalid JSON response for ${o}.`))}else t(new Error(`Server error ${i.statusCode} while fetching ${o}`))})});d.on("error",i=>t(i)),d.write(a),d.end()})}var C=process.argv.slice(2),x=C[0],je=["id","_id","userId","author","dateCreated","createdAt","_schema_version"],te=e=>je.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 ke(e){let o=[];if(!e||typeof e!="object"||!e.collections)return{schema:e,changed:!1,notes:o};let s=JSON.parse(JSON.stringify(e));return Object.entries(s.collections).forEach(([t,a])=>{let n=M(a);n&&Object.keys(n).forEach(d=>{te(d)&&n[d]&&typeof n[d]=="object"&&n[d].required===!0&&(n[d].required=!1,o.push(t+"."+d))})}),{schema:s,changed:o.length>0,notes:o}}function _e(e){let o=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]):o==="number"||o==="integer"||o==="float"?"0":o==="boolean"||o==="toggle"?"false":o==="date"||o==="datetime"||o==="timestamp"?"new Date().toISOString()":o==="reference"?"'<id du document li\xE9>'":o==="media"?"null /* image/fichier : oz.addWithMedia */":o==="array"?"[]":"'\u2026'"}function Ne(e){let s=Object.entries(e&&e.collections||{}),t=`## \u{1F4E5} CE QUE LE CODE DOIT ENVOYER (MOD\xC8LES D'\xC9CRITURE)
56
54
 
57
- `;o+=`### \u{1F194} Identifiants
58
- `,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 r=s.filter(([,t])=>U(t)&&Object.keys(U(t)).length>0);return r.length===0?o+`_Aucune collection scell\xE9e pour l'instant : les mod\xE8les appara\xEEtront apr\xE8s la mod\xE9lisation d'Alex._
59
- `:(r.forEach(([t,l])=>{let c=U(l),m=Object.entries(c).filter(([h])=>!te(h));o+="### `"+t+`\`
55
+ `;t+=`### \u{1F194} Identifiants
56
+ `,t+="* 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",t+="* N'envoie **jamais** `id` ni `_id` dans `oz.add` : `oz.add` renvoie `{ success, documentId }` (`documentId` = `_id`).\n",t+="* 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",t+="* `userId`, `createdAt` et les autres champs de tra\xE7abilit\xE9 sont renseign\xE9s par le moteur : ne les envoie pas.\n\n";let a=s.filter(([,n])=>M(n)&&Object.keys(M(n)).length>0);return a.length===0?t+`_Aucune collection scell\xE9e pour l'instant : les mod\xE8les appara\xEEtront apr\xE8s la mod\xE9lisation d'Alex._
57
+ `:(a.forEach(([n,d])=>{let i=M(d),m=Object.entries(i).filter(([h])=>!te(h));t+="### `"+n+`\`
60
58
 
61
59
  | Champ | Type | Obligatoire | Valeurs / remarques |
62
60
  |---|---|---|---|
63
- `,m.forEach(([h,p])=>{let O=typeof p=="string"?p:p&&p.type||"any",v=p&&(p.enum||p.values||p.options),E=Array.isArray(v)&&v.length?"parmi : "+v.map(y=>"`"+y+"`").join(", "):"";o+="| `"+h+"` | "+O+" | "+(p&&p.required===!0?"\u2705 oui":"non")+" | "+E+` |
64
- `});let u=m.filter(([,h])=>h&&h.required===!0),f=m.filter(([,h])=>!(h&&h.required===!0));o+="\nInsertion valide :\n```js\nawait oz.add('"+t+`', {
65
- `,u.forEach(([h,p])=>{o+=" "+h+": "+Ne(p)+`,
66
- `}),f.length&&(o+=" // optionnels : "+f.map(([h])=>h).join(", ")+`
67
- `),o+=`}, {
68
- `,o+=" desc: 'Cr\xE9ation d\\'un \xE9l\xE9ment dans "+t+`',
69
- `,o+=` role: 'AUTHENTICATED' // ou 'ANONYMOUS', 'ADMIN'
70
- `,o+=` // guard: 'condition sur les donn\xE9es' (optionnel)
71
- `,o+="});\n```\n\n"}),o)}function Pe(e,n,s=""){let o=e?.context||n?.context||"No written specifications provided.";return`# THE OZMOZ DATA CONTRACT (SVRO DATA CONTRACT)
61
+ `,m.forEach(([h,p])=>{let z=typeof p=="string"?p:p&&p.type||"any",S=p&&(p.enum||p.values||p.options),v=Array.isArray(S)&&S.length?"parmi : "+S.map(O=>"`"+O+"`").join(", "):"";t+="| `"+h+"` | "+z+" | "+(p&&p.required===!0?"\u2705 oui":"non")+" | "+v+` |
62
+ `});let u=m.filter(([,h])=>h&&h.required===!0),f=m.filter(([,h])=>!(h&&h.required===!0));t+="\nInsertion valide :\n```js\nawait oz.add('"+n+`', {
63
+ `,u.forEach(([h,p])=>{t+=" "+h+": "+_e(p)+`,
64
+ `}),f.length&&(t+=" // optionnels : "+f.map(([h])=>h).join(", ")+`
65
+ `),t+=`}, {
66
+ `,t+=" desc: 'Cr\xE9ation d\\'un \xE9l\xE9ment dans "+n+`',
67
+ `,t+=` role: 'AUTHENTICATED' // ou 'ANONYMOUS', 'ADMIN'
68
+ `,t+=` // guard: 'condition sur les donn\xE9es' (optionnel)
69
+ `,t+="});\n```\n\n"}),t)}function Ie(e,o,s=""){let t=e?.context||o?.context||"No written specifications provided.";return`# THE OZMOZ DATA CONTRACT (SVRO DATA CONTRACT)
72
70
 
73
71
  ### \u{1F6A8} MANDATORY CODE RULES (READ BEFORE WRITING ANY VIEW)
74
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\`.
75
73
  2. **Mock Data (\`oz.seed\`):** assign an \`_id\` to each item (e.g., \`_id: 'p1'\`), never an \`id\` field: Alex would interpret \`id\` as a business field. Relations reuse these \`_id\` values (e.g., \`playlistId: 'p1'\`).
76
- 3. **Insertion:** never send \`_id\` or \`id\` to \`oz.add\` (ozmoZ assigns them automatically); send strictly the fields defined in the contract ("WHAT CODE MUST SEND" section).
77
- 4. **Errors:** after \`oz.add\`, \`oz.update\`, and \`oz.delete\`, assign the return value (\`const res = await ...\`), inspect \`res.success\`, and display \`res.error\` to the user; never hide or swallow a rejection.
74
+ 3. **Insertion:** never send \`_id\` or \`id\` to \`oz.add\` (OZmoz assigns them automatically); send strictly the fields defined in the contract ("WHAT CODE MUST SEND" section).
75
+ 4. **Mutations vs Reads return signatures:**
76
+ - **Writes (\`oz.add\`, \`oz.update\`, \`oz.delete\`):** return \`{ success, documentId, error }\`. You MUST check \`if (!res.success)\`.
77
+ - **Reads (\`oz.getDocsG\`, \`oz.getDocsU\`):** return the **raw array directly** (\`const list = await oz.getDocsG('table')\`). NEVER check \`res.success\` or \`res.data\` on reads.
78
+ - **Single read (\`oz.getDoc\`):** returns the **document object directly** or \`null\`.
78
79
  5. **Governance:** every write call must include its 3rd argument \`{ desc, guard, role }\` (4th argument for \`update\`). The \`guard\` must be a strict, executable boolean expression evaluated at the Edge (no plain text); \`role\` must be \`'ANONYMOUS'\`, \`'AUTHENTICATED'\`, or an explicit business role.
79
80
  6. **Display:** for any field that can be empty or requires formatting, use exclusively native \`<oz-*>\` tags.
80
-
81
81
  ---
82
82
 
83
- This document constitutes the **Official Specifications and Bilateral Integrity Contract** binding client code (developer or AI agent) and the ozmoZ SVRO Data OS engine.
83
+ 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
84
 
85
85
  ### Why do we call it a "Contract"?
86
86
  * **A single, sealed source of truth (in production)**: Defines all business rules, strict types, ReBAC permissions, and state machines. It is absolutely authoritative for live data consumption (\`OZ_PROTOTYPE=false\`).
87
87
  * **A deterministic integrity shield**: Any non-compliant frontend call is rejected immediately at the Edge (HTTP 422) before reaching the database in production mode (\`OZ_PROTOTYPE=false\`).
88
88
  * **A bilateral execution agreement**:
89
89
  1. **The Agent / Developer** commits to sending only specified structures without inventing intermediate APIs or bypassing the schema.
90
- 2. **ozmoZ Engine** guarantees persistence, media storage, deterministic synchronization, and native TypeScript typing without an intermediate API.
90
+ 2. **OZmoz Engine** guarantees persistence, media storage, deterministic synchronization, and native TypeScript typing without an intermediate API.
91
91
 
92
92
  ---
93
93
 
@@ -134,7 +134,7 @@ ${s}
134
134
 
135
135
  ### Step 4: Edge Sealing, Global Typing & Markdown Contract
136
136
  * Execute \`npx ozmoz sync\` (or \`--check-only\` for a local offline check).
137
- * O(1) Cloudflare Gatekeeper lockdown and IDE type compilation.
137
+ * O(1) OZmoz Gatekeeper lockdown and IDE type compilation.
138
138
 
139
139
  ### Step 5: Instant Live Switch
140
140
  * Set \`OZ_PROTOTYPE=false\` in \`.env\` with explicit user approval.
@@ -144,7 +144,7 @@ ${s}
144
144
  # \u{1F4E6} EXISTING APPLICATION MIGRATION GUIDE (BROWNFIELD)
145
145
 
146
146
  \`\`\`javascript
147
- // Targeted ozmoZ data declaration with governance
147
+ // Targeted OZmoz data declaration with governance
148
148
  const updateStatus = async (orderId, newStatus) => {
149
149
  const res = await oz.update('orders', orderId, { status: newStatus }, {
150
150
  desc: 'Order status update by a logistics operator',
@@ -153,7 +153,7 @@ const updateStatus = async (orderId, newStatus) => {
153
153
  });
154
154
 
155
155
  if (!res.success) {
156
- console.error('[ozmoZ SVRO] Edge Rejection:', res.error);
156
+ console.error('[OZmoz SVRO] Edge Rejection:', res.error);
157
157
  handleError(res.error);
158
158
  }
159
159
  };
@@ -163,7 +163,7 @@ const updateStatus = async (orderId, newStatus) => {
163
163
 
164
164
  ## \u{1F3DB}\uFE0F ARCHITECTURAL DOCTRINE & TECHNICAL DEFENSE
165
165
 
166
- | Pillar | Traditional Approach (Express / NestJS / Prisma) | ozmoZ SVRO Approach |
166
+ | Pillar | Traditional Approach (Express / NestJS / Prisma) | OZmoz SVRO Approach |
167
167
  |---|---|---|
168
168
  | **Velocity** | 2 to 3 days: boilerplate, ORM, middlewares, CRUD routes. | Immediate: zero intermediate API, direct read/write via SDK. |
169
169
  | **Governance** | Scattered modeling or permissive NoSQL without strict runtime typing. | Dual immutable contract (\`svro.schema.json\` + \`svro.workflow.json\`). |
@@ -189,11 +189,11 @@ const updateStatus = async (orderId, newStatus) => {
189
189
  ---
190
190
 
191
191
  ## \u{1F4CB} BUSINESS SPECIFICATIONS (PROJECT CONTEXT)
192
- ${o}
192
+ ${t}
193
193
 
194
194
  ---
195
195
 
196
- ${Ie(e)}
196
+ ${Ne(e)}
197
197
 
198
198
  ---
199
199
 
@@ -206,32 +206,32 @@ ${JSON.stringify(e||{},null,2)}
206
206
 
207
207
  ## \u2699\uFE0F GOVERNANCE AND WORKFLOW CONTRACT (svro.workflow.json)
208
208
  \`\`\`json
209
- ${JSON.stringify(n||{},null,2)}
209
+ ${JSON.stringify(o||{},null,2)}
210
210
  \`\`\`
211
- `}function De(e){return String(e).toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[^a-z0-9]/g,"_").replace(/^_+|_+$/g,"").slice(0,30)||"app"}async function Fe(e,n){let s=$(e),o=i.existsSync(a.join(e,"svro.schema.json"));(s.OZ_DB_KEY||o)&&(z("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 r=(n||"").trim();r||(z('Project name is required. Usage: npx ozmoz create "<name>"'),process.exit(1));let t=a.join(e,".ozmoz.lock");if(i.existsSync(t)){let c=!1;try{let m=Number(i.readFileSync(t,"utf8"));Date.now()-m>6e4&&(c=!0)}catch{c=!0}c||(z("A project creation is already running in this folder."),process.exit(1)),i.unlinkSync(t)}i.writeFileSync(t,String(Date.now()));let l=()=>{if(i.existsSync(t))try{i.unlinkSync(t)}catch{}};try{let c=process.env.FLEETBO_DEV_TOKEN;if(!c){let v=a.join(w.homedir(),".fleetbo","credentials.json");if(i.existsSync(v))try{c=JSON.parse(i.readFileSync(v,"utf8")).devToken}catch{}}c||(l(),z('Missing developer token. Please run "npx ozmoz login" first.'),process.exit(1)),d(`[ozmoZ] Creating project "${r}" on Cloud...`);let m=De(r),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,h=null;for(let v of u)try{let E=await fetch("https://createprojectlight-jqycakhlxa-uc.a.run.app",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${c}`},body:JSON.stringify({data:{name:r,keyApp:v}})}),y=await E.json();if(E.ok&&!y.error){f={keyApp:v,data:y.result?.data||y.data||{}};break}else h=y.error?.message||`HTTP ${E.status}`}catch(E){h=E.message}f||(l(),z(`Failed to create project on Cloud: ${h||"Unknown error"}`),process.exit(1));let p=f.data.bootstrapToken;await W(e,[`--keyApp=${f.keyApp}`,`--token=${p}`]);let O=a.join(e,"package.json");K(e,O),await ee(e,[]),d(`
212
- [ozmoZ] Project "${r}" (${f.keyApp}) created and configured successfully.`),d(`Next step: scaffold the frontend if needed, then run "npx ozmoz sync".
213
- `)}finally{if(i.existsSync(t))try{i.unlinkSync(t)}catch{}}}async function Le(e){let n=process.env.FLEETBO_DEV_TOKEN;if(!n){let p=a.join(w.homedir(),".fleetbo","credentials.json");if(i.existsSync(p))try{n=JSON.parse(i.readFileSync(p,"utf8")).devToken}catch{}}let o=$(e).OZ_KEY_APP;(!o||!n)&&(z("Cannot update: project uninitialized or dev token missing."),process.exit(1));let r=i.existsSync(a.join(e,"src"))?a.join(e,"src"):e,t=new Set([".jsx",".tsx",".vue",".svelte",".js",".ts",".html"]),l=[],c=0;function m(p){let O=[];try{O=i.readdirSync(p,{withFileTypes:!0})}catch{return}for(let v of O){if(/^(node_modules|\.git|dist|build|\.next|\.svelte-kit)$/.test(v.name))continue;let E=a.join(p,v.name);if(v.isDirectory())m(E);else if(t.has(a.extname(v.name))&&!v.name.endsWith(".d.ts"))try{let y=i.statSync(E);if(y.size>3e5)continue;let D=i.readFileSync(E,"utf8");/oz\.|<oz-/i.test(D)&&(c+=y.size,l.push({name:a.relative(e,E).split(a.sep).join("/"),content:D}))}catch{}}}m(r),l.length===0&&(z("Cannot update: no components using oz.* found."),process.exit(1)),c>8*1024*1024&&(z("Payload too large: total UI source files exceed 8 MB limit."),process.exit(1));let u=C.find(p=>p.startsWith("--rules=")),f=u?u.slice(8).trim():"";d(`[ozmoZ] Sending ${l.length} component(s) to Cloud Engine for modeling...`);try{let p=await fetch("https://updateprojectlight-jqycakhlxa-uc.a.run.app",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({data:{keyApp:o,name:o,newViewFiles:l,fleetbo_rules:f}})}),O=await p.json();(!p.ok||O.error)&&(z(`Update failed: ${O.error?.message||O.message||"Server error"}`),process.exit(1))}catch(p){z(`Network error: ${p.message}`),process.exit(1)}d("\u2192 Structure modeled. Sealing into SVRO Kernel..."),j(process.execPath,[__filename,"sync"],{stdio:"inherit",cwd:e}).status===0?d(`
214
- [ozmoZ] Contract successfully locked into SVRO Kernel.
215
- `):(z(`
216
- [ozmoZ] Kernel sync failed. Run "npx ozmoz sync" manually.
217
- `),process.exit(1))}async function Re(){let e=process.cwd(),n=a.join(e,"package.json");if(x==="init"||x==="doctor")d(`
218
- [ozmoZ] Initializing and configuring ozmoZ...`),await W(e,C),K(e,n),d(`
219
- [ozmoZ] Configuration completed successfully!
220
- `),d(`
221
- Next step:`),d(` npx ozmoz sync (Sync cloud schema & generate IDE types)
222
- `);else if(x==="sync"){let s=C.includes("--dry-run"),o=C.includes("--check-only");d(`[ozmoZ] Syncing schema...${s?" (dry-run)":""}${o?" (check-only, no network)":""}`),s||le(e);let r=a.join(e,"svro.schema.json"),t=a.join(e,"svro.workflow.json"),l=a.join(e,"ozmoz_contract.md"),c=a.join(e,"src","ozmoz.d.ts"),u=$(e).OZ_ENTERPRISE_ID,f=null,h=null;if(o)d("\u2192 Mode check-only : Local contract used, no cloud fetch..");else if(u)try{d("\u2192 Fetching latest contracts from Cloud..."),f=await G(u,"svro.schema.json"),f&&(i.writeFileSync(r,JSON.stringify(f,null,2)+`
223
- `),d("\u2192 Local svro.schema.json updated.")),h=await G(u,"svro.workflow.json"),h&&(i.writeFileSync(t,JSON.stringify(h,null,2)+`
224
- `),d("\u2192 Local svro.workflow.json updated."))}catch(y){z(`\u26A0\uFE0F Cloud fetch bypassed: ${y.message}. Using local file fallback.`)}else z("\u26A0\uFE0F OZ_ENTERPRISE_ID missing in .env. Skipping cloud fetch.");let p=f;if(!p&&i.existsSync(r))try{p=JSON.parse(i.readFileSync(r,"utf8"))}catch{}p||(p={context:"Application en cours de mod\xE9lisation initiale.",collections:{}},i.writeFileSync(r,JSON.stringify(p,null,2)+`
225
- `,"utf8"),d("\u2192 Initial blank svro.schema.json created."));let O=h;if(!O&&i.existsSync(t))try{O=JSON.parse(i.readFileSync(t,"utf8"))}catch{}O||(O={actors:{},sequences:[]},i.writeFileSync(t,JSON.stringify(O,null,2)+`
226
- `,"utf8"),d("\u2192 Initial blank svro.workflow.json created."));{let y=_e(p);y.changed&&(p=y.schema,i.writeFileSync(r,JSON.stringify(p,null,2)+`
227
- `,"utf8"),d("\u2192 Managed by system, no longer required from your code: "+y.notes.join(", ")+"."))}let{protocol:v}=await X(),E=Pe(p,O,v);i.writeFileSync(l,E,"utf8"),d("\u2192 Contract markdown successfully generated at project root.");try{let y=Object.keys(p.collections||{});if(u&&!o)try{await je(u,p,O),d("\u2192 Schema successfully sealed into SVRO Kernel (O(1)).")}catch(g){z(`\u26A0\uFE0F Kernel Shield sync warning: ${g.message}`)}let D=p.collections||{},F=Object.entries(D).map(([g,T])=>{let S=T.fields||T.schema||{},A=Object.entries(S).map(([L,k])=>{let R="any",_=String(typeof k=="string"?k:k.type||"").toLowerCase();return _==="string"||_==="text"||_==="media"?R="string":_==="number"?R="number":_==="boolean"||_==="toggle"?R="boolean":_==="array"&&(R="any[]"),` ${L}?:${R};`}).join(`
211
+ `}function Pe(e){return String(e).toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[^a-z0-9]/g,"_").replace(/^_+|_+$/g,"").slice(0,30)||"app"}async function De(e,o){let s=U(e),t=r.existsSync(c.join(e,"svro.schema.json"));(s.OZ_DB_KEY||t)&&(y("Cannot create project: an OZmoz project already exists in this folder."),l('\u2192 Use "npx ozmoz sync" or evolve the existing contract instead.'),process.exit(1));let a=(o||"").trim();a||(y('Project name is required. Usage: npx ozmoz create "<name>"'),process.exit(1));let n=c.join(e,".ozmoz.lock");if(r.existsSync(n)){let i=!1;try{let m=Number(r.readFileSync(n,"utf8"));Date.now()-m>6e4&&(i=!0)}catch{i=!0}i||(y("A project creation is already running in this folder."),process.exit(1)),r.unlinkSync(n)}r.writeFileSync(n,String(Date.now()));let d=()=>{if(r.existsSync(n))try{r.unlinkSync(n)}catch{}};try{let i=process.env.FLEETBO_DEV_TOKEN;if(!i){let S=c.join(b.homedir(),".fleetbo","credentials.json");if(r.existsSync(S))try{i=JSON.parse(r.readFileSync(S,"utf8")).devToken}catch{}}i||(d(),y('Missing developer token. Please run "npx ozmoz login" first.'),process.exit(1)),l(`[OZmoz] Creating project "${a}" on Cloud...`);let m=Pe(a),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,h=null;for(let S of u)try{let v=await fetch("https://createprojectlight-jqycakhlxa-uc.a.run.app",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${i}`},body:JSON.stringify({data:{name:a,keyApp:S}})}),O=await v.json();if(v.ok&&!O.error){f={keyApp:S,data:O.result?.data||O.data||{}};break}else h=O.error?.message||`HTTP ${v.status}`}catch(v){h=v.message}f||(d(),y(`Failed to create project on Cloud: ${h||"Unknown error"}`),process.exit(1));let p=f.data.bootstrapToken;await K(e,[`--keyApp=${f.keyApp}`,`--token=${p}`]);let z=c.join(e,"package.json");W(e,z),await ee(e,[]),l(`
212
+ [OZmoz] Project "${a}" (${f.keyApp}) created and configured successfully.`),l(`Next step: scaffold the frontend if needed, then run "npx ozmoz sync".
213
+ `)}finally{if(r.existsSync(n))try{r.unlinkSync(n)}catch{}}}async function Fe(e){let o=process.env.FLEETBO_DEV_TOKEN;if(!o){let p=c.join(b.homedir(),".fleetbo","credentials.json");if(r.existsSync(p))try{o=JSON.parse(r.readFileSync(p,"utf8")).devToken}catch{}}let t=U(e).OZ_KEY_APP;(!t||!o)&&(y("Cannot update: project uninitialized or dev token missing."),process.exit(1));let a=r.existsSync(c.join(e,"src"))?c.join(e,"src"):e,n=new Set([".jsx",".tsx",".vue",".svelte",".js",".ts",".html"]),d=[],i=0;function m(p){let z=[];try{z=r.readdirSync(p,{withFileTypes:!0})}catch{return}for(let S of z){if(/^(node_modules|\.git|dist|build|\.next|\.svelte-kit)$/.test(S.name))continue;let v=c.join(p,S.name);if(S.isDirectory())m(v);else if(n.has(c.extname(S.name))&&!S.name.endsWith(".d.ts"))try{let O=r.statSync(v);if(O.size>3e5)continue;let P=r.readFileSync(v,"utf8");/oz\.|<oz-/i.test(P)&&(i+=O.size,d.push({name:c.relative(e,v).split(c.sep).join("/"),content:P}))}catch{}}}m(a),d.length===0&&(y("Cannot update: no components using oz.* found."),process.exit(1)),i>8*1024*1024&&(y("Payload too large: total UI source files exceed 8 MB limit."),process.exit(1));let u=C.find(p=>p.startsWith("--rules=")),f=u?u.slice(8).trim():"";l(`[OZmoz] Sending ${d.length} component(s) to Cloud Engine for modeling...`);try{let p=await fetch("https://updateprojectlight-jqycakhlxa-uc.a.run.app",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({data:{keyApp:t,name:t,newViewFiles:d,fleetbo_rules:f}})}),z=await p.json();(!p.ok||z.error)&&(y(`Update failed: ${z.error?.message||z.message||"Server error"}`),process.exit(1))}catch(p){y(`Network error: ${p.message}`),process.exit(1)}l("\u2192 Structure modeled. Sealing into SVRO Kernel..."),j(process.execPath,[__filename,"sync"],{stdio:"inherit",cwd:e}).status===0?l(`
214
+ [OZmoz] Contract successfully locked into SVRO Kernel.
215
+ `):(y(`
216
+ [OZmoz] Kernel sync failed. Run "npx ozmoz sync" manually.
217
+ `),process.exit(1))}async function Le(){let e=process.cwd(),o=c.join(e,"package.json");if(x==="init"||x==="doctor")l(`
218
+ [OZmoz] Initializing and configuring OZmoz...`),await K(e,C),W(e,o),l(`
219
+ [OZmoz] Configuration completed successfully!
220
+ `),l(`
221
+ Next step:`),l(` npx ozmoz sync (Sync cloud schema & generate IDE types)
222
+ `);else if(x==="sync"){let s=C.includes("--dry-run"),t=C.includes("--check-only");l(`[OZmoz] Syncing schema...${s?" (dry-run)":""}${t?" (check-only, no network)":""}`),s||le(e);let a=c.join(e,"svro.schema.json"),n=c.join(e,"svro.workflow.json"),d=c.join(e,"ozmoz_contract.md"),i=c.join(e,"src","ozmoz.d.ts"),u=U(e).OZ_ENTERPRISE_ID,f=null,h=null;if(t)l("\u2192 Mode check-only : Local contract used, no cloud fetch..");else if(u)try{l("\u2192 Fetching latest contracts from Cloud..."),f=await G(u,"svro.schema.json"),f&&(r.writeFileSync(a,JSON.stringify(f,null,2)+`
223
+ `),l("\u2192 Local svro.schema.json updated.")),h=await G(u,"svro.workflow.json"),h&&(r.writeFileSync(n,JSON.stringify(h,null,2)+`
224
+ `),l("\u2192 Local svro.workflow.json updated."))}catch(O){y(`\u26A0\uFE0F Cloud fetch bypassed: ${O.message}. Using local file fallback.`)}else y("\u26A0\uFE0F OZ_ENTERPRISE_ID missing in .env. Skipping cloud fetch.");let p=f;if(!p&&r.existsSync(a))try{p=JSON.parse(r.readFileSync(a,"utf8"))}catch{}p||(p={context:"Application en cours de mod\xE9lisation initiale.",collections:{}},r.writeFileSync(a,JSON.stringify(p,null,2)+`
225
+ `,"utf8"),l("\u2192 Initial blank svro.schema.json created."));let z=h;if(!z&&r.existsSync(n))try{z=JSON.parse(r.readFileSync(n,"utf8"))}catch{}z||(z={actors:{},sequences:[]},r.writeFileSync(n,JSON.stringify(z,null,2)+`
226
+ `,"utf8"),l("\u2192 Initial blank svro.workflow.json created."));{let O=ke(p);O.changed&&(p=O.schema,r.writeFileSync(a,JSON.stringify(p,null,2)+`
227
+ `,"utf8"),l("\u2192 Managed by system, no longer required from your code: "+O.notes.join(", ")+"."))}let{protocol:S}=await X(),v=Ie(p,z,S);r.writeFileSync(d,v,"utf8"),l("\u2192 Contract markdown successfully generated at project root.");try{let O=Object.keys(p.collections||{});if(u&&!t)try{await Ae(u,p,z),l("\u2192 Schema successfully sealed into SVRO Kernel (O(1)).")}catch(g){y(`\u26A0\uFE0F Kernel Shield sync warning: ${g.message}`)}let P=p.collections||{},D=Object.entries(P).map(([g,E])=>{let w=E.fields||E.schema||{},T=Object.entries(w).map(([$,k])=>{let F="any",_=String(typeof k=="string"?k:k.type||"").toLowerCase();return _==="string"||_==="text"||_==="media"?F="string":_==="number"?F="number":_==="boolean"||_==="toggle"?F="boolean":_==="array"&&(F="any[]"),` ${$}?:${F};`}).join(`
228
228
  `);return` ${g}: {
229
- ${A}
229
+ ${T}
230
230
  };`}).join(`
231
- `),Z=y.length>0?y.map(g=>`'${g}'`).join(" | "):"string";if(i.existsSync(a.dirname(c))){let g=`/* eslint-disable */
231
+ `),R=O.length>0?O.map(g=>`'${g}'`).join(" | "):"string";if(r.existsSync(c.dirname(i))){let g=`/* eslint-disable */
232
232
  /* prettier-ignore */
233
233
  // @ts-nocheck
234
- // Generated by ozmoZ \u2014 Updated via sync
234
+ // Generated by OZmoz \u2014 Updated via sync
235
235
  export {}
236
236
 
237
237
  type OzProp = {
@@ -257,11 +257,11 @@ type OzProp = {
257
257
  };
258
258
 
259
259
  interface OzSchemaMap {
260
- ${F}
260
+ ${D}
261
261
  }
262
262
 
263
263
  declare global {
264
- type KnownOzTables = ${Z};
264
+ type KnownOzTables = ${R};
265
265
  type OzTables = KnownOzTables | (string & { _ozPending?: never });
266
266
  type OzData<T extends string> = T extends KnownOzTables
267
267
  ? Partial<OzSchemaMap[T]>
@@ -364,7 +364,7 @@ declare module 'svelte/elements' {
364
364
  'oz-reference': OzProp;
365
365
  }
366
366
  }
367
- `;i.writeFileSync(c,g)}re(e),ae(e,n),ce(e),de(e),d(`[ozmoZ] Schema synced successfully (${y.length} collection(s)).`),s&&d("\u2192 [Dry-run] Schema is valid.")}catch(y){z(`Error during synchronization: ${y.message}`),process.exit(1)}}else if(x==="create"){let s=C.slice(1).filter(o=>!o.startsWith("--")).join(" ");await Fe(e,s),process.exit(0)}else if(x==="update")await Le(e),process.exit(0);else if(x==="mcp"){let s=C.includes("--run"),o=!1;if(!s&&!process.stdin.isTTY&&(s=await new Promise(r=>{let t=process.stdin,l=null,c=f=>{clearTimeout(l),t.removeListener("data",m),t.removeListener("end",u),t.removeListener("error",u),r(f)},m=f=>{t.pause(),t.unshift(f),o=!0,c(!0)},u=()=>c(!1);l=setTimeout(()=>{t.pause(),c(!1)},1500),t.on("data",m),t.once("end",u),t.once("error",u)})),s){try{await import(`file://${Q()}`),o&&process.stdin.resume()}catch(r){z(`Failed to start MCP server: ${r.message}`),process.exit(1)}return}await ee(e,C),process.exit(0)}else x==="login"?(await Ae(e),process.exit(0)):x==="start"?xe(e,C):["--help","-h","help"].includes(x)?(d(`ozmoZ CLI
367
+ `;r.writeFileSync(i,g)}re(e),ae(e,o),ce(e),de(e),l(`[OZmoz] Schema synced successfully (${O.length} collection(s)).`),s&&l("\u2192 [Dry-run] Schema is valid.")}catch(O){y(`Error during synchronization: ${O.message}`),process.exit(1)}}else if(x==="create"){let s=C.slice(1).filter(t=>!t.startsWith("--")).join(" ");await De(e,s),process.exit(0)}else if(x==="update")await Fe(e),process.exit(0);else if(x==="mcp"){let s=C.includes("--run"),t=!1;if(!s&&!process.stdin.isTTY&&(s=await new Promise(a=>{let n=process.stdin,d=null,i=f=>{clearTimeout(d),n.removeListener("data",m),n.removeListener("end",u),n.removeListener("error",u),a(f)},m=f=>{n.pause(),n.unshift(f),t=!0,i(!0)},u=()=>i(!1);d=setTimeout(()=>{n.pause(),i(!1)},1500),n.on("data",m),n.once("end",u),n.once("error",u)})),s){try{await import(`file://${Q()}`),t&&process.stdin.resume()}catch(a){y(`Failed to start MCP server: ${a.message}`),process.exit(1)}return}await ee(e,C),process.exit(0)}else x==="login"?(await Ce(e),process.exit(0)):x==="start"?be(e,C):["--help","-h","help"].includes(x)?(l(`OZmoz CLI
368
368
 
369
369
  Commands:
370
370
  login Authenticate this machine (opens the browser: approve once, the command exits by itself)
@@ -380,4 +380,4 @@ Commands:
380
380
 
381
381
  AI agents: to create a project, call the MCP tool "oz_create_project".
382
382
  To evolve schema/workflow from UI files, call the MCP tool "oz_update_project", then run "sync".
383
- `),process.exit(0)):(z('Unknown command. Run "npx ozmoz --help".'),process.exit(1))}Re().catch(e=>{z(`ozmoZ CLI Error: ${e.message}`),process.exit(1)});
383
+ `),process.exit(0)):(y('Unknown command. Run "npx ozmoz --help".'),process.exit(1))}Le().catch(e=>{y(`OZmoz CLI Error: ${e.message}`),process.exit(1)});