MatrixOS — Encrypted Personal Workspace
MATRIXOS
Initializing kernel...
`;
Bus.emit('browser.navigate_blocked',{url:u});
return;
}
try{frame.src=u;}catch{frame.srcdoc=`
Cannot load ${esc(u)}
Many sites block iframe embedding. Use ↗ to open in a real browser tab.
`;}
Bus.emit('browser.navigate',{url:u});
}
window.addEventListener('message',e=>{ if(e?.data?.type==='matrixos-open-external' && e.data.url) openExternal(e.data.url); });
w.body.querySelector(`#${w.id}-go`).onclick=()=>nav(urlBar.value);
w.body.querySelector(`#${w.id}-open`).onclick=()=>openExternal(urlBar.value||url);
urlBar.addEventListener('keydown',e=>{if(e.key==='Enter')nav(urlBar.value);});
w.body.querySelector(`#${w.id}-bk`).onclick=()=>{try{frame.contentWindow.history.back();}catch{}};
w.body.querySelector(`#${w.id}-fw`).onclick=()=>{try{frame.contentWindow.history.forward();}catch{}};
w.body.querySelector(`#${w.id}-read`).onclick=()=>{
readerMode=!readerMode;
if(readerMode){
frame.style.display='none';readerDiv.style.display='';
try{
const doc=frame.contentDocument||frame.contentWindow.document;
const body=doc.body?.innerText||'Cannot extract content from this page.';
const title=doc.title||url;
readerDiv.innerHTML=`
${esc(title)} ${esc(body).substring(0,10000).replace(/\n/g,' ')}
`;
}catch{readerDiv.innerHTML=`
Reader mode unavailable for cross-origin pages.
URL: ${esc(url)}
`;}
}else{frame.style.display='';readerDiv.style.display='none';}
};
w.body.querySelector(`#${w.id}-clip`).onclick=()=>{
let content='Clipped from: '+url+'\n\n';
try{content+=frame.contentDocument?.body?.innerText?.substring(0,500)||'';}catch{content+='[cross-origin — URL only]';}
const n=OB.put('note',{title:'Web clip: '+(url.split('/').slice(2,3)[0]||url).substring(0,40),body:content,_tags:['clip','web']});
OB.addAttachment(n.id,url,url);
ntf('Clipped','Saved to Notes with source link');
};
w.body.querySelector(`#${w.id}-bkm`).onclick=()=>{const title=prompt('Bookmark title:',url);if(title){OB.put('bookmark',{title,url,_tags:['web']});ntf('Bookmarked',title);}};
w.body.querySelector(`#${w.id}-dl`).onclick=()=>{
try{
const html=frame.contentDocument?.documentElement?.outerHTML;
if(html){const fname=(url.split('/').pop()||'page')+'.html';K.vfs.writeFile('/home/user/Downloads/'+fname,html);ntf('Saved',fname+' → Downloads');Bus.emit('browser.download',{filename:fname,url});}
}catch{ntf('Error','Cannot save cross-origin page');}
};
}});
const _Docs=()=>cwin({title:'Document Editor',icon:'📄',app:'docs',width:620,height:460,init:w=>{
let cur=null;
function renderList(){
const docs=OB.query('note',d=>d._tags?.includes('document'));
let list='';for(const d of docs)list+=`
${esc(d.title)} ${new Date(d.updated_at).toLocaleDateString()}
`;
w.body.innerHTML=`
📄 Documents + New Doc
${list||'
No documents. Click + New Doc.
'}
`;
w.body.querySelector(`#${w.id}-new`).onclick=()=>{const t=prompt('Document title:');if(t){const d=OB.put('note',{title:t,body:'',_tags:['document']});openDoc(d.id);}};
w.body.querySelectorAll('[data-id]').forEach(el=>el.onclick=()=>openDoc(el.dataset.id));
}
function openDoc(id){
cur=id;const d=OB.get(id);if(!d)return renderList();
w.body.innerHTML=`
← Docs Bold Italic H1 Save
${d.body||''}
`;
w.body.querySelector(`#${w.id}-bk`).onclick=()=>{saveDoc();renderList();};
w.body.querySelector(`#${w.id}-sv`).onclick=saveDoc;
w.body.querySelector(`#${w.id}-b`).onclick=()=>document.execCommand('bold');
w.body.querySelector(`#${w.id}-i`).onclick=()=>document.execCommand('italic');
w.body.querySelector(`#${w.id}-h`).onclick=()=>document.execCommand('formatBlock',false,'h1');
}
function saveDoc(){if(!cur)return;const el=w.body.querySelector(`#${w.id}-ed`);const tEl=w.body.querySelector(`#${w.id}-t`);OB.update(cur,{title:tEl?.value,body:el?.innerHTML});ntf('Saved','Document saved');}
renderList();
}});
const _Spreadsheet=()=>cwin({title:'Spreadsheet',icon:'▦',app:'sheet',width:640,height:440,init:w=>{
const ROWS=20,COLS=8;const cells=Array.from({length:ROWS},()=>Array(COLS).fill(''));
function colName(c){return String.fromCharCode(65+c);}
function render(){
let hdr='
';
for(let c=0;c${colName(c)}`;
hdr+=' ';
let rows='';for(let r=0;r';
rows+=`${r+1} `;
for(let c=0;c `;
}
rows+='';
}
w.body.innerHTML=`▦ Spreadsheet →Dataset Export CSV
`;
w.body.querySelectorAll('input[data-r]').forEach(inp=>{
inp.onfocus=()=>{inp.value=inp.dataset.raw;};
inp.onblur=()=>{cells[+inp.dataset.r][+inp.dataset.c]=inp.value;render();};
inp.onkeydown=e=>{if(e.key==='Enter'){inp.blur();e.preventDefault();}if(e.key==='Tab'){e.preventDefault();inp.blur();}};
});
w.body.querySelector(`#${w.id}-ds`).onclick=()=>{const csv=cells.map(r=>r.join(',')).join('\n');OB.put('dataset',{title:'Sheet Export',format:'csv',rows:ROWS,columns:COLS,data:csv});ntf('Dataset','Exported to Datasets');};
w.body.querySelector(`#${w.id}-csv`).onclick=()=>{const csv=cells.map(r=>r.join(',')).join('\n');const b=new Blob([csv]);const a=document.createElement('a');a.href=URL.createObjectURL(b);a.download='sheet.csv';a.click();};
}
function evalFormula(f,cells){
try{
let expr=f.slice(1).toUpperCase();
// SUM(A1:A5), simple cell refs
const sumMatch=expr.match(/SUM\(([A-Z])(\d+):([A-Z])(\d+)\)/);
if(sumMatch){const c=sumMatch[1].charCodeAt(0)-65;const r1=+sumMatch[2]-1;const r2=+sumMatch[4]-1;let s=0;for(let r=r1;r<=r2;r++)s+=parseFloat(cells[r]?.[c]||0)||0;return String(s);}
// Cell refs: A1, B2
expr=expr.replace(/([A-Z])(\d+)/g,(_,col,row)=>{const v=cells[+row-1]?.[col.charCodeAt(0)-65]||'0';return isNaN(v)?'0':v;});
return String(Function('"use strict";return('+expr+')')());
}catch{return '#ERR';}
}
render();
}});
const _Dashboards=()=>cwin({title:'Dashboard',icon:'📊',app:'dash',width:600,height:460,init:w=>{
function render(){
const tasks=OB.query('task');const mails=OB.query('mail');const events=OB.query('event');const notes=OB.query('note');
const todo=tasks.filter(t=>t.status==='todo').length;const inProg=tasks.filter(t=>t.status==='in-progress').length;const done=tasks.filter(t=>t.status==='done').length;
const unread=mails.filter(m=>!m.read).length;
const barMax=Math.max(todo,inProg,done,1);
function bar(val,max,color){return `${val}
`;}
w.body.innerHTML=`📊 Dashboard ${OB.objects.size} objects
Task Status
${bar(todo,barMax,'var(--inf)')}
Todo
${bar(inProg,barMax,'var(--ac2)')}
Active
${bar(done,barMax,'var(--ac)')}
Done
Recent Activity
${OB.query(null,null,{limit:6}).map(o=>`
${o.type} ${esc(o.title||o.name||o.subject||'—')}
`).join('')}
`;
}
render();const iv=setInterval(render,4000);w.onClose=()=>clearInterval(iv);
}});
// ── Keep remaining factory apps for smaller types ──
const _KB=mkDataApp('note','Knowledge Base','📚',[{key:'title',label:'Title'},{key:'body',label:'Body'},{key:'category',label:'Category'}],520,440);
const _Journal=mkDataApp('journal','Journal','📓',[{key:'title',label:'Entry Title'},{key:'body',label:'Text'},{key:'mood',label:'Mood'}]);
const _Scratch=mkDataApp('scratch','Scratchpad','📋',[{key:'text',label:'Text'}],360,300);
const _Kanban=mkDataApp('task','Kanban Board','▣',[{key:'title',label:'Task'},{key:'status',label:'Column',def:'todo'},{key:'priority',label:'Priority'}],600,420);
const _Contacts=mkDataApp('contact','Contacts','👤',[{key:'name',label:'Name'},{key:'email',label:'Email'},{key:'org',label:'Organization'},{key:'phone',label:'Phone'}]);
const _Projects=mkDataApp('project','Projects','◆',[{key:'title',label:'Project'},{key:'status',label:'Status',def:'active'},{key:'description',label:'Description'}],540,420);
const _Bookmarks=mkDataApp('bookmark','Bookmarks','🔖',[{key:'title',label:'Title'},{key:'url',label:'URL'}]);
const _Datasets=mkDataApp('dataset','Datasets','◫',[{key:'title',label:'Name'},{key:'format',label:'Format',def:'csv'},{key:'rows',label:'Rows'},{key:'columns',label:'Columns'}]);
const _Approvals=mkDataApp('approval','Approvals','✔',[{key:'title',label:'Request'},{key:'status',label:'Status',def:'pending'},{key:'requester',label:'Requester'}]);
const _Invoices=mkDataApp('invoice','Invoices','$',[{key:'title',label:'Invoice #'},{key:'amount',label:'Amount'},{key:'client',label:'Client'},{key:'status',label:'Status',def:'draft'}]);
const _Inventory=mkDataApp('inventory','Inventory','▣',[{key:'name',label:'Item'},{key:'category',label:'Category'},{key:'quantity',label:'Qty'},{key:'location',label:'Location'}]);
const _CRM=mkDataApp('lead','CRM','◈',[{key:'name',label:'Company'},{key:'contact',label:'Contact'},{key:'stage',label:'Stage',def:'new'},{key:'value',label:'Value'}],540,420);
const _Tickets=mkDataApp('ticket','Support Desk','⚐',[{key:'title',label:'Issue'},{key:'priority',label:'Priority',def:'medium'},{key:'status',label:'Status',def:'open'},{key:'reporter',label:'Reporter'}]);
const _Expenses=mkDataApp('expense','Expenses','¢',[{key:'title',label:'Description'},{key:'amount',label:'Amount'},{key:'category',label:'Category'},{key:'date',label:'Date'}]);
const _Snippets=mkDataApp('snippet','Snippets','<>',[{key:'title',label:'Name'},{key:'body',label:'Code'}],500,380);
const _Templates=mkDataApp('template','Templates','▧',[{key:'title',label:'Template Name'},{key:'body',label:'Content'},{key:'category',label:'Category'}]);
const _Procedures=mkDataApp('procedure','Procedures','▤',[{key:'title',label:'SOP Title'},{key:'body',label:'Steps'}]);
const _Risks=mkDataApp('risk','Risk Register','⚠',[{key:'title',label:'Risk'},{key:'probability',label:'Probability'},{key:'impact',label:'Impact'},{key:'mitigation',label:'Mitigation'}]);
const _Decisions=mkDataApp('decision','Decision Journal','◇',[{key:'title',label:'Decision'},{key:'date',label:'Date'},{key:'rationale',label:'Rationale'},{key:'outcome',label:'Outcome'}]);
const _Habits=mkDataApp('habit','Habits','↻',[{key:'title',label:'Habit'},{key:'frequency',label:'Frequency',def:'daily'},{key:'streak',label:'Streak',def:'0'}]);
const _Flashcards=mkDataApp('flashcard','Flashcards','⬡',[{key:'title',label:'Question'},{key:'body',label:'Answer'}]);
const _Courses=mkDataApp('course','Courses','🎓',[{key:'title',label:'Course'},{key:'lessons',label:'Total Lessons'},{key:'progress',label:'Completed'}]);
const _Scenarios=mkDataApp('scenario','Scenarios','⟡',[{key:'title',label:'Scenario'},{key:'assumptions',label:'Assumptions'},{key:'outcome',label:'Outcome'}]);
const _Citations=mkDataApp('citation','Citations','❝',[{key:'title',label:'Source'},{key:'author',label:'Author'},{key:'url',label:'URL'},{key:'quote',label:'Key Quote'}]);
const _Assets=mkDataApp('asset','Assets','⊟',[{key:'name',label:'Asset'},{key:'serial',label:'Serial #'},{key:'status',label:'Status',def:'active'},{key:'location',label:'Location'}]);
const _Vendors=mkDataApp('vendor','Vendors','⊞',[{key:'name',label:'Vendor'},{key:'contact',label:'Contact'},{key:'contract',label:'Contract #'}]);
const _Budgets=mkDataApp('budget','Budget Planner','$',[{key:'title',label:'Budget'},{key:'amount',label:'Total'},{key:'spent',label:'Spent'},{key:'category',label:'Category'}]);
const _Forms=mkDataApp('form','Forms','☐',[{key:'title',label:'Form Name'},{key:'fields',label:'Fields'},{key:'responses',label:'Responses',def:'0'}]);
const _Milestones=mkDataApp('milestone','Milestones','◎',[{key:'title',label:'Milestone'},{key:'date',label:'Target Date'},{key:'status',label:'Status',def:'upcoming'}]);
const _Announcements=mkDataApp('announcement','Announcements','📢',[{key:'title',label:'Title'},{key:'body',label:'Message'},{key:'audience',label:'Audience',def:'all'}]);
const _Reminders=mkDataApp('reminder','Reminders','⏰',[{key:'title',label:'Reminder'},{key:'date',label:'When'},{key:'repeat',label:'Repeat',def:'none'}]);
// ── COMPOSITE VIEW APPS ──
const _Search=()=>cwin({title:'Search',icon:'🔍',app:'search',width:500,height:400,init:w=>{
w.body.innerHTML=`
`;
w.body.querySelector(`#${w.id}-q`).oninput=e=>{
const q=e.target.value;if(q.length<2){w.body.querySelector(`#${w.id}-res`).innerHTML='';return;}
const results=OB.search(q);
let html=`${results.length} results for "${esc(q)}"
`;
for(const o of results){html+=`${o.type} ${esc(o.title||o.name||o.subject||o.id)} ${o._tags.map(t=>'#'+t).join(' ')}
`;}
w.body.querySelector(`#${w.id}-res`).innerHTML=html;
};
}});
const _Timeline=mkViewApp('Activity Timeline','⏱',()=>{
const all=OB.query().slice(0,40);
return all.map(o=>`${new Date(o._modified).toLocaleTimeString()} ${o.type} ${esc(o.title||o.name||o.subject||o.id)}
`).join('');
});
const _ClipHub=()=>cwin({title:'Clipboard Hub',icon:'📎',app:'clip',width:400,height:360,init:w=>{
const clips=OB.query('clip');
w.body.innerHTML=`📎 Clipboard + Clip
${clips.map(c=>`
${esc(c.text||c.title||'')}
`).join('')||'
No clips. Use + Clip to add.
'}
`;
}});
const _Agenda=mkViewApp('Agenda','📋',()=>{
const today=new Date().toISOString().split('T')[0];
const events=OB.query('event');const tasks=OB.query('task',t=>t.status!=='done');const mail=OB.query('mail',m=>!m.read);
return `Today's Events
${events.slice(0,5).map(e=>`📅 ${e.title} ${e.time||''}
`).join('')||'No events
'}
Active Tasks
${tasks.slice(0,5).map(t=>`✓ ${t.title} ${t.priority||'—'}
`).join('')||'No tasks
'}
Unread Mail
${mail.slice(0,5).map(m=>`✉ ${m.subject} ${m.from||''}
`).join('')||'All read
'}`;
},480,440);
const _PersonalDash=mkViewApp('Command Center','◆',()=>{
const s=OB.stats();const ss=Sync.getStatus();
return `
${Object.keys(s.types).length}
Types
${Snaps.snapshots.length}
Snapshots
Recent Activity
${OB.query().slice(0,8).map(o=>`${o.type} ${esc(o.title||o.name||o.subject||'—')}
`).join('')}
Workspace
Transport ${Transport.mode}
Encryption ${Crypto.ready?'AES-256-GCM ✓':'off'}
Services ${[...SvcMgr.services.values()].filter(s=>s.state==='running').length}/${SvcMgr.services.size}
`;
},500,460);
// ── EXISTING ADMIN APPS (kept compact) ──
function appSysmon(){cwin({title:'System Monitor',icon:'⬡',app:'sysmon',width:400,height:460,init:w=>{function render(){const up=((Date.now()-K.bootTime)/1000)|0;const mp=Math.min(100,Math.round(K.memUsed/K.memTotal*100));w.body.innerHTML=`CPU
Matrix ISA ${K.cpuUsage}%
Memory
${(K.memUsed/1024)|0}K / ${(K.memTotal/1024)|0}K ${mp}%
Object Store
${OB.objects.size} objects ${Object.keys(OB.stats().types).length} types
System
Uptime ${Math.floor(up/3600)}h ${Math.floor((up%3600)/60)}m
Processes ${K.procs.length}
Services ${SvcMgr.services.size}
Transport ${Transport.mode}
Encryption ${Crypto.ready?'✓':'-'}
Packages ${K.packages.size}
`;} render();const iv=setInterval(render,2000);w.onClose=()=>clearInterval(iv);}});}
function appProcs(){cwin({title:'Processes',icon:'≡',app:'procs',width:480,height:340,init:w=>{function render(){const sys=[{pid:0,ppid:0,name:'kernel',state:'running',cpu:1,mem:128},{pid:1,ppid:0,name:'wm',state:'running',cpu:2,mem:64}];let rows='';for(const p of[...sys,...K.procs])rows+=`${p.pid} ${p.name} ${p.mem||0}K ${p.cpu||0}% ${p.state}
`;w.body.innerHTML=`PID Name Mem CPU State
${rows}
`;}render();const iv=setInterval(render,2000);w.onClose=()=>clearInterval(iv);}});}
function appServices(){cwin({title:'Services',icon:'⚑',app:'svcs',width:580,height:440,init:w=>{function render(){const svcs=[...SvcMgr.services.values()];let rows='';for(const s of svcs)rows+=`${s.name} ${s.state} ${s.enabled?'✓':'✗'} ${s.pid||'-'} ${s.version} `;w.body.innerHTML=`⚑ Services
`;}render();const iv=setInterval(render,3000);w.onClose=()=>clearInterval(iv);}});}
function appLogs(){cwin({title:'Audit Logs',icon:'▤',app:'logs',width:620,height:440,init:w=>{function render(){const entries=Audit.entries.slice(-80);let rows='';for(const e of entries){const lc=e.level==='error'?'color:var(--wr)':e.level==='warn'?'color:#c4a000':'color:var(--txD)';rows+=`${new Date(e.ts).toLocaleTimeString()} ${e.level} ${e.source} ${esc(e.message).substring(0,100)}
`;}w.body.innerHTML=`▤ Logs ${entries.length}
${rows}
`;}render();const iv=setInterval(render,2000);w.onClose=()=>clearInterval(iv);}});}
function appConfig(){cwin({title:'Config',icon:'⚿',app:'cfg',width:520,height:420,init:w=>{function render(){const items=Cfg.list();let rows='';for(const i of items){const p=i.key.split('.');rows+=`${p.slice(0,-1).join('.')} ${p[p.length-1]} ${JSON.stringify(i.value)}
`;}w.body.innerHTML=`⚿ Config v${Cfg.version} · ${Cfg.data.size} keys
${rows}
`;}render();const iv=setInterval(render,3000);w.onClose=()=>clearInterval(iv);}});}
function appPolicies(){cwin({title:'Policies',icon:'⛊',app:'pol',width:540,height:440,init:w=>{function render(){const all=Cap.listAllGrants();let gr='';for(const[id,caps]of Object.entries(all))gr+=`${id} ${caps.map(c=>''+c+' ').join(' ')}
`;let den='';for(const d of Cap.denied.slice(-10))den+=`${new Date(d.ts).toLocaleTimeString()} ${d.cap} ${d.identity}
`;w.body.innerHTML=`⛊ Security ${Cap.checks} checks
Grants
${gr}
Denials
${den||'
none '}
`;}render();const iv=setInterval(render,3000);w.onClose=()=>clearInterval(iv);}});}
function appMetrics(){cwin({title:'Metrics',icon:'◉',app:'metrics',width:540,height:460,init:w=>{function render(){const m=Metrics.getCurrent();const h=Metrics.getHistory(20);const spark=h.map(s=>{const v=Math.round((s.cpu||0)/Math.max(...h.map(x=>x.cpu||1),1)*6);return'▁▂▃▄▅▆█'[Math.min(v,6)];}).join('');w.body.innerHTML=`◉ Metrics ${Crypto.ready?'🔒':'🔓'}
${OB.objects.size}
Objects
${m.svcs_running||0}/${m.svcs_total||0}
Services
CPU
${spark}
`;}render();const iv=setInterval(render,3000);w.onClose=()=>clearInterval(iv);}});}
function appSync(){cwin({title:'Sync',icon:'⇄',app:'sync',width:500,height:420,init:w=>{function render(){const ss=Sync.getStatus();const ws=Workspaces.getActive();w.body.innerHTML=`
${ws?.name||'Default'}
${Transport.mode} · ${ss.state} · ${Crypto.ready?'🔒':''}
Sync `;}render();const iv=setInterval(render,2500);w.onClose=()=>clearInterval(iv);}});}
function appFB(){cwin({title:'Display',icon:'◧',app:'fb',width:520,height:340,init:w=>{w.body.innerHTML=`XOR Plasma Noise 480×270
`;const cv=document.getElementById(w.id+'-c'),ctx=cv.getContext('2d'),W=480,H=270,img=ctx.createImageData(W,H);function draw(fn){for(let y=0;y{let f=0;(function a(){draw((x,y)=>{const v=((x+f)^(y+f))&255;return[v,v*.7,v*.4];});f++;if(f<120)requestAnimationFrame(a);})();};w.body.querySelector(`#${w.id}-p`).onclick=()=>{let t=0;(function a(){draw((x,y)=>{const v=Math.sin(x/20+t)+Math.sin(y/15+t*.7)+Math.sin((x+y)/25+t*1.3);const n=(v+3)/6;return[Math.sin(n*3.14)*255,Math.sin(n*3.14+2.09)*255,Math.sin(n*3.14+4.18)*255];});t+=.05;if(t<6)requestAnimationFrame(a);})();};w.body.querySelector(`#${w.id}-n`).onclick=()=>draw(()=>{const v=Math.random()*255;return[v,v,v];});draw((x,y)=>{const v=(x^y)&255;return[v*.2,v*.6,v*.9];});}});}
function appSettings(){cwin({title:'Settings',icon:'⚙',app:'settings',width:460,height:620,init:w=>{
const allWs=Workspaces.list();
const activeWs=Workspaces.getActive()||Workspaces.ensureCurrent('user');
const wsOptions=allWs.map(ws=>`${ws.name} `).join('');
w.body.innerHTML=`Workspace
Current ${activeWs?.name||'Default'}
Database ${getWorkspaceDbName()}
Switch Workspace ${wsOptions} Open
Create Workspace Create
Delete Current Delete
System
Objects ${OB.objects.size} (${Object.keys(OB.stats().types).length} types)
Encryption ${Crypto.ready?'AES-256-GCM ✓':'off'}
Transport ${Transport.mode}
Services ${SvcMgr.services.size}
Data
Export Capsule Export
Import Capsule Import
Create Snapshot Snap
Factory Reset Reset
`;
}});}
function appAbout(){cwin({title:"About",icon:"ⓘ",app:"about",width:400,height:480,init:w=>{const cs=Crypto.getStatus();w.body.innerHTML=`◆ MATRIXOS
Capsule v6.0 — Ship
Encrypted personal workspace. All security claims match implementation. Version history, subtasks, attachments, cross-linking, idle relock, key rotation, snapshot compare.
Apps ${APPS.length} integrated
Commands ${Object.keys(BUILTINS).length}
Objects ${OB.objects.size} (${OBJ_TYPES.length} types)
Lock ${cs.state}
Cipher ${cs.algorithm}
KDF ${cs.kdf}
Keys Unlock→Master→Content→Meta→Snapshot
PQ ${cs.pqState}
Idle relock 5 min
Journal WAL + real undo
Automation ${Automate.rules.length} rules
Events ${Bus.history.length} on bus
Services ${SvcMgr.services.size}
Reconnect auto
Sync ${Sync.getStatus().state}
Export .mxcapsule + dry-run + verify
`;}})}
// ═══ MASTER APP REGISTRY ════════════════════════════════════════════════════
const APPS=[
// Core Shell
{id:'term',name:'Terminal',icon:'⌘',desc:'Shell',fn:appTerminal},
{id:'files',name:'Files',icon:'📁',desc:'File manager',fn:appFiles},
{id:'edit',name:'Editor',icon:'✎',desc:'Text editor',fn:()=>appEditor(null)},
{id:'search',name:'Search',icon:'🔍',desc:'Global search',fn:_Search},
{id:'launcher',name:'Command Center',icon:'◆',desc:'Unified cockpit',fn:_PersonalDash},
{id:'browser',name:'Browser',icon:'🌐',desc:'Secure web shell',fn:_Browser},
{id:'clip',name:'Clipboard',icon:'📎',desc:'Clip history',fn:_ClipHub},
{id:'agenda',name:'Agenda',icon:'📋',desc:'Daily planner',fn:_Agenda},
{id:'timeline',name:'Timeline',icon:'⏱',desc:'Activity stream',fn:_Timeline},
// Notes & Knowledge
{id:'notes',name:'Notes',icon:'📝',desc:'Quick notes',fn:_Notes},
{id:'kb',name:'Knowledge Base',icon:'📚',desc:'Wiki',fn:_KB},
{id:'journal',name:'Journal',icon:'📓',desc:'Daily log',fn:_Journal},
{id:'scratch',name:'Scratchpad',icon:'📋',desc:'Temp notes',fn:_Scratch},
{id:'snippets',name:'Snippets',icon:'<>',desc:'Code snippets',fn:_Snippets},
{id:'templates',name:'Templates',icon:'▧',desc:'Reusable docs',fn:_Templates},
{id:'procedures',name:'Procedures',icon:'▤',desc:'SOPs',fn:_Procedures},
{id:'citations',name:'Citations',icon:'❝',desc:'Sources',fn:_Citations},
// Communication
{id:'mail',name:'Mail',icon:'✉',desc:'Email client',fn:_Mail},
{id:'contacts',name:'Contacts',icon:'👤',desc:'People & orgs',fn:_Contacts},
{id:'calendar',name:'Calendar',icon:'📅',desc:'Events',fn:_Calendar},
{id:'reminders',name:'Reminders',icon:'⏰',desc:'Alerts',fn:_Reminders},
{id:'announce',name:'Announcements',icon:'📢',desc:'Broadcasts',fn:_Announcements},
// Tasks & Projects
{id:'tasks',name:'Tasks',icon:'✓',desc:'To-do list',fn:_Tasks},
{id:'kanban',name:'Kanban',icon:'▣',desc:'Workflow board',fn:_Kanban},
{id:'projects',name:'Projects',icon:'◆',desc:'Project mgr',fn:_Projects},
{id:'milestones',name:'Milestones',icon:'◎',desc:'Deadlines',fn:_Milestones},
{id:'approvals',name:'Approvals',icon:'✔',desc:'Review chain',fn:_Approvals},
// Wave 1 Office
{id:'docs',name:'Documents',icon:'📄',desc:'Rich document editor',fn:_Docs},
{id:'sheet',name:'Spreadsheet',icon:'▦',desc:'Sheets & formulas',fn:_Spreadsheet},
// Data & Analytics
{id:'datasets',name:'Datasets',icon:'◫',desc:'Data manager',fn:_Datasets},
{id:'dashboards',name:'Dashboards',icon:'📊',desc:'BI dashboards',fn:_Dashboards},
{id:'scenarios',name:'Scenarios',icon:'⟡',desc:'What-if',fn:_Scenarios},
// Business & Ops
{id:'crm',name:'CRM',icon:'◈',desc:'Leads & deals',fn:_CRM},
{id:'tickets',name:'Support',icon:'⚐',desc:'Help desk',fn:_Tickets},
{id:'invoices',name:'Invoices',icon:'$',desc:'Billing',fn:_Invoices},
{id:'expenses',name:'Expenses',icon:'¢',desc:'Spend tracker',fn:_Expenses},
{id:'budgets',name:'Budgets',icon:'$',desc:'Budget plan',fn:_Budgets},
{id:'inventory',name:'Inventory',icon:'▣',desc:'Stock/items',fn:_Inventory},
{id:'assets',name:'Assets',icon:'⊟',desc:'Equipment',fn:_Assets},
{id:'vendors',name:'Vendors',icon:'⊞',desc:'Suppliers',fn:_Vendors},
{id:'forms',name:'Forms',icon:'☐',desc:'Data collection',fn:_Forms},
// Learning
{id:'flashcards',name:'Flashcards',icon:'⬡',desc:'Spaced rep',fn:_Flashcards},
{id:'courses',name:'Courses',icon:'🎓',desc:'Learning',fn:_Courses},
// Planning
{id:'risks',name:'Risks',icon:'⚠',desc:'Risk register',fn:_Risks},
{id:'decisions',name:'Decisions',icon:'◇',desc:'Decision log',fn:_Decisions},
{id:'habits',name:'Habits',icon:'↻',desc:'Habit tracker',fn:_Habits},
{id:'bookmarks',name:'Bookmarks',icon:'🔖',desc:'Saved links',fn:_Bookmarks},
// System & Admin
{id:'sysmon',name:'Monitor',icon:'⬡',desc:'System stats',fn:appSysmon},
{id:'calc',name:'Calculator',icon:'⊞',desc:'Calculator',fn:appCalc},
{id:'procs',name:'Processes',icon:'≡',desc:'Process mgr',fn:appProcs},
{id:'svcs',name:'Services',icon:'⚑',desc:'Services',fn:appServices},
{id:'logs',name:'Logs',icon:'▤',desc:'Audit logs',fn:appLogs},
{id:'cfgui',name:'Config',icon:'⚿',desc:'Config registry',fn:appConfig},
{id:'polui',name:'Policies',icon:'⛊',desc:'Security',fn:appPolicies},
{id:'metrui',name:'Metrics',icon:'◉',desc:'Metrics',fn:appMetrics},
{id:'syncui',name:'Sync',icon:'⇄',desc:'Sync & workspace',fn:appSync},
{id:'fbview',name:'Display',icon:'◧',desc:'Framebuffer',fn:appFB},
{id:'settings',name:'Settings',icon:'⚙',desc:'Preferences',fn:appSettings},
{id:'about',name:'About',icon:'ⓘ',desc:'System info',fn:appAbout},
// Wave 3 — Builder & Advanced
{id:'pkgbuild',name:'Pkg Builder',icon:'⊕',desc:'Create packages',fn:()=>cwin({title:'Package Builder',icon:'⊕',app:'pkgbuild',width:480,height:400,init:w=>{
const pkgs=K.vfs.readdir('/var/pkg')||[];
let cards='';for(const p of pkgs){const m=K.vfs.readFile(`/var/pkg/${p}/manifest.json`);let info='';try{const j=JSON.parse(m);info=`v${j.version} · ${j.type||'app'} · ${j.integrity?'✓ signed':'unsigned'}`;}catch{info='no manifest';}
cards+=``;}
w.body.innerHTML=`⊕ Package Builder + New
${cards||'
No packages. Use terminal: build package NAME
'}
CLI Commands
build package NAME [dir] [version] build service NAME build sign NAME build verify NAME
`;}})},
{id:'svcbuild',name:'Svc Builder',icon:'⊗',desc:'Create services',fn:()=>cwin({title:'Service Builder',icon:'⊗',app:'svcbuild',width:480,height:380,init:w=>{
const svcs=K.vfs.readdir('/etc/services')||[];
let rows='';for(const f of svcs){if(!f.endsWith('.json'))continue;try{const m=JSON.parse(K.vfs.readFile('/etc/services/'+f));rows+=`${m.name} ${m.version} ${m.depends_on?.join(',')||'-'} ${m.restart} `;}catch{}}
w.body.innerHTML=`⊗ Service Builder + New
Name Ver Deps Restart ${rows}
CLI
build service NAME svc start NAME svc status NAME
`;}})},
{id:'workflow',name:'Workflows',icon:'⤷',desc:'Automation rules',fn:()=>cwin({title:'Automation Workflows',icon:'⤷',app:'workflow',width:520,height:400,init:w=>{
function render(){const rules=Automate.listRules();const stats=Automate.stats();const evCounts=Bus.countByType();
let ruleCards='';for(const r of rules)ruleCards+=`${r.enabled?'ON':'OFF'} ${r.name} ${r.event} · ${r.runs} runs
`;
let evList='';for(const[ev,c]of Object.entries(evCounts).sort((a,b)=>b[1]-a[1]).slice(0,10))evList+=`${ev} ${c}
`;
w.body.innerHTML=`⤷ Automation ${stats.rules} rules · ${stats.executions} fired
Active Rules
${ruleCards||'
No rules
'}
Event Frequency
${evList}
Recent Events
${Bus.recent(8).map(e=>`
${new Date(e.ts).toLocaleTimeString()} ${e.event}
`).join('')}
`;}
render();const iv=setInterval(render,3000);w.onClose=()=>clearInterval(iv);}})},
{id:'schemaui',name:'Schema',icon:'⊞',desc:'Object schema browser',fn:mkViewApp('Schema Browser','⊞',()=>{
const s=OB.stats();
return `Object Types (${OBJ_TYPES.length})
${OBJ_TYPES.map(t=>`${t}: ${s.types[t]||0} `).join(' ')}
Universal Fields
id · type · title · owner · created_at · updated_at · status · _tags[] · _links[] · _comments[] · permissions · metadata
Index
Terms ${s.indexTerms}
Objects ${s.total}
Automation
Rules ${Automate.rules.length}
Bus events ${Bus.history.length}
`;
},460,420)},
{id:'remoteui',name:'Remote',icon:'☁',desc:'Remote workspace',fn:mkViewApp('Remote Workspace','\u2601',()=>{
const ts=Transport.stats;
return `
Workspace API v1.0
${ts.mode} · ${ts.session||'no session'}
Transport
Mode ${ts.mode}
Messages ${ts.msgCount}
Bytes ↑/↓ ${ts.bytesSent}/${ts.bytesRecv}
Queue ${ts.queued}
API Endpoints (${['auth','file','object','process','service','package','snapshot','search','event','config','audit'].length})
${['auth.login','file.read/write/list','object.query/get/update','process.spawn/attach','service.list/start/stop','package.install/remove/verify','snapshot.create/restore','search.query/reindex','event.stream','config.get/set','audit.query'].map(e=>''+e+' ').join(' ')}
Sync
State ${Sync.getStatus().state}
Pending ${Sync.pending}
Conflicts ${Sync.conflicts.length}
`;
},500,460)},
];
// ═══ §13 DESKTOP CHROME ═════════════════════════════════════════════════════
function esc(s){return s.replace(/&/g,'&').replace(//g,'>');}
function ntf(title,body,dur=3000){const a=document.getElementById('na');const e=document.createElement('div');e.className='nf';e.innerHTML=`${title}
${body}
`;a.appendChild(e);e.onclick=()=>{e.classList.add('out');setTimeout(()=>e.remove(),300);};setTimeout(()=>{e.classList.add('out');setTimeout(()=>e.remove(),300);},dur);}
// Launcher
function buildLauncher(){const l=document.getElementById('lml');function render(f=''){l.innerHTML='';for(const a of APPS){if(f&&!a.name.toLowerCase().includes(f)&&!a.desc.toLowerCase().includes(f))continue;const e=document.createElement('div');e.className='lmi';e.innerHTML=`${a.icon}
`;e.onclick=()=>{a.fn();closeLM();};l.appendChild(e);}}render();document.getElementById('lms').oninput=e=>render(e.target.value);}
let lmOpen=false;
function toggleLM(){lmOpen=!lmOpen;document.getElementById('lm').classList.toggle('open',lmOpen);if(lmOpen)document.getElementById('lms').focus();}
function closeLM(){lmOpen=false;document.getElementById('lm').classList.remove('open');}
document.getElementById('lb').onclick=toggleLM;
document.addEventListener('click',e=>{if(lmOpen&&!e.target.closest('#lm')&&!e.target.closest('#lb'))closeLM();});
// Desktop icons
function buildIcons(){
const c=document.getElementById('di');
[{icon:'⌘',l:'Terminal',fn:appTerminal},{icon:'📁',l:'Files',fn:appFiles},{icon:'📝',l:'Notes',fn:_Notes},{icon:'✉',l:'Mail',fn:_Mail},{icon:'✓',l:'Tasks',fn:_Tasks},{icon:'📅',l:'Calendar',fn:_Calendar},{icon:'📊',l:'Dashboard',fn:_Dashboards},{icon:'🌐',l:'Browser',fn:_Browser},{icon:'📄',l:'Docs',fn:_Docs},{icon:'⚙',l:'Settings',fn:appSettings}].forEach(i=>{
const e=document.createElement('div');e.className='dico';e.innerHTML=`${i.icon}
${i.l}
`;e.ondblclick=()=>i.fn();c.appendChild(e);
});
}
// Context menu
document.addEventListener('contextmenu',e=>{e.preventDefault();const m=document.getElementById('ctx');m.innerHTML='';
[{l:'New Terminal',fn:appTerminal},{l:'New File',fn:()=>{const n=prompt('Filename:','untitled.txt');if(n){K.vfs.writeFile('/home/user/'+n,'');ntf('Created',n);}}},{sep:1},{l:'Refresh',fn:()=>ntf('Desktop','Refreshed')},{l:'Settings',fn:appSettings},{l:'About',fn:appAbout}].forEach(i=>{
if(i.sep){m.insertAdjacentHTML('beforeend','
');return;}
const e=document.createElement('div');e.className='ci';e.textContent=i.l;e.onclick=()=>{m.classList.remove('open');i.fn();};m.appendChild(e);
});
m.style.left=Math.min(e.clientX,innerWidth-180)+'px';m.style.top=Math.min(e.clientY,innerHeight-200)+'px';m.classList.add('open');});
document.addEventListener('click',e=>{if(!e.target.closest('#ctx'))document.getElementById('ctx').classList.remove('open');});
// Clock & system tick
function tick(){
const d=new Date();document.getElementById('ck').textContent=d.toLocaleTimeString([],{hour:'2-digit',minute:'2-digit',second:'2-digit'});
const activeWindows=wins.filter(w=>!w.min).length;
K.cpuUsage=Math.min(100,Math.max(1,activeWindows*4+Math.min(6,Math.ceil(K.procs.length/3))));
Footprint.update();
K.totalCycles+=K.cpuUsage*100;
const memPct=Math.min(100,Math.round(K.memUsed/Math.max(1,K.memTotal)*100));
document.getElementById('tc').textContent='⬡ '+K.cpuUsage+'%';
document.getElementById('tm').textContent='▦ '+memPct+'%';
}
setInterval(tick,1500);tick();
// Keyboard shortcuts
document.addEventListener('keydown',e=>{
if(e.ctrlKey&&e.altKey&&e.key==='t'){e.preventDefault();appTerminal();}
if(e.ctrlKey&&e.altKey&&e.key==='f'){e.preventDefault();appFiles();}
if(e.ctrlKey&&e.altKey&&e.key==='e'){e.preventDefault();appEditor(null);}
});
// ═══ §14 BOOT SEQUENCE ══════════════════════════════════════════════════════
async function boot(){
// ═══ PHASE 0: Password lock screen ═══
// Workspace is LOCKED until password succeeds
Workspaces.ensureCurrent('user');
try{await openDB();}catch(e){console.warn('IndexedDB:',e);}
let isNew=true;
if(db){try{const s=await dbGet('meta','workspaceSalt');if(s)isNew=false;}catch{}}
const lockScreen=document.getElementById('lock-screen');
const lockWs=document.getElementById('lock-ws');
const lockWsName=document.getElementById('lock-wsname');
const lockPw=document.getElementById('lock-pw');
const lockBtn=document.getElementById('lock-go');
const lockMode=document.getElementById('lock-mode');
const lockErr=document.getElementById('lock-err');
let createMode=false;
function refreshWorkspaceSelector(){
const list=Workspaces.list();
lockWs.innerHTML=list.map(ws=>`${ws.name} `).join('');
lockWs.disabled=createMode||!list.length;
}
async function refreshExistingState(){
if(!db){isNew=true;return;}
try{const s=await dbGet('meta','workspaceSalt');isNew=!s;}catch{isNew=true;}
lockPw.placeholder=isNew?'Create workspace password':'Workspace password';
lockBtn.textContent=isNew?'Create Workspace':'Unlock Workspace';
}
function setCreateMode(on){
createMode=!!on;
lockWs.style.display=createMode?'none':'';
lockWsName.style.display=createMode?'':'none';
lockMode.textContent=createMode?'Use Existing Workspace':'New Workspace';
if(createMode){
isNew=true;
lockPw.placeholder='Create workspace password';
lockBtn.textContent='Create Workspace';
lockWsName.focus();
}else{
refreshWorkspaceSelector();
refreshExistingState();
lockPw.focus();
}
}
refreshWorkspaceSelector();
await refreshExistingState();
lockWs.onchange=async()=>{
CURRENT_WORKSPACE_ID=lockWs.value||CURRENT_WORKSPACE_ID;
const ws=Workspaces.getById(CURRENT_WORKSPACE_ID);CURRENT_WORKSPACE_NAME=ws?.name||CURRENT_WORKSPACE_NAME;
await openDB();
await refreshExistingState();
lockErr.textContent='';
};
lockMode.onclick=async()=>{
setCreateMode(!createMode);
if(!createMode){await openDB();await refreshExistingState();}
};
// Wait for unlock
await new Promise(resolve=>{
async function tryUnlock(){
const pw=lockPw.value;
if(!pw){lockErr.textContent='Password required';return;}
if((isNew||createMode)&&pw.length<4){lockErr.textContent='Minimum 4 characters';return;}
lockErr.textContent='Unlocking...';lockBtn.disabled=true;lockMode.disabled=true;
let createdWs=null;
try{
if(createMode){
const wsName=(lockWsName.value||'').trim();
if(!wsName)throw new Error('Workspace name required');
createdWs=Workspaces.create(wsName,'user',{activate:false});
CURRENT_WORKSPACE_ID=createdWs.id;CURRENT_WORKSPACE_NAME=createdWs.name;
await openDB();
isNew=true;
}else if(lockWs.value){
Workspaces.activate(lockWs.value,{persist:true});
CURRENT_WORKSPACE_ID=lockWs.value;
const ws=Workspaces.getById(CURRENT_WORKSPACE_ID);CURRENT_WORKSPACE_NAME=ws?.name||CURRENT_WORKSPACE_NAME;
await openDB();
await refreshExistingState();
}
await Crypto.unlock(pw);
if(createdWs)Workspaces.activate(createdWs.id,{persist:true});
lockErr.textContent='';
lockScreen.classList.add('unlocked');
setTimeout(()=>lockScreen.remove(),500);
resolve();
}catch(e){
if(createdWs&&createMode){
try{await Workspaces.destroy(createdWs.id);}catch{}
createdWs=null;
refreshWorkspaceSelector();
}
lockErr.textContent=e?.message||((isNew||createMode)?'Failed to create workspace':'Wrong password');
lockBtn.disabled=false;lockMode.disabled=false;lockPw.value='';lockPw.focus();
}
}
lockBtn.onclick=tryUnlock;
lockPw.addEventListener('keydown',e=>{if(e.key==='Enter')tryUnlock();});
lockWsName.addEventListener('keydown',e=>{if(e.key==='Enter')tryUnlock();});
});
// ═══ PHASE 1: Boot sequence (workspace is now unlocked) ═══ // ═══ PHASE 1: Boot sequence (workspace is now unlocked) ═══
const bs=document.getElementById('bs');bs.style.display='flex';
const fill=document.getElementById('bf');const st=document.getElementById('bst');
const steps=[
[5,'Loading capsule core...'],
[12,'Mounting virtual filesystem...'],
[20,'Loading persistent state...'],
[28,'Recovering journal...'],
[34,'Initializing capabilities...'],
[40,'Starting audit (logd)...'],
[46,'Loading policies (policyd)...'],
[52,'Starting config (configd)...'],
[58,'Starting auth (authd)...'],
[63,'Starting packages (pkgd)...'],
[68,'Starting network (netd)...'],
[73,'Starting desktop (desktopd)...'],
[78,'Starting apps (appd)...'],
[82,'Starting sync (syncd)...'],
[86,'Initializing transport...'],
[89,'Provisioning workspace...'],
[92,'Wiring automation...'],
[95,'Starting metrics...'],
[97,'Seeding objects...'],
[99,'Verifying health...'],
[100,'Ready.'],
];
// §2 — Filesystem
initDefaultFS();setupDevices(K.vfs);setupProc(K.vfs,K);
await K.vfs.loadFromDB();
// §3 — Capabilities
initCaps();
// §4 — Journal recovery
WAL.recover();
// §5 — Config
Cfg.load();
Cfg.registerSchema('system.display',{width:{type:'number',min:320,max:1920},height:{type:'number',min:240,max:1080}});
Cfg.registerSchema('system.shell',{historySize:{type:'number',min:10,max:5000},tabComplete:{type:'boolean'}});
Cfg.registerSchema('system.sync',{autoSync:{type:'boolean'},interval:{type:'number',min:5000,max:300000}});
// §6 — Policies
const defPol=K.vfs.readFile('/etc/policies/default.json');
if(defPol){try{Policy.load('default',JSON.parse(defPol));}catch{}}
// §7 — Services
const svcDir=K.vfs.readdir('/etc/services')||[];
for(const fname of svcDir){
if(!fname.endsWith('.json'))continue;
const raw=K.vfs.readFile('/etc/services/'+fname);
if(raw){try{SvcMgr.register(JSON.parse(raw));}catch{}}
}
// §8 — Quotas
Quotas.setQuota('user','processes',64);
Quotas.setQuota('user','files',10000);
// Animate boot
let i=0;
await new Promise(res=>{
function next(){if(i>=steps.length){setTimeout(res,150);return;}fill.style.width=steps[i][0]+'%';st.textContent=steps[i][1];i++;setTimeout(next,50+Math.random()*40);}
setTimeout(next,100);
});
// §9 — Service boot
await SvcMgr.bootAll();
// §10 — Transport + workspace
await Transport.connect('local');
const ws=Workspaces.ensureCurrent('user');Workspaces.activate(ws.id,{persist:true});
// §11 — Apps + seed data
seedObjectStore();
const appDir2=K.vfs.readdir('/system/apps')||[];
for(const fname of appDir2){if(!fname.endsWith('.json'))continue;try{AppReg.register(JSON.parse(K.vfs.readFile('/system/apps/'+fname)));}catch{}}
for(const app of APPS)AppReg.register({id:app.id,name:app.name,class:'local',icon:app.icon,capabilities:['ui.window'],version:'6.0'});
// §12 — Automation + metrics
wireAutomation();
Metrics.start();
// §13 — Initial snapshot
await Snaps.create('boot');
// §14 — Desktop
bs.classList.add('done');setTimeout(()=>bs.remove(),600);
buildLauncher();buildIcons();
// §15 — Complete
const bootSec=((Date.now()-K.bootTime)/1000).toFixed(2);
Audit.log('info','boot',`Capsule ready in ${bootSec}s — ${SvcMgr.services.size} svcs, ${Crypto.keys.state}, ${OB.objects.size} objects`);
ntf('MatrixOS Capsule',`🔒 Encrypted · ${APPS.length} apps · ${OB.objects.size} objects`);
appTerminal();
// §16 — Persistence + sync + idle relock + auto-reconnect
const si=parseInt(Cfg.get('system.persistence','interval'))||15000;
setInterval(()=>{K.vfs._persist();Cfg.save();},si);
if(Cfg.get('system.sync','autoSync')!==false)setInterval(()=>Sync.sync(),30000);
Crypto.startIdleLock(300000); // 5 min idle relock
Transport.startAutoReconnect('local',20000);
}
boot();