kloudy 0.4.8 → 1.0.1

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.
Files changed (53) hide show
  1. package/AGENTS.md +54 -0
  2. package/LICENSE +202 -202
  3. package/MCP-DEFAULT.md +12 -12
  4. package/README.md +375 -315
  5. package/bin/entry.mjs +25 -22
  6. package/bin/kloudy.mjs +80 -71
  7. package/package.json +4 -2
  8. package/schemas/SDF-LICENSE.txt +21 -21
  9. package/schemas/kloudy.deployable-bot.schema.json +80 -0
  10. package/schemas/sdf-document-0.2.schema.json +411 -411
  11. package/schemas/sdf-webpage-v1.schema.json +176 -176
  12. package/src/activity.mjs +23 -23
  13. package/src/approval-ui.mjs +2 -2
  14. package/src/approval.mjs +25 -25
  15. package/src/autoupdate.mjs +2 -2
  16. package/src/bots.mjs +144 -0
  17. package/src/chooser-link.mjs +17 -17
  18. package/src/client.mjs +96 -96
  19. package/src/connect-card.mjs +32 -32
  20. package/src/connect-ui.mjs +3 -3
  21. package/src/connection.mjs +25 -25
  22. package/src/conversation.mjs +53 -53
  23. package/src/deployable-bots.json.gz +0 -0
  24. package/src/editor-install.mjs +79 -79
  25. package/src/host-interface.mjs +10 -10
  26. package/src/hosted.mjs +42 -42
  27. package/src/httpk.mjs +66 -66
  28. package/src/install.mjs +35 -35
  29. package/src/introduce.mjs +33 -33
  30. package/src/mcp.mjs +74 -74
  31. package/src/modalities.mjs +28 -0
  32. package/src/models.mjs +55 -55
  33. package/src/preferences-card.mjs +21 -21
  34. package/src/preferences-ui.mjs +2 -2
  35. package/src/product-actions.mjs +22 -22
  36. package/src/public.mjs +41 -41
  37. package/src/query.mjs +28 -28
  38. package/src/recommend.mjs +478 -0
  39. package/src/replies.mjs +7 -7
  40. package/src/reply-templates.json +12 -12
  41. package/src/sample-actions.mjs +31 -31
  42. package/src/sample-card.mjs +11 -11
  43. package/src/sample-cards.mjs +47 -47
  44. package/src/sample-ui.mjs +2 -2
  45. package/src/sdf-budget.mjs +23 -23
  46. package/src/sdf.mjs +12 -12
  47. package/src/starter.mjs +43 -43
  48. package/src/status-indicator.css +5 -5
  49. package/src/strings.mjs +51 -51
  50. package/src/terminal-status.mjs +6 -6
  51. package/src/website-return.mjs +18 -18
  52. package/src/welcome.mjs +8 -8
  53. package/src/wrap.mjs +58 -58
