ozmoz 0.1.8 → 0.1.11

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,123 +1,31 @@
1
1
  #!/usr/bin/env node
2
- var l=require("fs"),c=require("path"),te=require("https"),pe=require("http"),A=require("os"),{exec:me,spawnSync:I}=require("child_process"),he=[c.join(__dirname,"..","scripts","setup-lib.cjs"),c.join(__dirname,"..","..","scripts","setup-lib.cjs"),c.join(__dirname,"scripts","setup-lib.cjs")],fe=he.find(l.existsSync)||c.join(__dirname,"..","scripts","setup-lib.cjs"),{runFullSetup:ne,handleAuthAndEnv:oe,touchTsConfig:ge,attemptViteAutoImportPatch:ye,injectUniversalRuntime:ve,writeBrowserConfig:ze,patchAllowScripts:Oe}=require(fe),we="\x1B[34m",Ee="\x1B[31m",se="\x1B[0m";function m(e){console.log(`${we}${e}${se}`)}function z(e){console.error(`${Ee}${e}${se}`)}var re=`
3
- 1. YOUR FREEDOM: the entire frontend belongs to you (rendering, state, styles, navigation, components, UI logic). Only one exception: the technology (the framework), which the user chooses among supported options; you ask them before installing anything. ozmoZ only handles data, authentication, and storage. A change that does not touch data requires nobody's approval.
4
-
5
- 2. YOUR USER is not a developer. In your messages to the user (not in code), always speak in the user's language (detect it from their prompt, e.g. French if they write in French) in a plain, jargon-free manner: never say prototype, true, false, .env, contract, schema, sync, Edge, endpoint, collection, nor oz_update_project. Instead, say (adapt to their language):
6
- - "trial mode" (or \xAB mode essai \xBB) for OZ_PROTOTYPE=true, and "live mode" (or \xAB mode r\xE9el \xBB) for false;
7
- - "your data structure" (or \xAB la structure de vos donn\xE9es \xBB) for the contract;
8
- - "Alex, the assistant who prepares your data structure" (or \xAB Alex, l'assistant qui pr\xE9pare la structure de vos donn\xE9es \xBB) for Alex;
9
- - "I am saving the new structure" (or \xAB j'enregistre la nouvelle structure \xBB) for synchronization.
10
- Perform all technical tasks yourself (terminal, commands, files): never ask the user to run them. Before the first handover to Alex (5a) and before any mode switch, explain in one sentence what you are going to do and why, then wait for a simple "yes". For subsequent iterations (5b, 5c), the user's request counts as approval: simply announce what you are doing.
11
-
12
- 3. PROTOTYPE MODE (OZ_PROTOTYPE=true, "trial mode" for the user): the goal is to validate screens and the user journey.
13
- - Write UI with real wiring: oz.getDocsG / getDocsU / getDoc / add / update / delete / join, final collection and field names, type casts, <oz-*> tags.
14
- - TRIAL AUTHENTICATION & DIAGNOSTICS: wire a real screen (oz.sendotpsvro / verifyotpsvro), just like the rest (Zero-Rewrite) \u2014 no separate mocked forms. The flow remains identical to production (the tester enters an email, confirms, then enters a code, confirms): behind the scenes, trial mode sends no real emails and always accepts "0000" as the code. Show this code directly on screen (e.g., a note "Trial mode \u2014 test code: 0000") so the tester knows what to input at step two without waiting for an email that will never arrive.
15
- In trial mode (OZ_PROTOTYPE=true), all auth and data operations are 100% simulated locally. The Edge Gatekeeper and Cloud functions are bypassed:
16
- \u2022 Any verification code other than "0000" will fail, and "0000" always succeeds.
17
- \u2022 If oz.sendotpsvro or oz.verifyotpsvro fails or behaves unexpectedly, THE FAULT IS 100% INSIDE YOUR FRONTEND LOGIC (bad arguments, lost state, hardcoded UI errors).
18
- \u2022 ABSOLUTELY FORBIDDEN to run shell commands, node scripts ('node -e'), or inspect package internals to debug authentication. Review and fix your UI component code directly.
19
- \u2022 AUTH STATUS CHECK: ozmoZ automatically attaches an anonymous session on load. Calling oz.getUser() always returns an anonymous user. To check if an actual user is logged in, you MUST call 'await oz.isAuthenticated()' or check '!currentUser.isAnonymous'.
20
- - Data is virtual: oz.seed('collection', [...]) then normal read.
21
- - Zero-Rewrite also applies to UI: NEVER hardcode trial-specific text unconditionally (banner "Trial mode", hint "code 0000", etc.) \u2014 this text only makes sense in trial mode and would be false/misleading in production. Condition any such element on import.meta.env.OZ_PROTOTYPE === 'true', so it disappears on its own in production without rewriting a line. NEVER hardcode a fallback like "0000" on the client: trust the actual response from oz.sendotpsvro/verifyotpsvro, whatever it returns.
22
- - The contract can be blank: do not wait for it and do not design it. The UI dictates the fields.
23
- - Before the first structure save (5a), do not call Alex on every change: this happens when the user validates the screens.
24
- - MANDATORY SELF-REVIEW, before starting the server: review, one by one, every file you just wrote or modified that calls oz.*. For each call, explicitly verify the 5 rules in "MANDATORY CODE RULES" at the top of ozmoz_contract.md (_id identifiers, seed without bare id field, no _id/id passed to add, res.success/res.error inspected after add/update/delete, <oz-*> tags for display). Fix any violation found before proceeding \u2014 never settle for writing code once: this review is a standalone step, not a formality.
25
- - The development server only starts ONCE ALL views are written AND this self-review is complete.
26
-
27
- 4. PRODUCTION MODE (OZ_PROTOTYPE=false, "live mode" for the user): the contract is absolute law.
28
- - No field, no collection, no rule outside ozmoz_contract.md.
29
- - No mock data (oz.seed is inert). Edge errors (HTTP 422, permission-denied...) must be read and fixed: never hide them.
30
- - If a screen requires data missing from the contract: no workarounds, apply point 5b.
31
- - On the first switch to live mode, the database is empty (oz.seed is inert): warn the user in one sentence and verify that the app allows creating data (creation forms).
32
-
33
- 5. WHEN TO HAND OVER TO ALEX (in these cases, and only these cases):
34
- a) The user confirms the screens look good and wants to switch to real data: first save of their data structure. Never assume this approval. If the moment seems right, explain the situation with pedagogical empathy: remind them in simple, jargon-free words that the app currently runs in sandbox/trial mode with dummy data to test the experience safely, and that validating the visual flow is what will unlock creating their real live ozmoZ database. Ask them naturally if the interface and user journey suit their needs. DO NOT recite a robotic template: adapt your phrasing naturally to the tone and flow of the conversation. HARD STOP: NEVER call oz_update_project in the same turn...
35
- b) After this first save, data is added, modified, or deleted (collection, field, type, relation, business rule, permission): hand over as soon as the view is written.
36
- c) The user asks you to.
37
- How: call oz_update_project with name, filePaths, rules, and userApproval (the EXACT verbatim quote of the user's message authorizing this call: their approval of the screens or their request to change data; never write it yourself), then apply point 7.
38
- - filePaths: all files that call oz.* or describe data fields (views AND data files, never views alone); all files in case of doubt.
39
- - rules: only business rules provided by the user, in plain text. If you have none, ask them simply if there are rules to enforce (limits, durations, permissions); if they have none, do not send rules. Never invent a rule.
40
- Without MCP: run 'npx ozmoz update' directly in the terminal, then apply point 7.
41
- For updates, propose (without forcing) returning to trial mode first to validate screens before saving the new structure.
42
-
43
- 6. DO NOT HAND OVER TO ALEX for: styling, layout, copy, navigation, components, UI state or logic, frontend bug fixes, demo data (oz.seed).
44
-
45
- 7. SYNCHRONIZATION: after a REAL update of the backend contract (oz_update_project, or Alex in ozmoZ confirmed by the user), run npx ozmoz sync (without flags) before continuing to code, then tell the user in one sentence that the new structure has been saved. For any OTHER reason to re-verify code (ozmoz package update, simple code refactoring, compliance doubt): run npx ozmoz sync --check-only instead \u2014 never a full sync, which would contact the cloud and reseal the Edge when no data has changed.
46
-
47
- 8. NEVER: modify OZ_PROTOTYPE on your own initiative (only with explicit user consent, after explaining the difference between trial mode and live mode in one sentence); design or edit svro.schema.json and svro.workflow.json (Alex's authority); write a backend, API route, or ORM; invent oz.* methods or <oz-*> tags.
48
-
49
- 9. WRITE GOVERNANCE (MANDATORY): every oz.add / addWithId / addWithUserId / addWithMedia / update / delete call MUST carry a literal 3rd argument {desc, guard, role} (4th for update) \u2014 never optional, never omitted, even in trial mode (this parameter is never sent over the network; it only informs Alex). "desc": one sentence explaining the exact business intent of this write operation. "guard": a simple boolean condition on the "data" fields you send (e.g., "price > 0 && name.length > 2") \u2014 omit if no rule is required. "role": required access level for this action ("ANONYMOUS", "AUTHENTICATED", or an explicit business role like "MANAGER" if defined). Never invent a "guard" you cannot justify by actual screen logic; in doubt, omit "guard" rather than writing an arbitrary one. This applies to reads only if relevant (never mandatory for getDocsG/getDocsU/getDoc/join).`,k="ozmoz",q=/<!-- (?:ozmoz|fleetbo):start[^>]*-->[\s\S]*?<!-- (?:ozmoz|fleetbo):end -->/,Te="<!-- ozmoZ:end -->",ie="# OZMOZ DATA OS \u2014 DIRECTIVES SYST\xC8ME",$={claude:"Claude Code",cursor:"Cursor",windsurf:"Windsurf",devin:"Devin",codex:"Codex CLI",gemini:"Gemini CLI",antigravity:"Antigravity CLI"},Se=`D1. EVERY request to create a NEW application MUST trigger the 'oz_create_project' MCP tool. However, if the project's '.env' already contains OZ_DB_KEY (or if 'svro.schema.json' exists), the project ALREADY EXISTS: NEVER call 'oz_create_project'; use 'oz_update_project' instead ('keyApp' is the value of OZ_KEY_APP; pass it explicitly if the session was not launched from the project folder).
50
-
51
- D2. The MCP server is already pre-authenticated: do not inspect the shell ('env', 'grep'), do not traverse the filesystem outside the project root, and do not trigger a login (reading the project's '.env' is allowed). Only exception: if a tool returns "FLEETBO_DEV_TOKEN missing", run 'npx ozmoz login' ONCE, wait for it to complete (the user approves in the browser: simply notify them), then call the tool again.
52
-
53
- D3. CREATION ONLY: NEVER invent or provide a 'keyApp' yourself \u2014 call 'oz_create_project' with only 'name', never 'keyApp': the server systematically generates a unique identifier derived from the name (e.g., "Coworking Space" -> "coworking_space_x7k2"), guaranteed collision-free, without ever needing to retry. For an existing project, NEVER deduce the keyApp: read it from '.env' (OZ_KEY_APP).
54
-
55
- D4. Once creation is validated, execute the returned command ('commandInit') at the root of the Vite frontend project (first scaffold this project using the template chosen by the user in the initial question, see D10, and with Tailwind if requested, if it does not exist yet) and start writing UI code using the global oz.* object. The folder is NEVER empty at this stage (GEMINI.md, AGENTS.md, CLAUDE.md, '.gemini/', '.mcp.json'): scaffold the project with EXACTLY "npm create vite@latest ozmoz-tmp -- --template <react|vue|svelte|vanilla> --no-interactive --no-immediate" (NEVER '--overwrite', which deletes these files, nor '--immediate' or interactive mode, which START the server on the Vite starter page), move its contents to the root WITHOUT overwriting existing files, delete 'ozmoz-tmp', run 'npm install', then run 'commandInit'. No development server at this stage.
56
-
57
- D5. If 'oz_create_project' or 'oz_update_project' are missing from your tools: do NOT ask the user to restart, do NOT run 'npx ozmoz mcp', and NEVER ask the user to copy-paste into ozmoZ. Use terminal fallback commands directly:
58
- - Creation: run 'npx ozmoz create "<name>"'
59
- - Modeling update: run 'npx ozmoz update'
60
-
61
- D6. ozmoZ rule sources: this file (protocol below), 'ozmoz_contract.md' (root, generated by 'npx ozmoz sync'), and the 'oz_get_contract' MCP tool. Do not load other .md files in the project. Scope: SDK syntax rules apply in both modes; data compliance with the contract (fields, tables, rules) is only absolute if OZ_PROTOTYPE=false.
62
-
63
- D7. Before writing data code, read OZ_PROTOTYPE in the project's '.env': true = prototype (SDK local sandbox, demo data via oz.seed); false = production ('oz.*' and Edge security take over). Zero-Rewrite (philosophy): write code identically in prototype and production, without separate code paths per mode; only data can be virtual. This is a design principle, not a prohibition against fixing code.
64
-
65
- D8. For any decision regarding data (actions per mode, when to hand over to Alex, when not to, when to sync), strictly apply the DATA PROTOCOL below (identical to 'ozmoz_contract.md').
66
-
67
- D9. FRAMEWORKS: the user chooses (D10) among Vite with React, Vue 3, Svelte 5, or vanilla JavaScript. Next.js (App Router): keep 'ozmoz-runtime' and 'ozmoz-client' created next to 'layout'; restart 'next dev' or 'next build' after any '.env' change. HTML without bundler: 'ozmoz.config.js' (generated by 'init' and 'sync': re-run 'sync' after any OZ_PROTOTYPE change), then 'node_modules/ozmoz/dist/ozmoz.iife.js'. Nuxt, SvelteKit, Astro, and Angular: untested, avoid them.
68
-
69
- D10. STARTER QUESTIONS: without an ozmoZ project in the folder (no OZ_KEY_APP in '.env'), ask TWO questions before installing or creating anything, ONE AT A TIME, in this order, in plain, jargon-free language, skipping any question whose answer was already provided: (1) the technology: React (recommended), Vue, Svelte, or vanilla JavaScript (Next.js and a simple HTML page upon request; when in doubt, React); (2) a one-sentence project description, from which you deduce the application name. Install nothing and do not call 'oz_create_project' before receiving both answers. create-vite templates: 'react', 'vue', 'svelte', and 'vanilla' (JavaScript).
70
-
71
- D11. To verify a method or SDK signature, NEVER read node_modules/ozmoz (minified, unreadable, context-heavy code): rely on ozmoz_contract.md and src/ozmoz.d.ts (already present in the project) as the only references.
72
-
73
- D12. SCOPE & TRIAL DEBUGGING:
74
- - Technology Scope: Determine which tool handles each feature. If ozmoZ is used (oz.* calls or <oz-*> tags), ozmoz_contract.md and src/ozmoz.d.ts are the absolute reference. If the user explicitly requested an external service (e.g., Clerk, Auth0, custom REST API), apply that specific provider's patterns without applying ozmoZ trial shortcuts.
75
- - ozmoZ Trial Invariant: When ozmoZ handles auth or data in trial mode (OZ_PROTOTYPE=true), everything is 100% simulated locally (Edge Gatekeeper and Cloud functions are bypassed, code "0000" always succeeds).
76
- - Zero Exploratory Scripts: Never run terminal commands or node scripts ('node -e', shell tests) to probe the SDK or environment when an ozmoZ call fails. Any failure in trial mode stems 100% from your frontend component code (argument mismatches, lost state, hardcoded fallback errors). Fix your UI code directly.
77
- - Anonymous Session Trap: ozmoZ automatically attaches an anonymous session on load. 'oz.getUser()' always returns an object. Never use 'getUser() !== null' to verify login: use 'await oz.isAuthenticated()' or verify '!currentUser.isAnonymous'.
78
-
79
- D13. PACKAGE VERSION & REVISION REFLEX:
80
- - Before deep debugging or when starting a session, check the installed version of 'ozmoz' in 'package.json'.
81
- - If the package is outdated or if you suspect an SDK bug that may have been patched, update it directly using the project package manager (e.g. 'npm install ozmoz@latest').
82
- - Immediately after updating the package, run 'npx ozmoz sync --check-only' to regenerate 'src/ozmoz.d.ts' and contract types locally (never run a full cloud sync for a simple package update).
83
- - Never inspect 'node_modules/ozmoz': verify the newly updated signatures strictly in 'src/ozmoz.d.ts'.
84
-
85
- D14 (Bare Global Identifier): Call 'oz.*' directly as a bare identifier (e.g., 'await oz.sendotpsvro(email)'). NEVER access via 'window.oz' or optional chains like 'window.oz?.'. The object is globally declared in 'src/ozmoz.d.ts'. Using 'window.' circumvents static contract audits, breaks CLI regexes, and triggers false linter workarounds.
86
-
87
- D15 (CONTRACT FIRST & STRICT LAST-RESORT ESCALATION):
88
- - MANDATORY DOC CHECK: Before writing, fixing, or diagnosing ANY data code, you MUST inspect 'ozmoz_contract.md' and your instructions ('AGENTS.md' / 'GEMINI.md'). They are your absolute authority.
89
- - AUTONOMOUS RESOLUTION FIRST: Review your frontend logic, verify method signatures, cast types, check component props, and inspect 'res.error'. You must actively solve issues yourself within the frontend code.
90
- - ZERO EXPLORATION: Never execute exploratory shell scripts ('find', 'grep', 'node -e') or web searches.
91
- - LAST-RESORT ESCALATION ONLY: ONLY if you have exhausted all contract checks and code fixes, and the issue is proven to be a persistent platform or SDK bug with NO possible solution on your end, stop cleanly and tell the user:
92
- \xAB Je ne parviens pas \xE0 r\xE9soudre ce blocage malgr\xE9 la v\xE9rification du contrat et du code. En dernier recours, vous pouvez ouvrir un ticket sur https://ozmoz.io \xBB.
93
-
94
- `,P={created:"created",updated:"updated",unchanged:"already up to date",appended:"ozmoZ block appended (your own content was kept)",migrated:"old file replaced (backup: <file>.ozmoz-legacy.bak)",invalid:"skipped: the file is not valid JSON, fix or delete it first"};function be(){try{return JSON.parse(l.readFileSync(c.join(__dirname,"..","package.json"),"utf8")).version||"dev"}catch{return"dev"}}function xe(){return`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
2
+ var i=require("fs"),a=require("path"),q=require("https"),ne=require("http"),w=require("os"),{exec:oe,spawnSync:A}=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",V=/<!-- (?:ozmoz|fleetbo):start[^>]*-->[\s\S]*?<!-- (?:ozmoz|fleetbo):end -->/,me="<!-- ozmoZ:end -->",H="# OZMOZ DATA OS \u2014 DIRECTIVES SYST\xC8ME",R={claude:"Claude Code",cursor:"Cursor",windsurf:"Windsurf",devin:"Devin",codex:"Codex CLI",gemini:"Gemini CLI",antigravity:"Antigravity CLI"},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 J(e,n){return"<!-- ozmoz:start v"+e+` -->
3
+ `+n.trim()+`
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):V.test(o)?(t=o.replace(V,()=>n.trimEnd()),r=t===o?"unchanged":"updated"):o.includes(H)?(r="migrated",t=n):(r="appended",t=o.replace(/\s*$/,`
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 A(n,[e],{stdio:"ignore"}).status===0}function B(e,n,s){let o=A(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 project description is already given: "+o+". Ask me only the technology question, then build it: ask me another question only if essential information is missing.":"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). Before doing anything else, state this in one plain sentence to the user (e.g. "Ce projet existe d\xE9j\xE0, je le reprends.") so they can correct you immediately if this is wrong \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 (index.html or package.json found) \u2014 do NOT run "npm create vite" or scaffold a new frontend, you would overwrite it. Do not spend a tool call checking which framework it uses. Skip the technology question (detect it from the existing files if needed) and ask me only for a one-sentence project description, then call oz_create_project directly on this existing project.':"This folder does NOT contain an ozmoZ project yet (no .env, no svro.schema.json) \u2014 do not spend a tool call checking, proceed directly to the starter questions below. "+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=A("ps",["-A","-o","pid=,ppid=,args="],{encoding:"utf8"});if(n.status!==0)return!1;let s=new Map;n.stdout.split(`
12
+ `).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 A(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)."),A(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))),A(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(`
13
+ [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.
14
+ `),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(`
15
+ [ozmoZ] Launching `+t.bin+` in this folder...
16
+ `);let u=A(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(R):r;let g=t.filter(T=>!R[T]);g.length&&(z("Unknown agent(s): "+g.join(", ")+". Valid values: "+Object.keys(R).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(R).filter(g=>m[g]),f=fe();d(`
17
+ [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
95
18
 
96
- `+Se+`
19
+ `+(h.directives||h.guidelines||"")+`
97
20
 
98
21
  ## PROTOCOLE DONN\xC9ES : QUI FAIT QUOI (AGENT FRONTEND \u2194 ALEX AI)
99
22
 
100
- `+re}function K(e,o){return"<!-- ozmoz:start v"+e+` -->
101
- `+o.trim()+`
102
- `+Te+`
103
- `}function Ae(e,o,s){let n=l.existsSync(e)?l.readFileSync(e,"utf8"):null,a,t;return n===null?(a="created",t=o):q.test(n)?(t=n.replace(q,()=>o.trimEnd()),a=t===n?"unchanged":"updated"):n.includes(ie)?(a="migrated",t=o):(a="appended",t=n.replace(/\s*$/,`
104
-
105
- `)+o),!s&&a!=="unchanged"&&(a==="migrated"&&l.writeFileSync(e+".ozmoz-legacy.bak",n,"utf8"),l.mkdirSync(c.dirname(e),{recursive:!0}),l.writeFileSync(e,t,"utf8")),a}function ae(){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=>l.existsSync(o))||c.resolve(__dirname,"ozmoz-mcp.js")}function R(e,o){let s={command:process.execPath,args:[__filename,"mcp","--run"]},n={};if(l.existsSync(e))try{let t=JSON.parse(l.readFileSync(e,"utf8"));if(!t||typeof t!="object"||Array.isArray(t))return"invalid";n=t}catch{return"invalid"}let a=n.mcpServers&&n.mcpServers[k];return a&&JSON.stringify(a)===JSON.stringify(s)?"unchanged":(n.mcpServers=n.mcpServers||{},n.mcpServers[k]=s,o||(l.mkdirSync(c.dirname(e),{recursive:!0}),l.writeFileSync(e,JSON.stringify(n,null,2)+`
106
- `,"utf8")),a?"updated":"created")}function ke(e){if(!l.existsSync(e))return"absent";let o;try{o=JSON.parse(l.readFileSync(e,"utf8"))}catch{return"invalid"}return!o||typeof o!="object"||!o.mcpServers||!o.mcpServers[k]?"absent":(delete o.mcpServers[k],l.writeFileSync(e,JSON.stringify(o,null,2)+`
107
- `,"utf8"),"removed")}function L(e){let o=process.platform==="win32"?"where":"which";return I(o,[e],{stdio:"ignore"}).status===0}function Y(e,o,s){let n=I(e,o,{encoding:"utf8",timeout:s||3e4,shell:process.platform==="win32"});return{ok:n.status===0,out:(n.stdout||"")+(n.stderr||"")}}function je(e,o,s){let n=e==="claude"?["--scope",s||"user"]:[],a=ae(),t=["mcp","add"].concat(n,[k,"--",process.execPath,a]),r=["mcp","remove",k].concat(n),i=e+" "+t.join(" ");if(!L(e))return{status:"manual",detail:i};if(o)return{status:"planned",detail:i};let d=Y(e,["mcp","list"],6e4),u=d.ok?d.out.split(`
108
- `):[],p=u.find(T=>/^[\s|│┃]*ozmoz(?![\w@-])/.test(T)),f=u.some(T=>/^\s*(?:fleetbo|fleetbo-svro):\s/.test(T));if(p&&p.includes("ozmoz@latest"))return{status:"unchanged",legacy:f};if(p&&!Y(e,r).ok)return{status:"manual",detail:e+" "+r.join(" ")+" && "+i,legacy:f};let v=Y(e,t);return v.ok?{status:p?"updated":"created",legacy:f}:{status:"failed",detail:i,message:v.out.trim().split(`
109
- `).slice(-2).join(" "),legacy:f}}function _e(e){let o={user:!1,local:!1,others:[]};try{let s=JSON.parse(l.readFileSync(c.join(A.homedir(),".claude.json"),"utf8")),n=i=>!!i&&typeof i=="object"&&/fleetbo-svro|ozmoz/.test(String(i.command||"")+" "+JSON.stringify(i.args||[])),a=(i,d)=>{!i||typeof i!="object"||Object.keys(i).forEach(u=>{u===k?o[d]=!0:n(i[u])&&o.others.push({name:u,where:d})})};a(s.mcpServers,"user");let t=e;try{t=l.realpathSync(e)}catch{}let r=s.projects||{};Array.from(new Set([e,t])).forEach(i=>a((r[i]||{}).mcpServers,"local"))}catch{}return o}function Ie(e){let o=_e(e);o.user&&m(" \u26A0\uFE0F A global (user-scope) '"+k+"' entry from a previous version also exists: the tools appear in every project. To keep them in ozmoZ projects only: claude mcp remove "+k+" --scope user"),o.local&&m(" \u26A0\uFE0F A local-scope '"+k+"' entry exists for this folder and takes precedence over .mcp.json. Remove it: claude mcp remove "+k+" --scope local"),o.others.forEach(s=>{m(" \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 Ce(e){let o=A.homedir(),s=n=>l.existsSync(n);return{claude:L("claude")||s(c.join(o,".claude")),cursor:s(c.join(e,".cursor"))||s(c.join(o,".cursor"))||L("cursor"),windsurf:s(c.join(o,".codeium","windsurf"))||s(c.join(e,".windsurf")),devin:s(c.join(e,".devin")),codex:L("codex")||s(c.join(o,".codex")),gemini:L("gemini")||s(c.join(o,".gemini")),antigravity:L("agy")||s(c.join(o,".antigravity"))||s(c.join(e,".antigravity"))}}var Ne={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 Pe(e){return String(e||"").replace(/[^\p{L}\p{N} '.,:\-_]/gu," ").replace(/\s+/g," ").trim().slice(0,4e3)}function De(e,o,s){let n=Pe(o),a=n?"The project description is already given: "+n+". Ask me only the technology question, then build it: ask me another question only if essential information is missing.":"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=c.join(s,".env");if(l.existsSync(u)){let p=l.readFileSync(u,"utf8").match(/^\s*OZ_DB_KEY\s*=\s*(.+?)\s*$/m);p&&(t=p[1].trim())}}catch{}let r=l.existsSync(c.join(s,"svro.schema.json")),i=l.existsSync(c.join(s,"index.html"))||l.existsSync(c.join(s,"package.json")),d=t||r?"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). Before doing anything else, state this in one plain sentence to the user (e.g. "Ce projet existe d\xE9j\xE0, je le reprends.") so they can correct you immediately if this is wrong \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 (index.html or package.json found) \u2014 do NOT run "npm create vite" or scaffold a new frontend, you would overwrite it. Do not spend a tool call checking which framework it uses. Skip the technology question (detect it from the existing files if needed) and ask me only for a one-sentence project description, then call oz_create_project directly on this existing project.':"This folder does NOT contain an ozmoZ project yet (no .env, no svro.schema.json) \u2014 do not spend a tool call checking, proceed directly to the starter questions below. "+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). "+d}function Re(){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=I("ps",["-A","-o","pid=,ppid=,args="],{encoding:"utf8"});if(o.status!==0)return!1;let s=new Map;o.stdout.split(`
110
- `).forEach(a=>{let t=a.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);t&&s.set(Number(t[1]),{ppid:Number(t[2]),args:t[3]})});let n=process.ppid;for(let a=0;n>1&&a<20&&s.has(n);a++){let{ppid:t,args:r}=s.get(n);if(r.split(/\s+/).slice(0,2).some(d=>/(^|\/)(gemini|claude|codex|antigravity|agy)$/.test(d))||/@google\/gemini-cli|@anthropic-ai\/claude-code|@openai\/codex/.test(r))return!0;n=t}}catch{}return!1}function Le(e){let o=process.platform==="win32"?"where":"which";return I(o,[e],{stdio:"ignore"}).status===0}function Fe(e,o){let s=o.slice(1).filter(p=>!p.startsWith("--")),n=(s[0]||"").toLowerCase(),a=s.slice(1).join(" "),t=Ne[n];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 r=!1;try{r=!!JSON.parse(l.readFileSync(c.join(A.homedir(),".fleetbo","credentials.json"),"utf8")).devToken}catch{}r||(m("[ozmoZ] First use on this machine: sign in (your browser opens, approve once)."),I(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 '+n+'" again.'),process.exit(1))),I(process.execPath,[__filename,"mcp","--agent="+n],{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='+n+'" to see why.'),process.exit(1)),Re()&&(m(`
111
- [ozmoZ] ozmoZ is set up in this folder (instruction file + MCP server).`),m("[ozmoZ] You are already inside an AI agent's shell, so no second agent is launched."),m('[ozmoZ] NEXT: tell the user, in plain words, to quit this agent and start it again in this folder (or to run "npx -y ozmoz@latest start '+n+`" in a normal terminal), then to paste the message again. Do not run any other command.
112
- `),process.exit(0)),Le(t.bin)||(z('"'+t.bin+'" is not installed or not in your PATH. Install it, then run: npx ozmoz start '+n),process.exit(1));let d=De(t.rules,a,e);m(`
113
- [ozmoZ] Launching `+t.bin+` in this folder...
114
- `);let u=I(t.bin,t.launch(process.platform==="win32"?'"'+d+'"':d),{stdio:"inherit",cwd:e,shell:process.platform==="win32"});process.exit(u.status===null?1:u.status)}async function ce(e,o){let s=o.includes("--dry-run"),n=o.find(y=>y.startsWith("--agent=")),a=n&&n.slice(8).trim()?n.slice(8).split(",").map(y=>y.trim().toLowerCase()).filter(Boolean):null,t=null;if(a){t=a.includes("all")?Object.keys($):a;let y=t.filter(S=>!$[S]);y.length&&(z("Unknown agent(s): "+y.join(", ")+". Valid values: "+Object.keys($).join(", ")+", all."),process.exit(1))}let r=o.find(y=>y.startsWith("--scope=")),i=r?r.slice(8).trim().toLowerCase():"project";["project","user","local"].includes(i)||(z("Unknown scope: "+i+". Valid values for Claude Code: project (default), user, local."),process.exit(1));let d=Ce(e),u=t||Object.keys($).filter(y=>d[y]),p=be();m(`
115
- [ozmoZ] Configuring your AI agents`+(s?" (dry run: nothing is written)":"")+"...");let f=K(p,xe()),v=[["AGENTS.md",f],["GEMINI.md",f],["CLAUDE.md",K(p,`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
116
- @AGENTS.md`)]],T=c.join(e,".cursorrules");if(l.existsSync(T)){let y=l.readFileSync(T,"utf8");(q.test(y)||y.includes(ie))&&v.push([".cursorrules",f])}for(let y of v)m("\u2192 "+y[0]+": "+P[Ae(c.join(e,y[0]),y[1],s)]);for(let y of u){let S=$[y];if(y==="cursor")m("\u2192 "+S+" MCP (.cursor/mcp.json): "+P[R(c.join(e,".cursor","mcp.json"),s)]);else if(y==="windsurf")m("\u2192 "+S+" MCP (~/.codeium/windsurf/mcp_config.json): "+P[R(c.join(A.homedir(),".codeium","windsurf","mcp_config.json"),s)]);else if(y==="antigravity"){if(m("\u2192 "+S+" MCP (.agents/mcp_config.json): "+P[R(c.join(e,".agents","mcp_config.json"),s)]),R(c.join(e,".mcp.json"),s),!s){let O=[];u.includes("gemini")||(O.push(c.join(e,".gemini","settings.json")),O.push(c.join(A.homedir(),".gemini","settings.json"))),O.push(c.join(e,".antigravity","settings.json")),O.push(c.join(A.homedir(),".antigravity","settings.json")),O.push(c.join(e,".antigravity","mcp.json")),O.forEach(b=>{try{ke(b)==="removed"&&m("\u2192 Removed stale ozmoz entry: "+(c.relative(e,b)||b))}catch{}})}}else if(y==="gemini"){let O=[c.join(A.homedir(),".gemini","settings.json"),c.join(e,".gemini","settings.json"),c.join(e,".mcp.json")],b="unchanged";O.forEach(x=>{let E=R(x,s);(E==="created"||E==="updated")&&(b=E)}),m("\u2192 "+S+" MCP (settings.json & .mcp.json): "+P[b])}else if(y==="claude"&&i==="project"){let O=R(c.join(e,".mcp.json"),s);m("\u2192 "+S+" MCP (.mcp.json, project scope): "+P[O]),(O==="created"||O==="updated")&&m(" 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)."),Ie(e)}else if(y==="claude"||y==="codex"){let O=je(y,s,i);O.status==="manual"?m("\u2192 "+S+": '"+y+"' not found or not scriptable. Run manually: "+O.detail):O.status==="planned"?m("\u2192 "+S+" MCP: would run: "+O.detail):O.status==="failed"?z("\u2192 "+S+" MCP: registration failed ("+O.message+"). Run manually: "+O.detail):m("\u2192 "+S+" MCP"+(y==="claude"?" ("+i+" scope)":" (~/.codex/config.toml, global)")+": "+P[O.status]),O.legacy&&m(" \u26A0\uFE0F An old MCP entry named 'fleetbo' exists. Remove it: "+y+" mcp remove fleetbo")}else y==="devin"&&m("\u2192 "+S+": reads AGENTS.md. Devin runs in its own environment: add the Fleetbo MCP server from Devin's settings (not automated).")}!t&&u.length===0&&m("\u2192 No agent detected: instruction files were written; re-run with --agent=<name> to register the MCP server.");let g=!!(V(e).FLEETBO_DEV_TOKEN||process.env.FLEETBO_DEV_TOKEN),w=c.join(A.homedir(),".fleetbo","credentials.json");if(l.existsSync(w))try{g=g||!!JSON.parse(l.readFileSync(w,"utf8")).devToken}catch{}g||z('\u26A0\uFE0F No developer token found. Run "npx ozmoz login" once.'),process.env.FLEETBO_START||m(`
23
+ `+(h.protocol||""),v=J(p,O),E=[["AGENTS.md",v],["GEMINI.md",v],["CLAUDE.md",J(p,`# OZMOZ DATA OS \u2014 DIRECTIVES AGENT
24
+ @AGENTS.md`)]],y=a.join(e,".cursorrules");if(i.existsSync(y)){let g=i.readFileSync(y,"utf8");(V.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=R[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(C=>{try{ge(C)==="removed"&&d("\u2192 Removed stale ozmoz entry: "+(a.relative(e,C)||C))}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")],C="unchanged";S.forEach(L=>{let k=I(L,s);(k==="created"||k==="updated")&&(C=k)}),d("\u2192 "+T+" MCP (settings.json & .mcp.json): "+N[C])}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(`
117
25
  [ozmoZ] Done. Restart your agent so it reloads the tools and instruction files.
118
- `)}function Ze(e){let o=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";me(`${o} "${e}"`)}function Ue(e){return new Promise((o,s)=>{let n=pe.createServer((a,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"),a.method==="OPTIONS"){t.writeHead(204),t.end();return}let r=new URL(a.url,"http://127.0.0.1");if(r.pathname==="/callback"){let i=r.searchParams.get("token"),d=r.searchParams.get("refresh");if(!i){t.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),t.end("<h3>Error: Missing token.</h3>");return}let u=c.join(A.homedir(),".fleetbo");l.existsSync(u)||l.mkdirSync(u,{recursive:!0}),l.writeFileSync(c.join(u,"credentials.json"),JSON.stringify({devToken:i,refreshToken:d||null,updatedAt:new Date().toISOString()},null,2));let p=c.join(e,".env");if(l.existsSync(p)){let f=l.readFileSync(p,"utf8");f.includes("FLEETBO_DEV_TOKEN=")?f=f.replace(/FLEETBO_DEV_TOKEN=.*/g,`FLEETBO_DEV_TOKEN=${i}`):f+=`
119
- FLEETBO_DEV_TOKEN=${i}
120
- `,l.writeFileSync(p,f,"utf8")}t.writeHead(200,{"Content-Type":"text/html; charset=utf-8",Connection:"close"}),t.end(`
26
+ `)}function je(e){let n=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";oe(`${n} "${e}"`)}function Ce(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+=`
27
+ FLEETBO_DEV_TOKEN=${c}
28
+ `,i.writeFileSync(f,h,"utf8")}t.writeHead(200,{"Content-Type":"text/html; charset=utf-8",Connection:"close"}),t.end(`
121
29
  <!DOCTYPE html>
122
30
  <html>
123
31
  <head>
@@ -135,34 +43,28 @@ FLEETBO_DEV_TOKEN=${i}
135
43
  </div>
136
44
  </body>
137
45
  </html>
138
- `),m(`
139
- [ozmoZ] Developer token received and stored successfully!`),!process.env.FLEETBO_START&&!["AGENTS.md","CLAUDE.md","GEMINI.md"].some(f=>l.existsSync(c.join(e,f)))&&(m(`
140
- Next step to connect your AI agents:`),m(` npx ozmoz mcp (Configure Claude Code, Cursor, Windsurf, Devin, Codex CLI, Gemini CLI)
141
- `)),typeof n.closeAllConnections=="function"&&n.closeAllConnections(),n.close(()=>o()),setTimeout(()=>o(),300)}});n.listen(0,"127.0.0.1",()=>{let t=`https://ozmoz.io/cli-auth?port=${n.address().port}`;m(`
142
- [ozmoZ] Waiting for authentication...`),m(`If your browser does not open automatically, visit: ${t}`),Ze(t);let r=Number(process.env.FLEETBO_LOGIN_TIMEOUT_MS)||12e4;setTimeout(()=>{try{typeof n.closeAllConnections=="function"&&n.closeAllConnections()}catch{}n.close(),s(new Error(`Login timed out after ${Math.round(r/1e3)}s: browser approval not received. Run "npx ozmoz login" once more and approve in the browser.`))},r).unref()}),n.on("error",a=>s(a))})}function Me(e,o){return new Promise((s,n)=>{let a=JSON.stringify({enterpriseID:e,schema:o}),t={hostname:"fleetbo-gatekeeper.fleetbo.workers.dev",path:"/sync-schema",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(a)}},r=te.request(t,i=>{let d="";i.on("data",u=>{d+=u}),i.on("end",()=>{i.statusCode>=200&&i.statusCode<300?s(JSON.parse(d)):n(new Error(`Edge sync failed with HTTP ${i.statusCode}`))})});r.on("error",i=>n(i)),r.write(a),r.end()})}function V(e){let o=c.join(e,".env");if(!l.existsSync(o))return{};let s=l.readFileSync(o,"utf8"),n={};return s.split(`
143
- `).forEach(a=>{let[t,...r]=a.split("=");t&&r.length>0&&(n[t.trim()]=r.join("=").trim())}),n}function X(e,o){return new Promise((s,n)=>{let a=JSON.stringify({projectId:e,moduleName:o}),t={hostname:"getmodulecache-jqycakhlxa-uc.a.run.app",path:"/",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(a)}},r=te.request(t,i=>{let d="";i.on("data",u=>{d+=u}),i.on("end",()=>{if(i.statusCode>=200&&i.statusCode<300)try{let u=JSON.parse(d);if(u.success&&u.found&&u.module){let p=u.module.code||u.module.mockCode;s(typeof p=="string"?JSON.parse(p):p)}else s(null)}catch{n(new Error(`Invalid JSON response for ${o}.`))}else n(new Error(`Server error ${i.statusCode} while fetching ${o}`))})});r.on("error",i=>n(i)),r.write(a),r.end()})}var _=process.argv.slice(2),j=_[0],$e=["id","_id","userId","author","dateCreated","createdAt","_schema_version"],le=e=>$e.includes(e)||/^_/.test(e)||/^(created|updated|modified|deleted)(At|By)$/i.test(e);function W(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 We(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(([n,a])=>{let t=W(a);t&&Object.keys(t).forEach(r=>{le(r)&&t[r]&&typeof t[r]=="object"&&t[r].required===!0&&(t[r].required=!1,o.push(n+"."+r))})}),{schema:s,changed:o.length>0,notes:o}}function Be(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 Ge(e){let s=Object.entries(e&&e.collections||{}),n=`## \u{1F4E5} CE QUE LE CODE DOIT ENVOYER (MOD\xC8LES D'\xC9CRITURE)
46
+ `),d(`
47
+ [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(`
48
+ Next step to connect your AI agents:`),d(` npx ozmoz mcp (Configure Claude Code, Cursor, Windsurf, Devin, Codex CLI, Gemini CLI)
49
+ `)),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(`
50
+ [ozmoZ] Waiting for authentication...`),d(`If your browser does not open automatically, visit: ${t}`),je(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 Ae(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(`
51
+ `).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 j=process.argv.slice(2),x=j[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)
144
52
 
145
- `;n+=`### \u{1F194} Identifiants
146
- `,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 a=s.filter(([,t])=>W(t)&&Object.keys(W(t)).length>0);return a.length===0?n+`_Aucune collection scell\xE9e pour l'instant : les mod\xE8les appara\xEEtront apr\xE8s la mod\xE9lisation d'Alex._
147
- `:(a.forEach(([t,r])=>{let i=W(r),d=Object.entries(i).filter(([f])=>!le(f));n+="### `"+t+`\`
53
+ `;o+=`### \u{1F194} Identifiants
54
+ `,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._
55
+ `:(r.forEach(([t,l])=>{let c=U(l),m=Object.entries(c).filter(([h])=>!te(h));o+="### `"+t+`\`
148
56
 
149
57
  | Champ | Type | Obligatoire | Valeurs / remarques |
150
58
  |---|---|---|---|
151
- `,d.forEach(([f,v])=>{let T=typeof v=="string"?v:v&&v.type||"any",h=v&&(v.enum||v.values||v.options),g=Array.isArray(h)&&h.length?"parmi : "+h.map(w=>"`"+w+"`").join(", "):"";n+="| `"+f+"` | "+T+" | "+(v&&v.required===!0?"\u2705 oui":"non")+" | "+g+` |
152
- `});let u=d.filter(([,f])=>f&&f.required===!0),p=d.filter(([,f])=>!(f&&f.required===!0));n+="\nInsertion valide :\n```js\nawait oz.add('"+t+`', {
153
- `,u.forEach(([f,v])=>{n+=" "+f+": "+Be(v)+`,
154
- `}),p.length&&(n+=" // optionnels : "+p.map(([f])=>f).join(", ")+`
155
- `),n+=`}, {
156
- `,n+=" desc: 'Cr\xE9ation d\\'un \xE9l\xE9ment dans "+t+`',
157
- `,n+=` role: 'AUTHENTICATED' // ou 'ANONYMOUS', 'ADMIN'
158
- `,n+=` // guard: 'condition sur les donn\xE9es' (optionnel)
159
- `,n+="});\n```\n\n"}),n)}function H(e){return e.replace(/("(\\.|[^"\\\r\n])*"|'(\\.|[^'\\\r\n])*'|`(\\.|[^`\\])*`)|(\/\*[\s\S]*?\*\/|\/\/[^\r\n]*)/g,(o,s)=>s||"")}function de(e,o){let s=e[o];for(let n=o+1;n<e.length;n++){if(e[n]==="\\"){n++;continue}if(s!=="`"&&(e[n]===`
160
- `||e[n]==="\r"))return n;if(s==="`"&&e[n]==="$"&&e[n+1]==="{"){n=F(e,n+1)-1;continue}if(e[n]===s)return n+1}return e.length}function F(e,o){let s=e[o],n=s==="("?")":s==="["?"]":"}",a=0;for(let t=o;t<e.length;t++){let r=e[t];if(r==='"'||r==="'"||r==="`"){t=de(e,t)-1;continue}if(r==="/"&&e[t+1]==="/"){let i=e.indexOf(`
161
- `,t);if(i<0)return e.length;t=i;continue}if(r==="/"&&e[t+1]==="*"){let i=e.indexOf("*/",t+2);if(i<0)return e.length;t=i+1;continue}if(r==="("||r==="["||r==="{")a++;else if((r===")"||r==="]"||r==="}")&&(a--,a===0&&r===n||a<0))return t+1}return e.length}function ue(e,o,s){let n=[],a=o,t=o;for(;t<s;){let r=e[t];if(r==='"'||r==="'"||r==="`"){t=de(e,t);continue}if(r==="/"&&e[t+1]==="/"){let i=e.indexOf(`
162
- `,t);t=i<0?s:i;continue}if(r==="/"&&e[t+1]==="*"){let i=e.indexOf("*/",t+2);t=i<0?s:i+2;continue}if(r==="("||r==="["||r==="{"){t=F(e,t);continue}r===","&&(n.push(e.slice(a,t)),a=t+1),t++}return e.slice(a,s).trim()!==""&&n.push(e.slice(a,s)),n}function Ve(e){let o=e.trim(),s=new Set,n=!1,a=!1;return ue(o,1,o.length-1).forEach(t=>{let r=t.replace(/^(?:\s|\/\/[^\n]*\n|\/\*[\s\S]*?\*\/)+/,"").trim();if(!r)return;if(r.startsWith("...")){n=!0;return}if(r.startsWith("[")){a=!0;return}let i=r.match(/^(['"])(.*?)\1\s*:/);if(i){s.add(i[2]);return}i=r.match(/^([A-Za-z_$][\w$]*)\s*(:|\(|$)/),i&&s.add(i[1])}),{keys:s,hasSpread:n,hasComputed:a}}function Ye(e,o,s){let n=o.trim();if(n.startsWith("{"))return n;if(!/^[A-Za-z_$][\w$]*$/.test(n))return null;let a=new RegExp("(?:const|let|var)\\s+"+n.replace(/\$/g,"\\$")+"\\s*=\\s*\\{","g"),t=-1,r;for(;(r=a.exec(e))&&r.index<s;)t=r.index+r[0].length-1;return t<0?null:e.slice(t,F(e,t))}function B(e,o){return e.slice(0,o).split(`
163
- `).length}function J(e){let o=[],s=new Set(["node_modules","dist","build",".next",".git",".svelte-kit",".nuxt","coverage"]),n=(a,t)=>{if(t>6||o.length>400)return;let r=[];try{r=l.readdirSync(a,{withFileTypes:!0})}catch{return}r.forEach(i=>{if(s.has(i.name))return;let d=c.join(a,i.name);if(i.isDirectory())n(d,t+1);else if(/\.(jsx?|tsx?|mjs|vue|svelte)$/.test(i.name)&&!/\.d\.ts$/.test(i.name))try{l.statSync(d).size<5e5&&o.push(d)}catch{}})};return["src","app","pages","components"].forEach(a=>n(c.join(e,a),0)),o}function qe(e,o){let s=[],n=0,a=o&&o.collections||{};if(Object.keys(a).length===0)return{issues:s,checked:n,skipped:!0};let t=/\boz\s*\.\s*(add|addWithId|addWithUserId|addWithMedia|update)\s*\(/g,r=/\boz\s*\.\s*(add|addWithId|addWithUserId|addWithMedia|update|delete|getDocsG|getDocsU|getDoc|join)\s*\(\s*(['"`])([^'"`$\\]+)\2/g;return J(e).forEach(i=>{let d="";try{d=l.readFileSync(i,"utf8")}catch{return}if(!/oz\./.test(d)&&!/<oz-/i.test(d))return;d=H(d);let u=c.relative(e,i).split(c.sep).join("/"),p;for(r.lastIndex=0;p=r.exec(d);)Object.prototype.hasOwnProperty.call(a,p[3])||s.push({where:u+":"+B(d,p.index),msg:"oz."+p[1]+"('"+p[3]+"') : the collection '"+p[3]+"' is not in the contract"});for(t.lastIndex=0;p=t.exec(d);){let f=p.index+p[0].length-1,v=F(d,f)-1,T=ue(d,f+1,v),h=p[1],w=(T[0]||"").trim().match(/^(['"`])([^'"`$\\]+)\1$/),y=h==="update"?T[2]:T[1];if(!w||!y)continue;let S=W(a[w[2]]);if(!S)continue;let O=Ye(d,y,p.index);if(!O)continue;let{keys:b,hasSpread:x,hasComputed:E}=Ve(O);n++;let Z=u+":"+B(d,p.index),G=[...b].filter(D=>!Object.prototype.hasOwnProperty.call(S,D));if(G.length&&s.push({where:Z,msg:"oz."+h+"('"+w[2]+"') sends field(s) not in the contract: "+G.join(", ")}),h!=="update"&&!x&&!E){let D=Object.entries(S).filter(([U,C])=>C&&typeof C=="object"&&C.required===!0&&!b.has(U)).map(([U])=>U);D.length&&s.push({where:Z,msg:"oz."+h+"('"+w[2]+"') is missing required field(s): "+D.join(", ")})}}}),{issues:s,checked:n,skipped:!1}}function He(e,o){let s=qe(e,o);if(!s.skipped){if(s.issues.length===0){s.checked>0&&m("\u2192 Contract check: "+s.checked+" write call(s) match the contract.");return}m(`
164
- \u26A0\uFE0F Contract check: `+s.issues.length+" problem(s) that production (OZ_PROTOTYPE=false) would reject with HTTP 422:"),s.issues.slice(0,20).forEach(n=>m(" "+n.where+" "+n.msg)),m(` \u2192 Fix each one in your code now, or evolve the contract with oz_update_project, BEFORE switching to live mode. Details: ozmoz_contract.md, section "CE QUE LE CODE DOIT ENVOYER".
165
- `)}}var Q=/(?:const|let|var)\s+(\w+)\s*=\s*await\s+oz\s*\.\s*(add|addWithId|addWithUserId|addWithMedia|update|delete|sendotpsvro|verifyotpsvro)\s*\(/g,ee=/(?<!=\s*)\bawait\s+oz\s*\.\s*(add|addWithId|addWithUserId|addWithMedia|update|delete|sendotpsvro|verifyotpsvro)\s*\(/g;function Je(e){let o=[];return J(e).forEach(s=>{let n="";try{n=l.readFileSync(s,"utf8")}catch{return}if(!/oz\./.test(n))return;let a=H(n),t=c.relative(e,s).split(c.sep).join("/");Q.lastIndex=0;let r;for(;r=Q.exec(a);){let i=r[1],d=a.slice(r.index);new RegExp("\\b"+i+"\\s*(?:\\?\\.|\\.)\\s*(success|error)\\b").test(d)||o.push({where:t+":"+B(a,r.index),msg:`oz.${r[2]}(): return value ('${i}') never checked with .success/.error (rule 4).`})}for(ee.lastIndex=0;r=ee.exec(a);)o.push({where:t+":"+B(a,r.index),msg:`oz.${r[1]}(): called without assigning return value to check .success/.error (rule 4).`})}),o}function Ke(e){let o=[],s=/\bresource\.([a-zA-Z_][a-zA-Z0-9_]*)\b/g,n;for(;n=s.exec(String(e));)o.push(n[1]);return Array.from(new Set(o))}function Xe(e){let o=[],s=c.join(e,"svro.schema.json"),n=c.join(e,"svro.workflow.json");if(!l.existsSync(s)||!l.existsSync(n))return o;let a,t;try{a=JSON.parse(l.readFileSync(s,"utf8")),t=JSON.parse(l.readFileSync(n,"utf8"))}catch{return o}return Array.isArray(t.sequences)&&t.sequences.forEach(r=>{let i=a.collections?.[r.collection]?.fields||null;if(!i){o.push({where:r.id||"?",msg:`S\xE9quence sur la collection '${r.collection}', absente de svro.schema.json.`});return}(r.guards||[]).forEach(d=>{Ke(d).forEach(u=>{u in i||o.push({where:r.id||r.collection,msg:`Guard "${d}" r\xE9f\xE9rence '${u}', absent des champs d\xE9clar\xE9s de '${r.collection}' \u2014 l'Edge rejettera toute \xE9criture contenant ce champ (HTTP 422).`})})})}),o}var Qe=["add","addWithId","addWithUserId","addWithMedia","update","delete"];function et(e){let o=[],s=new RegExp("oz\\.("+Qe.join("|")+`)\\s*\\(\\s*['"][A-Za-z0-9_]+['"]`,"g");return J(e).forEach(n=>{let a="";try{a=l.readFileSync(n,"utf8")}catch{return}if(!/oz\./.test(a))return;let t=H(a),r=c.relative(e,n).split(c.sep).join("/");s.lastIndex=0;let i;for(;i=s.exec(t);){let d=i[1],u=t.indexOf("(",i.index);if(u===-1)continue;let p=F(t,u)-1;if(p<=u)continue;let f=t.slice(u+1,p),v=/\bdesc\s*:/.test(f),T=/\brole\s*:/.test(f);if(!v||!T){let h=[];v||h.push("desc"),T||h.push("role"),o.push({where:r+":"+B(t,i.index),msg:`oz.${d}() missing mandatory governance metadata: ${h.join(", ")} (desc and role are required, guard is optional).`})}}}),o}function tt(e,o){let s=e?.context||o?.context||"No written specifications provided.";return`# THE OZMOZ DATA CONTRACT (SVRO DATA CONTRACT)
59
+ `,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+` |
60
+ `});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+`', {
61
+ `,u.forEach(([h,p])=>{o+=" "+h+": "+Ne(p)+`,
62
+ `}),f.length&&(o+=" // optionnels : "+f.map(([h])=>h).join(", ")+`
63
+ `),o+=`}, {
64
+ `,o+=" desc: 'Cr\xE9ation d\\'un \xE9l\xE9ment dans "+t+`',
65
+ `,o+=` role: 'AUTHENTICATED' // ou 'ANONYMOUS', 'ADMIN'
66
+ `,o+=` // guard: 'condition sur les donn\xE9es' (optionnel)
67
+ `,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)
166
68
 
167
69
  ### \u{1F6A8} MANDATORY CODE RULES (READ BEFORE WRITING ANY VIEW)
168
70
  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\`.
@@ -201,7 +103,7 @@ This document constitutes the **Official Specifications and Bilateral Integrity
201
103
  ---
202
104
 
203
105
  ### \u{1F9ED} DATA PROTOCOL: WHO DOES WHAT (FRONTEND AGENT \u2194 ALEX AI)
204
- ${re}
106
+ ${s}
205
107
 
206
108
  ---
207
109
 
@@ -283,11 +185,11 @@ const updateStatus = async (orderId, newStatus) => {
283
185
  ---
284
186
 
285
187
  ## \u{1F4CB} BUSINESS SPECIFICATIONS (PROJECT CONTEXT)
286
- ${s}
188
+ ${o}
287
189
 
288
190
  ---
289
191
 
290
- ${Ge(e)}
192
+ ${Ie(e)}
291
193
 
292
194
  ---
293
195
 
@@ -300,29 +202,29 @@ ${JSON.stringify(e||{},null,2)}
300
202
 
301
203
  ## \u2699\uFE0F GOVERNANCE AND WORKFLOW CONTRACT (svro.workflow.json)
302
204
  \`\`\`json
303
- ${JSON.stringify(o||{},null,2)}
205
+ ${JSON.stringify(n||{},null,2)}
304
206
  \`\`\`
305
- `}function nt(e){return String(e).toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[^a-z0-9]/g,"_").replace(/^_+|_+$/g,"").slice(0,30)||"app"}async function ot(e,o){let s=V(e),n=l.existsSync(c.join(e,"svro.schema.json"));(s.OZ_DB_KEY||n)&&(z("Cannot create project: an ozmoZ project already exists in this folder."),m('\u2192 Use "npx ozmoz sync" or evolve the existing contract instead.'),process.exit(1));let a=(o||"").trim();a||(z('Project name is required. Usage: npx ozmoz create "<name>"'),process.exit(1));let t=c.join(e,".ozmoz.lock");if(l.existsSync(t)){let i=!1;try{let d=Number(l.readFileSync(t,"utf8"));Date.now()-d>6e4&&(i=!0)}catch{i=!0}i||(z("A project creation is already running in this folder."),process.exit(1)),l.unlinkSync(t)}l.writeFileSync(t,String(Date.now()));let r=()=>{if(l.existsSync(t))try{l.unlinkSync(t)}catch{}};try{let i=process.env.FLEETBO_DEV_TOKEN;if(!i){let h=c.join(A.homedir(),".fleetbo","credentials.json");if(l.existsSync(h))try{i=JSON.parse(l.readFileSync(h,"utf8")).devToken}catch{}}i||(r(),z('Missing developer token. Please run "npx ozmoz login" first.'),process.exit(1)),m(`[ozmoZ] Creating project "${a}" on Cloud...`);let d=nt(a),u=[d,`${d.slice(0,24)}_${Math.random().toString(36).slice(2,6)}`,`${d.slice(0,24)}_${Math.random().toString(36).slice(2,6)}`],p=null,f=null;for(let h of u)try{let g=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:h}})}),w=await g.json();if(g.ok&&!w.error){p={keyApp:h,data:w.result?.data||w.data||{}};break}else f=w.error?.message||`HTTP ${g.status}`}catch(g){f=g.message}p||(r(),z(`Failed to create project on Cloud: ${f||"Unknown error"}`),process.exit(1));let v=p.data.bootstrapToken;await oe(e,[`--keyApp=${p.keyApp}`,`--token=${v}`]);let T=c.join(e,"package.json");ne(e,T),await ce(e,[]),m(`
306
- [ozmoZ] Project "${a}" (${p.keyApp}) created and configured successfully.`),m(`Next step: scaffold the frontend if needed, then run "npx ozmoz sync".
307
- `)}finally{if(l.existsSync(t))try{l.unlinkSync(t)}catch{}}}function st(e){if(!e||typeof e!="string")return e;let o=new Set(["auth","resource","true","false","null","undefined","in","typeof","instanceof","new","return","Math","Number","String","Boolean","Date"]);return e.replace(/(?<![\w.$])([a-zA-Z_$][a-zA-Z0-9_$]*)\b(?!\s*\()/g,(s,n,a,t)=>a>0&&t[a-1]==="."||o.has(n)||!isNaN(n)?s:`resource.${n}`)}async function rt(e){let o=process.env.FLEETBO_DEV_TOKEN;if(!o){let h=c.join(A.homedir(),".fleetbo","credentials.json");if(l.existsSync(h))try{o=JSON.parse(l.readFileSync(h,"utf8")).devToken}catch{}}let n=V(e).OZ_KEY_APP;(!n||!o)&&(z("Cannot update: project not initialized or developer token missing."),process.exit(1));let a=l.existsSync(c.join(e,"src"))?c.join(e,"src"):e,t=[],r=new Set([".jsx",".tsx",".vue",".svelte",".js",".ts",".html"]);function i(h){let g=[];try{g=l.readdirSync(h,{withFileTypes:!0})}catch{return}for(let w of g){if(/^(node_modules|\.git|dist|build)$/.test(w.name))continue;let y=c.join(h,w.name);if(w.isDirectory())i(y);else if(r.has(c.extname(w.name))&&!w.name.endsWith(".d.ts")){let S=l.readFileSync(y,"utf8");/oz\.|<oz-/i.test(S)&&t.push({name:c.basename(y),content:S})}}}i(a),t.length===0&&(z("Cannot update: no files calling oz.* found."),process.exit(1));let d=[],u=/oz\.(add|addWithId|addWithUserId|addWithMedia|update|delete)\s*\(\s*['"]([A-Za-z0-9_]+)['"]/g;t.forEach(h=>{u.lastIndex=0;let g;for(;g=u.exec(h.content);){let w=h.content.indexOf("(",g.index);if(w===-1)continue;let y=F(h.content,w)-1;if(y<=w)continue;let S=h.content.slice(w+1,y),O=E=>(S.match(new RegExp(E+"\\s*:\\s*(['\"`])((?:(?!\\1)[\\s\\S])*?)\\1"))||[])[2]||null,b=S.matchAll(/([a-zA-Z0-9_]+)\s*:/g),x=0;for(let E of b)["desc","guard","role"].includes(E[1])||x++;d.push({operation:g[1],table:g[2],fieldCount:x,desc:O("desc"),guard:st(O("guard")),role:O("role"),source:h.name})}});let p=d.filter(h=>!h.desc||!h.role);p.length>0&&(z(`Governance check failed: missing mandatory metadata { desc, role } on ${p.length} write operation(s).`),p.forEach(h=>{let g=[];h.desc||g.push("desc"),h.role||g.push("role"),z(`\u2192 oz.${h.operation}('${h.table}') in ${h.source} [manquant : ${g.join(", ")}]`)}),process.exit(1));let f=new Map;d.forEach(h=>{let g=`${h.table}:${h.operation}`;(!f.has(g)||h.fieldCount>f.get(g).fieldCount)&&f.set(g,h)});let v=Array.from(f.values()).map(({fieldCount:h,...g})=>g);m(`[ozmoZ] Sending ${t.length} component(s) to Alex AI...`);try{let h=await fetch("https://updateprojectlight-jqycakhlxa-uc.a.run.app",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({data:{keyApp:n,name:n,newViewFiles:t,explicitGovernance:v}})}),g=await h.json();(!h.ok||g.error)&&(z(`Update failed: ${g.error?.message||"Unknown API error"}`),process.exit(1))}catch(h){z(`Network error contacting Cloud: ${h.message}`),process.exit(1)}m("\u2192 Structure modeled. Sealing contract on Edge..."),I(process.execPath,[__filename,"sync"],{stdio:"inherit",cwd:e}).status===0?m(`
308
- [ozmoZ] Contract successfully updated and sealed at Edge.
207
+ `}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(`
208
+ [ozmoZ] Project "${r}" (${f.keyApp}) created and configured successfully.`),d(`Next step: scaffold the frontend if needed, then run "npx ozmoz sync".
209
+ `)}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=j.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..."),A(process.execPath,[__filename,"sync"],{stdio:"inherit",cwd:e}).status===0?d(`
210
+ [ozmoZ] Contract successfully locked into SVRO Kernel.
309
211
  `):(z(`
310
- [ozmoZ] Edge sync failed. Run "npx ozmoz sync" manually.
311
- `),process.exit(1))}async function it(){let e=process.cwd(),o=c.join(e,"package.json");if(j==="init"||j==="doctor")m(`
312
- [ozmoZ] Initializing and configuring ozmoZ...`),await oe(e,_),ne(e,o),m(`
212
+ [ozmoZ] Kernel sync failed. Run "npx ozmoz sync" manually.
213
+ `),process.exit(1))}async function Me(){let e=process.cwd(),n=a.join(e,"package.json");if(x==="init"||x==="doctor")d(`
214
+ [ozmoZ] Initializing and configuring ozmoZ...`),await W(e,j),K(e,n),d(`
313
215
  [ozmoZ] Configuration completed successfully!
314
- `),m(`
315
- Next step:`),m(` npx ozmoz sync (Sync cloud schema & generate IDE types)
316
- `);else if(j==="sync"){let s=_.includes("--dry-run"),n=_.includes("--check-only");m(`[ozmoZ] Syncing schema...${s?" (dry-run)":""}${n?" (check-only, no network)":""}`),s||ze(e);let a=c.join(e,"svro.schema.json"),t=c.join(e,"svro.workflow.json"),r=c.join(e,"ozmoz_contract.md"),i=c.join(e,"src","ozmoz.d.ts"),u=V(e).OZ_ENTERPRISE_ID,p=null,f=null;if(n)m("\u2192 Mode check-only : Local contract used, no cloud fetch..");else if(u)try{m("\u2192 Fetching latest contracts from Cloud..."),p=await X(u,"svro.schema.json"),p&&(l.writeFileSync(a,JSON.stringify(p,null,2)+`
317
- `),m("\u2192 Local svro.schema.json updated.")),f=await X(u,"svro.workflow.json"),f&&(l.writeFileSync(t,JSON.stringify(f,null,2)+`
318
- `),m("\u2192 Local svro.workflow.json updated."))}catch(g){z(`\u26A0\uFE0F Cloud fetch bypassed: ${g.message}. Using local file fallback.`)}else z("\u26A0\uFE0F OZ_ENTERPRISE_ID missing in .env. Skipping cloud fetch.");let v=p;if(!v&&l.existsSync(a))try{v=JSON.parse(l.readFileSync(a,"utf8"))}catch{}v||(v={context:"Application en cours de mod\xE9lisation initiale.",collections:{}},l.writeFileSync(a,JSON.stringify(v,null,2)+`
319
- `,"utf8"),m("\u2192 Initial blank svro.schema.json created."));let T=f;if(!T&&l.existsSync(t))try{T=JSON.parse(l.readFileSync(t,"utf8"))}catch{}T||(T={actors:{},sequences:[]},l.writeFileSync(t,JSON.stringify(T,null,2)+`
320
- `,"utf8"),m("\u2192 Initial blank svro.workflow.json created."));{let g=We(v);g.changed&&(v=g.schema,l.writeFileSync(a,JSON.stringify(v,null,2)+`
321
- `,"utf8"),m("\u2192 Managed by system, no longer required from your code: "+g.notes.join(", ")+"."))}let h=tt(v,T);l.writeFileSync(r,h,"utf8"),m("\u2192 Contract markdown successfully generated at project root.");try{let g=Object.keys(v.collections||{});if(u&&!n)try{await Me(u,v),m("\u2192 Schema successfully sealed at Global Edge (O(1)).")}catch(E){z(`\u26A0\uFE0F Edge Shield sync warning: ${E.message}`)}let w=v.collections||{},y=Object.entries(w).map(([E,Z])=>{let G=Z.fields||Z.schema||{},D=Object.entries(G).map(([U,C])=>{let M="any",N=String(typeof C=="string"?C:C.type||"").toLowerCase();return N==="string"||N==="text"||N==="media"?M="string":N==="number"?M="number":N==="boolean"||N==="toggle"?M="boolean":N==="array"&&(M="any[]"),` ${U}?:${M};`}).join(`
322
- `);return` ${E}: {
323
- ${D}
216
+ `),d(`
217
+ Next step:`),d(` npx ozmoz sync (Sync cloud schema & generate IDE types)
218
+ `);else if(x==="sync"){let s=j.includes("--dry-run"),o=j.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)+`
219
+ `),d("\u2192 Local svro.schema.json updated.")),h=await G(u,"svro.workflow.json"),h&&(i.writeFileSync(t,JSON.stringify(h,null,2)+`
220
+ `),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)+`
221
+ `,"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)+`
222
+ `,"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)+`
223
+ `,"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 Ae(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||{},C=Object.entries(S).map(([L,k])=>{let M="any",_=String(typeof k=="string"?k:k.type||"").toLowerCase();return _==="string"||_==="text"||_==="media"?M="string":_==="number"?M="number":_==="boolean"||_==="toggle"?M="boolean":_==="array"&&(M="any[]"),` ${L}?:${M};`}).join(`
224
+ `);return` ${g}: {
225
+ ${C}
324
226
  };`}).join(`
325
- `),S=g.length>0?g.map(E=>`'${E}'`).join(" | "):"string";if(l.existsSync(c.dirname(i))){let E=`/* eslint-disable */
227
+ `),Z=y.length>0?y.map(g=>`'${g}'`).join(" | "):"string";if(i.existsSync(a.dirname(c))){let g=`/* eslint-disable */
326
228
  /* prettier-ignore */
327
229
  // @ts-nocheck
328
230
  // Generated by ozmoZ \u2014 Updated via sync
@@ -351,11 +253,11 @@ type OzProp = {
351
253
  };
352
254
 
353
255
  interface OzSchemaMap {
354
- ${y}
256
+ ${F}
355
257
  }
356
258
 
357
259
  declare global {
358
- type KnownOzTables = ${S};
260
+ type KnownOzTables = ${Z};
359
261
  type OzTables = KnownOzTables | (string & { _ozPending?: never });
360
262
  type OzData<T extends string> = T extends KnownOzTables
361
263
  ? Partial<OzSchemaMap[T]>
@@ -458,13 +360,7 @@ declare module 'svelte/elements' {
458
360
  'oz-reference': OzProp;
459
361
  }
460
362
  }
461
- `;l.writeFileSync(i,E)}ge(e),ye(e,o),ve(e),Oe(e),m(`[ozmoZ] Schema synced successfully (${g.length} collection(s)).`);try{He(e,v)}catch{}let O=Je(e);O.length>0&&(z(`
462
- \u{1F6AB} Sync blocked: ${O.length} write call(s) do not check results (rule 4):`),O.slice(0,20).forEach(E=>z(" "+E.where+" "+E.msg)),z(` \u2192 Inspect res.success and handle res.error on each call before syncing.
463
- `),process.exit(1));let b=Xe(e);b.length>0&&(z(`
464
- \u{1F6AB} Sync blocked: ${b.length} workflow guard(s) reference unsealed fields:`),b.slice(0,20).forEach(E=>z(" ["+E.where+"] "+E.msg)),z(` \u2192 Update svro.schema.json or adjust workflow guards before continuing.
465
- `),process.exit(1));let x=et(e);x.length>0&&(z(`
466
- \u{1F6AB} Sync blocked: ${x.length} write call(s) missing mandatory governance { desc, role }:`),x.slice(0,20).forEach(E=>z(" "+E.where+" "+E.msg)),z(` \u2192 Add literal { desc, role } to each write call before syncing (optional only on reads).
467
- `),process.exit(1)),s&&m("\u2192 [Dry-run] Schema is valid.")}catch(g){z(`Error during synchronization: ${g.message}`),process.exit(1)}}else if(j==="create"){let s=_.slice(1).filter(n=>!n.startsWith("--")).join(" ");await ot(e,s),process.exit(0)}else if(j==="update")await rt(e),process.exit(0);else if(j==="mcp"){let s=_.includes("--run"),n=!1;if(!s&&!process.stdin.isTTY&&(s=await new Promise(a=>{let t=process.stdin,r=null,i=p=>{clearTimeout(r),t.removeListener("data",d),t.removeListener("end",u),t.removeListener("error",u),a(p)},d=p=>{t.pause(),t.unshift(p),n=!0,i(!0)},u=()=>i(!1);r=setTimeout(()=>{t.pause(),i(!1)},1500),t.on("data",d),t.once("end",u),t.once("error",u)})),s){try{await import(`file://${ae()}`),n&&process.stdin.resume()}catch(a){z(`Failed to start MCP server: ${a.message}`),process.exit(1)}return}await ce(e,_),process.exit(0)}else j==="login"?(await Ue(e),process.exit(0)):j==="start"?Fe(e,_):["--help","-h","help"].includes(j)?(m(`ozmoZ CLI
363
+ `;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=j.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=j.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,j),process.exit(0)}else x==="login"?(await Ce(e),process.exit(0)):x==="start"?xe(e,j):["--help","-h","help"].includes(x)?(d(`ozmoZ CLI
468
364
 
469
365
  Commands:
470
366
  login Authenticate this machine (opens the browser: approve once, the command exits by itself)
@@ -475,9 +371,9 @@ Commands:
475
371
  start Zero-friction launch for terminal agents: sign in once, configure, then start ready to work.
476
372
  start <claude|gemini|codex|antigravity> ["your app idea"]
477
373
  init Initialize the project: init --keyApp=<KEY> --token=<TOKEN>
478
- sync Seal the schema/workflow on the Edge and generate ozmoz_contract.md + IDE types
374
+ sync Seal the schema/workflow into SVRO Kernel and generate ozmoz_contract.md + IDE types
479
375
  --check-only No network call (offline type & rule check)
480
376
 
481
377
  AI agents: to create a project, call the MCP tool "oz_create_project".
482
378
  To evolve schema/workflow from UI files, call the MCP tool "oz_update_project", then run "sync".
483
- `),process.exit(0)):(z('Unknown command. Run "npx ozmoz --help".'),process.exit(1))}it().catch(e=>{z(`ozmoZ CLI Error: ${e.message}`),process.exit(1)});
379
+ `),process.exit(0)):(z('Unknown command. Run "npx ozmoz --help".'),process.exit(1))}Me().catch(e=>{z(`ozmoZ CLI Error: ${e.message}`),process.exit(1)});