@@ -1,47 +1,47 @@
1
- // Portable, non-authorizing presentation contract. No credential or payment execution.
2
- export const SAMPLE_VERSION='kloudy.sample/1';
3
- export const SAMPLE_TITLE='Kloudy Sample card';
4
- export const preferenceChoices={
5
- tools:[['open_source','Open source'],['paid','Paid tools'],['hybrid','Mix of both'],['free_then_paid','Free tier, then ask']],
6
- target:[['local','This device'],['www','World Wide Web'],['bww','Bot Wide Web'],['mixed','A mix']],
7
- delivery:[['silent','Quietly'],['paid','Paid tools only'],['all','Every tool']]
8
- };
9
- export const preferenceDefaults=()=>({tools:null,target:null,delivery:'silent'});
10
- export function validPreferences(value){return !!value&&typeof value==='object'&&!Array.isArray(value)&&Object.keys(value).length===3&&Object.entries(preferenceChoices).every(([key,options])=>(key!=='delivery'&&value[key]===null)||options.some(([id])=>id===value[key]));}
11
- export function preferenceQuestion(step,surface='site'){
12
- const external=['ide','chatbot','terminal'].includes(surface);
13
- return [
14
- {key:'tools',question:'Which tools do you prefer?',intro:external?'Kloudy gives your assistant tools to build your projects.':'Kloudy uses tools to build your projects.'},
15
- {key:'target',question:'Where will your projects run?',intro:'Choose where people will use your projects.'},
16
- {key:'delivery',question:'How much should Kloudy show?',intro:'Quietly is the default. You can ask for updates instead.'}
17
- ][step]||null;
18
- }
19
- export class SamplePreferences{
20
- constructor(value=preferenceDefaults()){if(!validPreferences(value))throw Error('Invalid preferences');this.value=structuredClone(value);this.step=0;}
21
- choose(id){const q=preferenceQuestion(this.step);if(!q||!preferenceChoices[q.key].some(([value])=>value===id))throw Error('Choose one of the offered options.');this.value[q.key]=id;this.step++;return this.value;}
22
- back(){this.step=Math.max(0,this.step-1);}
23
- }
24
- export const cardKinds=['preferences','clarify','tools','attachment','signin','approval','payment','exhaustion','receipt','recovery','analytics','conversion'];
25
- export function shouldShowCard(kind,preferences=preferenceDefaults(),{paid=false,requested=false}={}){
26
- if(!cardKinds.includes(kind)||!validPreferences(preferences))return false;
27
- if(requested||['signin','approval','payment','exhaustion','recovery','clarify','attachment'].includes(kind))return true;
28
- if(kind==='tools')return preferences.delivery==='all'||(preferences.delivery==='paid'&&paid);
29
- return false;
30
- }
31
- export class SampleQueue{
32
- constructor(){this.current=null;this.waiting=[];this.seen=new Set();}
33
- offer(card,preferences,options){if(!card||!cardKinds.includes(card.kind)||typeof card.id!=='string'||card.id.length>160||this.seen.has(card.id)||!shouldShowCard(card.kind,preferences,options))return false;
34
- this.seen.add(card.id);if(this.seen.size>256)this.seen.delete(this.seen.values().next().value);
35
- const urgent=['payment','approval','exhaustion','recovery'].includes(card.kind);
36
- if(!this.current)this.current=card;else if(urgent&&!['payment','approval','exhaustion','recovery'].includes(this.current.kind)){this.waiting.unshift(this.current);this.current=card;}else this.waiting.push(card);
37
- this.waiting=this.waiting.slice(0,10);return true;
38
- }
39
- dismiss(){this.current=this.waiting.shift()||null;return this.current;}
40
- clear(){this.current=null;this.waiting=[];this.seen.clear();}
41
- }
42
- const esc=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
43
- export function samplePreferencesMarkup(flow,{surface='site',notice=''}={}){
44
- const q=preferenceQuestion(flow.step,surface),complete=!q;
45
- return `<section class="sample-card" aria-label="${SAMPLE_TITLE}"><header><span class="sample-orb" aria-hidden="true"></span><span>${SAMPLE_TITLE}</span><small>${complete?'Ready':(flow.step+1)+' / 3'}</small></header><h1 tabindex="-1">${complete?'Your way to build.':esc(q.question)}</h1>${complete?'':`<p>${esc(q.intro)}</p>`}${complete?`<dl>${Object.entries(preferenceChoices).map(([key,options])=>`<dt>${esc({tools:'Tools',target:'Where',delivery:'Updates'}[key])}</dt><dd>${esc(options.find(([id])=>id===flow.value[key])?.[1]||'Ask when needed')}</dd>`).join('')}</dl><button class="sample-primary" data-sample-save>Save preferences</button>`:`<div class="sample-options">${preferenceChoices[q.key].map(([id,label])=>`<button data-sample-choice="${id}" aria-pressed="${flow.value[q.key]===id}">${esc(label)}</button>`).join('')}</div>`}<p class="sample-note">${q?.key==='tools'?'Open source describes the tools; hosting or compute may still cost money.':q?.key==='target'?'Bot Wide Web sites need hosting: your computer, your cloud, or a paid host.':'New costs always need your approval. Ask which tools are connected anytime.'}</p><details><summary>How this works</summary><p>Quietly means fewer updates, not permission to spend. Free tiers ending always prompt a choice. These preferences do not install tools or authorize a connection.</p></details><footer>${flow.step?'<button data-sample-back>Back</button>':''}<button data-sample-later>Not now</button></footer><p role="status" class="sample-status">${esc(notice)}</p></section>`;
46
- }
47
- export function conversionCardMarkup(){return `<section class="sample-card"><header>${SAMPLE_TITLE}</header><h1>Let bots reach your site.</h1><p>Publish a BWW card so compatible assistants can fetch the part a user needs.</p><a class="sample-primary" href="https://kloudy.ai/hosting">Choose hosting</a><details><summary>Benefits and costs</summary><p>A converted site can offer structured fragments instead of a full browser visit. Actual compute, water and cost savings depend on measured usage; no fixed savings are promised.</p><p>Bring your PC or cloud, or use a paid host. If your compute goes offline, your site becomes unavailable. Concierge and ad bots are optional paid services.</p></details></section>`;}
1
+ // Portable, non-authorizing presentation contract. No credential or payment execution.
2
+ export const SAMPLE_VERSION='kloudy.sample/1';
3
+ export const SAMPLE_TITLE='Kloudy Sample card';
4
+ export const preferenceChoices={
5
+ tools:[['open_source','Open source'],['paid','Paid tools'],['hybrid','Mix of both'],['free_then_paid','Free tier, then ask']],
6
+ target:[['local','This device'],['www','World Wide Web'],['bww','Bot Wide Web'],['mixed','A mix']],
7
+ delivery:[['silent','Quietly'],['paid','Paid tools only'],['all','Every tool']]
8
+ };
9
+ export const preferenceDefaults=()=>({tools:null,target:null,delivery:'silent'});
10
+ export function validPreferences(value){return !!value&&typeof value==='object'&&!Array.isArray(value)&&Object.keys(value).length===3&&Object.entries(preferenceChoices).every(([key,options])=>(key!=='delivery'&&value[key]===null)||options.some(([id])=>id===value[key]));}
11
+ export function preferenceQuestion(step,surface='site'){
12
+ const external=['ide','chatbot','terminal'].includes(surface);
13
+ return [
14
+ {key:'tools',question:'Which tools do you prefer?',intro:external?'Kloudy gives your assistant tools to build your projects.':'Kloudy uses tools to build your projects.'},
15
+ {key:'target',question:'Where will your projects run?',intro:'Choose where people will use your projects.'},
16
+ {key:'delivery',question:'How much should Kloudy show?',intro:'Quietly is the default. You can ask for updates instead.'}
17
+ ][step]||null;
18
+ }
19
+ export class SamplePreferences{
20
+ constructor(value=preferenceDefaults()){if(!validPreferences(value))throw Error('Invalid preferences');this.value=structuredClone(value);this.step=0;}
21
+ choose(id){const q=preferenceQuestion(this.step);if(!q||!preferenceChoices[q.key].some(([value])=>value===id))throw Error('Choose one of the offered options.');this.value[q.key]=id;this.step++;return this.value;}
22
+ back(){this.step=Math.max(0,this.step-1);}
23
+ }
24
+ export const cardKinds=['preferences','clarify','tools','attachment','signin','approval','payment','exhaustion','receipt','recovery','analytics','conversion'];
25
+ export function shouldShowCard(kind,preferences=preferenceDefaults(),{paid=false,requested=false}={}){
26
+ if(!cardKinds.includes(kind)||!validPreferences(preferences))return false;
27
+ if(requested||['signin','approval','payment','exhaustion','recovery','clarify','attachment'].includes(kind))return true;
28
+ if(kind==='tools')return preferences.delivery==='all'||(preferences.delivery==='paid'&&paid);
29
+ return false;
30
+ }
31
+ export class SampleQueue{
32
+ constructor(){this.current=null;this.waiting=[];this.seen=new Set();}
33
+ offer(card,preferences,options){if(!card||!cardKinds.includes(card.kind)||typeof card.id!=='string'||card.id.length>160||this.seen.has(card.id)||!shouldShowCard(card.kind,preferences,options))return false;
34
+ this.seen.add(card.id);if(this.seen.size>256)this.seen.delete(this.seen.values().next().value);
35
+ const urgent=['payment','approval','exhaustion','recovery'].includes(card.kind);
36
+ if(!this.current)this.current=card;else if(urgent&&!['payment','approval','exhaustion','recovery'].includes(this.current.kind)){this.waiting.unshift(this.current);this.current=card;}else this.waiting.push(card);
37
+ this.waiting=this.waiting.slice(0,10);return true;
38
+ }
39
+ dismiss(){this.current=this.waiting.shift()||null;return this.current;}
40
+ clear(){this.current=null;this.waiting=[];this.seen.clear();}
41
+ }
42
+ const esc=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
43
+ export function samplePreferencesMarkup(flow,{surface='site',notice=''}={}){
44
+ const q=preferenceQuestion(flow.step,surface),complete=!q;
45
+ return `<section class="sample-card" aria-label="${SAMPLE_TITLE}"><header><span class="sample-orb" aria-hidden="true"></span><span>${SAMPLE_TITLE}</span><small>${complete?'Ready':(flow.step+1)+' / 3'}</small></header><h1 tabindex="-1">${complete?'Your way to build.':esc(q.question)}</h1>${complete?'':`<p>${esc(q.intro)}</p>`}${complete?`<dl>${Object.entries(preferenceChoices).map(([key,options])=>`<dt>${esc({tools:'Tools',target:'Where',delivery:'Updates'}[key])}</dt><dd>${esc(options.find(([id])=>id===flow.value[key])?.[1]||'Ask when needed')}</dd>`).join('')}</dl><button class="sample-primary" data-sample-save>Save preferences</button>`:`<div class="sample-options">${preferenceChoices[q.key].map(([id,label])=>`<button data-sample-choice="${id}" aria-pressed="${flow.value[q.key]===id}">${esc(label)}</button>`).join('')}</div>`}<p class="sample-note">${q?.key==='tools'?'Open source describes the tools; hosting or compute may still cost money.':q?.key==='target'?'Bot Wide Web sites need hosting: your computer, your cloud, or a paid host.':'New costs always need your approval. Ask which tools are connected anytime.'}</p><details><summary>How this works</summary><p>Quietly means fewer updates, not permission to spend. Free tiers ending always prompt a choice. These preferences do not install tools or authorize a connection.</p></details><footer>${flow.step?'<button data-sample-back>Back</button>':''}<button data-sample-later>Not now</button></footer><p role="status" class="sample-status">${esc(notice)}</p></section>`;
46
+ }
47
+ export function conversionCardMarkup(){return `<section class="sample-card"><header>${SAMPLE_TITLE}</header><h1>Let bots reach your site.</h1><p>Publish a BWW card so compatible assistants can fetch the part a user needs.</p><a class="sample-primary" href="https://kloudy.ai/hosting">Choose hosting</a><details><summary>Benefits and costs</summary><p>A converted site can offer structured fragments instead of a full browser visit. Actual compute, water and cost savings depend on measured usage; no fixed savings are promised.</p><p>Bring your PC or cloud, or use a paid host. If your compute goes offline, your site becomes unavailable. Concierge and ad bots are optional paid services.</p></details></section>`;}