allyhub 0.2.0-next.4 → 0.3.0
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-version.js +2 -0
- package/dist/commands/add.js +5 -5
- package/dist/commands/cloud-tools.js +9 -10
- package/dist/commands/dev.js +2 -2
- package/dist/commands/mcp.js +1 -1
- package/dist/commands/model.js +1 -1
- package/dist/commands/orgs.js +2 -2
- package/dist/commands/render.js +1 -1
- package/dist/commands/skills.js +3 -3
- package/dist/commands/voice.js +2 -2
- package/dist/main.js +7 -7
- package/dist/works.js +1 -1
- package/editor-app/view.html +4 -4
- package/editor-web/assets/chevron-left-W6sP7nB1.js +1 -0
- package/editor-web/assets/{chevron-up-B2IfPYC4.js → chevron-up-566GQpAm.js} +1 -1
- package/editor-web/assets/{dist-VsUk3S-a.js → dist-BKDr73BR.js} +4 -4
- package/editor-web/assets/dist-CPCNTYVu.js +8 -0
- package/editor-web/assets/{dist-ChU-0IAY.js → dist-C_NajYp0.js} +1 -1
- package/editor-web/assets/{dist-DCgVauDD.js → dist-mA6NrAKh.js} +34 -34
- package/editor-web/assets/{floating-ui.react-dom-C6Aeuo3L.js → floating-ui.react-dom-BUxFRF6t.js} +1 -1
- package/editor-web/assets/index-CFZhjTQW.js +56 -0
- package/editor-web/assets/index-DgU-lyX6.css +2 -0
- package/editor-web/assets/{react-CSPssXRH.js → react-Ff_buMj8.js} +3 -3
- package/editor-web/assets/{undo-2-D6qCS-P0.js → undo-2-BKFItM3X.js} +1 -1
- package/editor-web/index.html +4 -4
- package/node_modules/@allyhub-next/audio/package.json +1 -1
- package/node_modules/@allyhub-next/browser/package.json +1 -1
- package/node_modules/@allyhub-next/build/dist/scan.js +1 -1
- package/node_modules/@allyhub-next/build/package.json +1 -1
- package/node_modules/@allyhub-next/check/dist/check.js +3 -3
- package/node_modules/@allyhub-next/check/package.json +1 -1
- package/node_modules/@allyhub-next/cloud/dist/call.js +2 -2
- package/node_modules/@allyhub-next/cloud/dist/index.js +1 -1
- package/node_modules/@allyhub-next/cloud/dist/signin.js +2 -2
- package/node_modules/@allyhub-next/cloud/dist/token.js +1 -1
- package/node_modules/@allyhub-next/cloud/dist/voice.js +1 -1
- package/node_modules/@allyhub-next/cloud/package.json +1 -1
- package/node_modules/@allyhub-next/components/package.json +1 -1
- package/node_modules/@allyhub-next/components/r/callout.json +5 -1
- package/node_modules/@allyhub-next/components/r/caption-line.json +5 -1
- package/node_modules/@allyhub-next/components/r/caption-subtitle.json +5 -1
- package/node_modules/@allyhub-next/components/r/caption-word.json +5 -1
- package/node_modules/@allyhub-next/components/r/chart.json +5 -1
- package/node_modules/@allyhub-next/components/r/code-panel.json +5 -1
- package/node_modules/@allyhub-next/components/r/screen-demo.json +5 -1
- package/node_modules/@allyhub-next/dev-server/dist/live.js +1 -1
- package/node_modules/@allyhub-next/dev-server/dist/tools.js +1 -1
- package/node_modules/@allyhub-next/dev-server/package.json +1 -1
- package/node_modules/@allyhub-next/doc/package.json +1 -1
- package/node_modules/@allyhub-next/export/dist/export.d.ts +5 -2
- package/node_modules/@allyhub-next/export/dist/export.js +2 -2
- package/node_modules/@allyhub-next/export/package.json +1 -1
- package/node_modules/@allyhub-next/formats/dist/items.d.ts +5 -0
- package/node_modules/@allyhub-next/formats/dist/items.js +1 -1
- package/node_modules/@allyhub-next/formats/dist/layout.d.ts +2 -0
- package/node_modules/@allyhub-next/formats/dist/layout.js +1 -1
- package/node_modules/@allyhub-next/formats/package.json +1 -1
- package/node_modules/@allyhub-next/measure/package.json +1 -1
- package/node_modules/@allyhub-next/media/package.json +1 -1
- package/node_modules/@allyhub-next/model/dist/report.d.ts +1 -1
- package/node_modules/@allyhub-next/model/package.json +1 -1
- package/node_modules/@allyhub-next/project/package.json +1 -1
- package/node_modules/@allyhub-next/protocol/dist/app.d.ts +3 -0
- package/node_modules/@allyhub-next/protocol/dist/auth.d.ts +17 -0
- package/node_modules/@allyhub-next/protocol/dist/auth.js +1 -1
- package/node_modules/@allyhub-next/protocol/dist/cli.d.ts +1 -1
- package/node_modules/@allyhub-next/protocol/dist/cli.js +1 -1
- package/node_modules/@allyhub-next/protocol/dist/cloud.d.ts +23 -168
- package/node_modules/@allyhub-next/protocol/dist/cloud.js +1 -1
- package/node_modules/@allyhub-next/protocol/dist/editor.d.ts +4 -0
- package/node_modules/@allyhub-next/protocol/dist/index.d.ts +1 -0
- package/node_modules/@allyhub-next/protocol/dist/index.js +1 -1
- package/node_modules/@allyhub-next/protocol/dist/registry.d.ts +5 -1
- package/node_modules/@allyhub-next/protocol/dist/registry.js +1 -1
- package/node_modules/@allyhub-next/protocol/dist/routes.d.ts +14 -0
- package/node_modules/@allyhub-next/protocol/dist/routes.js +2 -0
- package/node_modules/@allyhub-next/protocol/dist/teams.d.ts +1 -7
- package/node_modules/@allyhub-next/protocol/dist/teams.js +1 -1
- package/node_modules/@allyhub-next/protocol/dist/tools.d.ts +1 -0
- package/node_modules/@allyhub-next/protocol/package.json +1 -1
- package/node_modules/@allyhub-next/registry/package.json +1 -1
- package/node_modules/@allyhub-next/render/package.json +1 -1
- package/node_modules/@allyhub-next/runtime/dist/page.js +1 -1
- package/node_modules/@allyhub-next/runtime/package.json +1 -1
- package/node_modules/@allyhub-next/runtimes/package.json +1 -1
- package/node_modules/@allyhub-next/scaffold/dist/index.js +5 -5
- package/node_modules/@allyhub-next/scaffold/package.json +1 -1
- package/node_modules/@allyhub-next/scenery/package.json +1 -1
- package/node_modules/@allyhub-next/scenery-host/dist/bundle.d.ts +1 -0
- package/node_modules/@allyhub-next/scenery-host/dist/bundle.js +3 -3
- package/node_modules/@allyhub-next/scenery-host/dist/model-stage.d.ts +32 -0
- package/node_modules/@allyhub-next/scenery-host/dist/model-stage.js +3 -0
- package/node_modules/@allyhub-next/scenery-host/package.json +1 -1
- package/node_modules/@allyhub-next/sheet/package.json +1 -1
- package/node_modules/@allyhub-next/site/package.json +1 -1
- package/node_modules/@allyhub-next/stage/package.json +1 -1
- package/node_modules/@allyhub-next/video-core/dist/problem.d.ts +4 -0
- package/node_modules/@allyhub-next/video-core/dist/problem.js +1 -1
- package/node_modules/@allyhub-next/video-core/package.json +1 -1
- package/package.json +28 -28
- package/dist/charge.js +0 -2
- package/editor-web/assets/chevron-left-B1KTa28S.js +0 -1
- package/editor-web/assets/dist-CuyNR3bn.js +0 -8
- package/editor-web/assets/index-BoYpZLq7.js +0 -56
- package/editor-web/assets/index-DRbemuuR.css +0 -2
- package/node_modules/@allyhub-next/cloud/dist/price.js +0 -2
package/dist/commands/add.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{readFile as
|
|
3
|
-
found in ${e.matchedIn.join(", ")||"everything"}; tags ${e.tags.join(", ")}`}async function
|
|
4
|
-
`)}}const o=await
|
|
5
|
-
`)}}catch(
|
|
6
|
-
`)}}catch(
|
|
2
|
+
import{readFile as Y}from"node:fs/promises";import{join as A,posix as B,relative as V}from"node:path";import{fileURLToPath as W}from"node:url";import{z as h}from"zod";import{modelInfo as q}from"@allyhub-next/build";import{COMPONENTS_DIR as I}from"@allyhub-next/formats";import{EXIT as f}from"@allyhub-next/protocol";import{ASSET_DEFAULTS as G,ASSET_TYPES as K,PolyHaven as X,PolyHavenError as Z,RegistryError as J,applyAdd as T,fetchBakes as Q,folderRegistry as D,planAdd as L,searchIndex as O}from"@allyhub-next/registry";import{cacheHome as ee}from"@allyhub-next/runtimes";import{CLI_VERSION as te}from"../cli-version.js";import{CommandError as j,defineCommand as C}from"../command.js";import{projectRoot as ne}from"../project.js";import{dir as oe}from"../fields.js";import{resourcesIndex as P}from"../resources.js";const _=W(new URL(".",import.meta.resolve("@allyhub-next/components/registry.json"))),se=Object.keys(K),x=["component","3d-model","scenery","skill","template","lib","@polyhaven"],ae={"allyhub:component":"component","allyhub:model":"3d-model","allyhub:scenery":"scenery","allyhub:skill":"skill","allyhub:template":"template","allyhub:lib":"lib"},H=e=>ae[e]??e.replace(/^allyhub:/u,""),E=e=>`${H(e.type)}/${e.name}`;function ie(e){const n=/^(@?[a-z0-9-]+)\/(.+)$/u.exec(e),a=x.find(d=>d===n?.[1]);if(a===void 0||n?.[2]===void 0)throw new j("usage",n===null?`Name what to add as <type>/<name>: ${e} has no type.`:`${n[1]??""} is not a type: name what to add as <type>/<name>.`,{exit:f.usage,hint:`Types: ${x.join(", ")} (3d-model/monitor, scenery/home-desk-day, skill/product-demos, component/caption-line, @polyhaven/<id>). allyhub add lists every one.`});return{type:a,name:n[2]}}const le={"allyhub:model":"3D models","allyhub:scenery":"3D sceneries","allyhub:skill":"Skills","allyhub:template":"Templates","allyhub:component":"Components","allyhub:lib":"Libs (added with what uses them)"};function F(e,n){if(e.from==="none")return["AllyHub's resources (models, sceneries) could not be read: check the connection."];const a=n??e.index?.items??[],d=Math.max(0,...a.map(o=>E(o).length)),r=[`AllyHub's resources (allyhub add <type>/<name> copies one with what it needs, its Poly Haven assets and its baked light)${e.from==="stale"?", as last read (the registry cannot be read now)":""}:`];for(const[o,p]of Object.entries(le)){const c=a.filter(u=>u.type===o);c.length!==0&&r.push(` ${p}:`,...c.map(u=>` ${E(u).padEnd(d)} ${u.description}`))}return r}const N=20,z=e=>e.replace(/\.(?:ts|js)$/u,"").replaceAll(/[A-Z]/gu,n=>`-${n.toLowerCase()}`).replace(/^-/u,"");function M(e){return e instanceof J?new j(e.code,e.message,{exit:e.code==="conflict"?f.conflict:e.code==="no-item"?f.notFound:f.failed,...e.hint===void 0?{}:{hint:e.hint}}):e instanceof Z?new j(e.code,e.message,{exit:e.code==="network"?f.platform:e.code==="not-found"?f.notFound:e.code==="bad-choice"?f.usage:f.failed,...e.hint===void 0?{}:{hint:e.hint}}):e}const R=e=>new X({userAgent:`AllyHub/${te} (+https://allyhub.com)`,cacheDir:A(ee(e.env),"polyhaven"),...e.env.ALLYHUB_POLYHAVEN_API?{api:e.env.ALLYHUB_POLYHAVEN_API}:{}}),k=e=>`${e.toFixed(3)} m`;function de(e){const n=[e.type,e.category,e.size?`${k(e.size.width)} wide, ${k(e.size.depth)} deep, ${k(e.size.height)} tall`:void 0,e.covers?`one tile covers ${e.covers.map(k).join(" × ")}`:void 0,e.polycount!==void 0?`${e.polycount.toLocaleString("en")} polygons`:void 0,e.maxResolution?`up to ${String(e.maxResolution[0])} px`:void 0,e.authors.length>0?`by ${e.authors.join(", ")}`:void 0].filter(a=>a!==void 0);return` @polyhaven/${e.id}: ${e.name} (${n.join("; ")})
|
|
3
|
+
found in ${e.matchedIn.join(", ")||"everything"}; tags ${e.tags.join(", ")}`}async function U(e,n){const a=[`${n.name} from Poly Haven (CC0, by ${n.source.authors.join(", ")||"its authors"}): ${String(n.files.length)} files in ${n.dir}/, ${n.fetched>0?`${String(n.fetched)} fetched`:"all already there"}. Records: ${n.records.join(", ")}.`];if(n.type==="model"){const r=n.main[0]??"",o=await q(e,r,await Y(A(e,r))),p=o.bounds;return a.push(p?`Measured: ${p.size.map(c=>c.toFixed(3)).join(" × ")} m along x, y (up), z; from ${p.min.map(c=>c.toFixed(3)).join(", ")} to ${p.max.map(c=>c.toFixed(3)).join(", ")}.`:`Not measured: ${o.contentsMissing??"no contents"}.`,...o.missing.length>0?[`Missing: ${o.missing.join(", ")}.`]:[],`In a scenery: const m = await w.load("${r}");`),{lines:a,model:o}}if(n.type==="hdri")return a.push(`In a scenery: await w.environment("${n.main[0]??""}", { background: true });`),{lines:a};const d=n.covers;return a.push(d&&d.length>=2?`One tile covers ${k(d[0]??0)} × ${k(d[1]??0)} (Poly Haven's dimensions): a surface's repeat is its size over that.`:"Poly Haven gives no size for one tile.",...n.main.map((r,o)=>{const p=n.maps?.[o]??"";return` ${p}: await w.texture("${r}"${p==="diffuse"?"":', { colorSpace: "linear" }'})`})),{lines:a}}export const add=C({name:"add",summary:"Adds to the project what AllyHub and Poly Haven have, each named <type>/<name>: a starter component, a 3D model, a 3D scenery, a skill or a template from AllyHub's registry, or a CC0 model, HDRI or texture from Poly Haven; alone it lists everything AllyHub has, by type",input:h.strictObject({name:h.array(h.string()).optional().describe("What to add, each <type>/<name>: component/caption-line, 3d-model/monitor, scenery/home-desk-demo-day, skill/product-demos (a skill goes in .agents/skills, linked from .claude/skills), template/<name>, lib/<name>, or @polyhaven/<id> (as allyhub add search prints it)"),to:h.string().optional().describe(`The folder the files go in, from the project (default ${I} for a component; for an asset, its kind's folder under assets/media/ and its id)`),force:h.boolean().default(!1).describe("Replace a component's copy the project changed (its changes are lost)"),res:h.string().optional().describe(`An asset's resolution, of its textures or of the HDRI (default ${G.resolution})`),dir:oe}),positional:["name"],output:h.looseObject({}),examples:["allyhub add","allyhub add component/caption-line","allyhub add 3d-model/monitor scenery/home-desk-day","allyhub add @polyhaven/metal_office_desk --res 2k"]},async(e,n)=>{const a=D(_);try{const d=await a.index();if(!e.name||e.name.length===0){const t=Math.max(...d.items.map(y=>`component/${y.name}`.length)),l=await P(n);return{value:{components:d.items,resources:l.index?.items??[]},text:["Starter components (allyhub add component/<name> copies one into components/; allyhub add search <words> finds among everything, Poly Haven's models, HDRIs and textures too):",...d.items.map(y=>` ${`component/${y.name}`.padEnd(t)} ${y.description}`),"",...F(l,void 0)].join(`
|
|
4
|
+
`)}}const r=e.name.map(ie),o=await ne(n.cwd,e.dir),p=new Set(d.items.map(t=>t.name)),c=t=>t.type==="component"&&p.has(z(t.name)),u=r.filter(c).map(t=>z(t.name)),v=r.filter(t=>t.type==="@polyhaven").map(t=>t.name),g=r.filter(t=>t.type!=="@polyhaven"&&!c(t)),b=g.length>0?await P(n):void 0;for(const t of g){const l=b?.index?.items.find(y=>y.name===t.name);if(!l)throw new j("no-item",`There is no ${t.type}/${t.name}.`,{exit:f.notFound,hint:b?.from==="none"?"AllyHub's registry could not be read: check the connection.":`allyhub add search --type ${t.type} lists them.`});if(H(l.type)!==t.type)throw new j("usage",`${t.name} is a ${H(l.type)}, not a ${t.type}.`,{exit:f.usage,hint:`allyhub add ${E(l)}`})}const w=g.map(t=>t.name),i=[],S={};if(u.length>0){const t=e.to??I,l=await L(a,u,{root:o,dir:t,force:e.force});await T(o,l);const y=m=>m==="up to date"?"Up to date":m==="added"?"Added":"Replaced";i.push(...l.files.map(m=>`${y(m.status)} ${m.path}`));const s=l.items.find(m=>m.name===u[0]),$=s?.files[0]?.target.replaceAll("{dir}",t);if(s&&$){const m=V(A(o,"name"),A(o,$)).split("\\").join("/").replace(/\.ts$/u,".js");i.push(`Import it from an item's entry file (<name>/video.ts): import { ${s.title} } from "${m.startsWith(".")?m:`./${m}`}"; one "../" more for each folder the item is deeper.`,"The file is the project's: change it as you like. allyhub add component/<name> --force puts the registry's back.")}l.missing.length>0&&i.push(`It needs packages the project does not declare: ${l.missing.join(", ")}.`),S.components=l.files.map(m=>({item:m.item,path:m.path,status:m.status})),S.missing=l.missing}if(b&&w.length>0){const t=await L(b.source,w,{root:o,dir:".",force:e.force});await T(o,t),i.length>0&&i.push(""),i.push(...t.files.map(s=>`${s.status==="up to date"?"Up to date":s.status==="added"?"Added":"Replaced"} ${s.path}`));const l=R(n);for(const s of t.assets){const $=await l.add(s.id,{root:o,...s.resolution===void 0?{}:{resolution:s.resolution},...s.maps===void 0?{}:{maps:s.maps}});i.push(...(await U(o,$)).lines)}const y=await Q(o,t.bakes);i.push(...y.map(s=>`${s.status==="added"?"Downloaded":"Up to date"} the baked light for ${s.bake.scenery}: ${s.path}`),"The files are the project's: change them as you like (a changed scenery is drawn unbaked until allyhub scenery bake bakes it again). allyhub add <type>/<name> --force puts the registry's back."),S.resources={files:t.files.map(s=>({item:s.item,path:s.path,status:s.status})),assets:t.assets,bakes:y.map(s=>({path:s.path,status:s.status}))}}if(v.length>0){const t=R(n),l=[];for(const y of v){const s=await t.add(y,{root:o,...e.to===void 0||u.length>0?{}:{to:B.normalize(e.to)},...e.res===void 0?{}:{resolution:e.res}}),$=await U(o,s);i.length>0&&i.push(""),i.push(...$.lines),l.push({...s,...$.model===void 0?{}:{model:$.model}})}S.assets=l}return{value:S,text:i.join(`
|
|
5
|
+
`)}}catch(d){throw M(d)}}),addSearch=C({name:"add search",summary:"Finds the starter components, AllyHub's resources (models, sceneries) and Poly Haven's CC0 models, HDRIs and textures whose names, tags, categories or descriptions hold every word, each with where its words were found; with no words, lists every one",input:h.strictObject({words:h.array(h.string()).default([]).describe("The words to find (a word may start one of theirs); none lists every one"),type:h.array(h.enum(x)).optional().describe(`Only these types (default all): ${x.join(", ")} (@polyhaven: Poly Haven's models, HDRIs and textures)`),all:h.boolean().default(!1).describe(`Every match, not only the first ${String(N)} Poly Haven assets`)}),positional:["words"],output:h.looseObject({}),examples:["allyhub add search --type 3d-model",'allyhub add search "office desk" --type @polyhaven',"allyhub add search caption --type component"]},async(e,n)=>{const a=e.words.join(" ").trim(),d=a===""?"":` hold "${a}"`;try{const r=e.type??x,o=r.includes("component")?O(await D(_).index(),a):[],p=r.filter(i=>i!=="@polyhaven"),c=p.length>0?await P(n):void 0,u=c?.index?O(c.index,a).filter(i=>p.includes(H(i.type))):[],v=r.includes("@polyhaven")?se:[],{found:g,total:b}=v.length>0?await R(n).search(a,v):{found:[],total:0},w=e.all?g:g.slice(0,N);return{value:{query:a,components:o,resources:u,assets:{total:b,matches:g.length,found:w}},text:[...r.includes("component")?[`Starter components: ${String(o.length)}${d}.`,...o.map(i=>` component/${i.name} (${i.title}): ${i.description}`)]:[],...c?c.from==="none"?F(c,[]):[`AllyHub's resources: ${String(u.length)}${d}${c.from==="stale"?" (as last read)":""}.`,...u.map(i=>` ${E(i)} (${i.title}): ${i.description}`)]:[],...v.length>0?[`From Poly Haven (CC0): ${String(g.length)} of ${String(b)} assets${d}${w.length<g.length?`; the first ${String(w.length)} (--all for every one)`:""}.`,...w.map(de)]:[],"","Add one: allyhub add <type>/<name>"].join(`
|
|
6
|
+
`)}}catch(r){throw M(r)}});
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{readFile as
|
|
3
|
-
`)}}))}
|
|
4
|
-
`);if(
|
|
5
|
-
`);const
|
|
6
|
-
`),...
|
|
7
|
-
`)}const
|
|
8
|
-
`)}}const N=Q(n,m);if(N.length>0)throw k(`${e.name} needs ${N.join(", ")}.`,`allyhub help ${t} shows its options.`);const x=l.approve,T=await B(v,e.name,m,{...q,...x===void 0?{}:{approve:()=>{const c=F(e.price,e.input,[m]).calls[0];return c===void 0?Promise.resolve(!0):x(z(t,e.title,c))}},outDir:U(S,G,e.work,e.name),...u.file===void 0?{}:{file:R(l.cwd,u.file)},force:u.force,wait:u.wait});return{value:{...T},text:J(T,t)}})}}const re=e=>h(p(e)).catch(()=>{});export const CLOUD_SOURCE={entries:[{name:"<work>",summary:"List a work's cloud tools (AllyHub's catalog), a line each with its price; allyhub help lists the works"},{name:"<work> <tool>",summary:"Run a cloud tool with the account's credits, its input as options (allyhub help <work> <tool>); --quote prices it first"}],async nouns(e){return(await h(p(e))).works.map(n=>({name:n.id,summary:`${n.title}: ${n.description}`}))},resolve:(e,t)=>f(async()=>{const[n,r]=e;if(n===void 0||n.startsWith("-"))return;let s=await re(t),i=s?.works.find(l=>l.id===n);if(i||(s=await h(p(t),{refresh:!0}).catch(()=>s),i=s?.works.find(l=>l.id===n)),!s||!i)return;if(r===void 0||r.startsWith("-"))return{command:W(i),rest:e.slice(1),list:!0};const o=s.tools.find(l=>l.name===r);if(o?.work!==i.id)throw new b("unknown-tool",o?`${r} is not a ${i.id} tool: it is in allyhub ${o.work}.`:`No ${i.id} tool ${r}.`,{exit:$.notFound,hint:o?`allyhub ${o.work} ${r}`:`allyhub ${i.id} lists its tools.`});return{command:toolCommand(o),rest:e.slice(2),list:!1}})},upload=w({name:"upload",summary:"Upload files from this computer for a cloud tool whose input takes a URL (a presenter photo, speech audio, a reference clip), and print a signed URL for each, which works for a few hours",input:a.strictObject({files:a.array(a.string()).min(1).describe("The files: images (.jpg, .png, .webp, .gif), sound (.mp3, .wav, .m4a, .aac, .ogg, .flac) or video (.mp4, .mov, .webm), 50 MB at most")}),positional:["files"],output:a.looseObject({files:a.array(a.looseObject({file:a.string(),ok:a.boolean(),url:a.string().optional()}))}),examples:["allyhub upload assets/media/presenter.jpg"]},(e,t)=>f(async()=>{const n=await _(p(t),e.files,{base:t.cwd}),r=n.filter(o=>!o.ok),s=n.map(o=>o.ok?`${o.file}
|
|
2
|
+
import{readFile as I}from"node:fs/promises";import{join as D,resolve as x}from"node:path";import{z as n}from"zod";import{callTool as F,findTool as N,loadCatalog as p,resumeJob as L,uploadFiles as M}from"@allyhub-next/cloud";import{WORK_DIR as E}from"@allyhub-next/formats";import{EXIT as h}from"@allyhub-next/protocol";import{CommandError as w,defineCommand as m}from"../command.js";import{optionName as H}from"../args.js";import{commandHelp as U}from"../help.js";import{requiredMissing as B,toolInput as K,toolOptions as _}from"../tool-options.js";import{cloudOf as u,cloudWork as f,placeFrom as q,plural as g}from"./cloud.js";const G=8e3,c={input:n.string().optional().describe("The input as JSON, or a file of it: the whole of it, or the fields no option gives; an option given beside it wins"),file:n.string().optional().describe("The path of the file it makes (without an extension it takes the result's); the same call with the same input then keeps it, calling nothing, and while its call works waits for that call; default a folder under .allyhub/work/"),force:n.boolean().default(!1).describe("With --file: call even when the file was made from this input, and replace a file that has no record"),wait:n.boolean().default(!0).describe("Wait for a long tool (an audit, a video model); --no-wait returns its call at once"),resume:n.string().optional().describe("Wait for a call of this tool this computer made (from --no-wait, or a call that stopped waiting), and download its file")},$=(t,a)=>new w("usage",t,{exit:h.usage,...a===void 0?{}:{hint:a}}),R=t=>{const a=t.reduce((e,r)=>r.map((s,i)=>Math.max(e[i]??0,s.length)),[]);return t.map(e=>` ${e.map((r,s)=>s===e.length-1?r:r.padEnd(a[s]??0)).join(" ")}`.trimEnd())};function T(t){return m({name:t.id,summary:`${t.title}: ${t.description} Lists the tools, each a command`,input:n.strictObject({fresh:n.boolean().default(!1).describe("Read the catalog from AllyHub again, not the copy kept an hour")}),output:n.looseObject({work:n.string(),tools:n.array(n.looseObject({name:n.string()}))}),examples:[`allyhub ${t.id}`,`allyhub ${t.id} --json`]},(a,e)=>f(async()=>{const s=(await p(u(e),{refresh:a.fresh})).tools.filter(i=>i.work===t.id).sort((i,o)=>i.name.localeCompare(o.name));return{value:{work:t.id,title:t.title,tools:s.map(i=>({name:i.name,title:i.title,description:i.description,long:i.long}))},text:[`${t.title} (${g(s.length,"tool")}):`,...R(s.map(i=>[i.name,i.title])),"",`Each costs credits when it worked; a failed call is free. allyhub help ${t.id} <tool> shows a tool's options and how its credits are counted.`].join(`
|
|
3
|
+
`)}}))}function z(t,a=5,e=160){const r=i=>{const o=i===void 0?"undefined":JSON.stringify(i);return o.length>e?`${o.slice(0,e-1)}…`:o},s=(i,o)=>[`${i?`${i}: `:""}${g(o.length,"item")}${o.length>a?`, the first ${String(a)}:`:":"}`,...o.slice(0,a).map((l,b)=>` [${String(b)}] ${r(l)}`)];return Array.isArray(t)?s("",t):typeof t!="object"||t===null?[r(t)]:Object.entries(t).flatMap(([i,o])=>Array.isArray(o)?s(i,o):[`${i}: ${r(o)}`])}function W(t,a){if("jobId"in t)return[`${t.tool} is still working (call ${t.jobId}).`,`Wait for it: allyhub ${a} --resume ${t.jobId}${t.file===void 0?"":" (or the same command again: it waits for this call)"}`].join(`
|
|
4
|
+
`);if(t.kept)return[`Kept ${t.file??""}: ${t.tool} made it from this same input on ${t.kept.at} (${t.gen??""}).`,"Nothing was called or charged. --force makes it again."].join(`
|
|
5
|
+
`);const e=JSON.stringify(t.output,null,2);return[e.length<=G?e:[`Output: ${String(Math.round(Buffer.byteLength(e)/1024))} KB of JSON, in short (--json prints it whole):`,...z(t.output)].join(`
|
|
6
|
+
`),...t.file?[`File: ${t.file}${t.replaced?" (replaced: it was made from another input)":""}`]:[],...t.words?[`Words: ${t.words} (when each word is said: a part can say a stretch of the file)`]:[],...t.gen?[`Record: ${t.gen} (move it with the file)`]:[],`Credits used: ${t.credits===void 0?"not reported":String(t.credits)}`].join(`
|
|
7
|
+
`)}const P=t=>{const a=Math.max(0,Math.round(t));return`${String(Math.floor(a/60))}:${String(a%60).padStart(2,"0")}`},X=t=>t!==null&&typeof t=="object"&&!Array.isArray(t);async function Q(t,a){const e=t.trim().startsWith("{"),r=e?t:await I(x(a.cwd,t),"utf8").catch(i=>{throw new w("not-found",`--input: cannot read ${t}: ${i.message}`,{exit:h.notFound,hint:"Give a JSON object, or a file of one."})});let s;try{s=JSON.parse(r)}catch{s=void 0}if(!X(s))throw $(`--input: ${e?"the text":t} is not a JSON object.`,`Give '{"field": …}', or a file of it.`);return s}export function toolCommand(t){const a=`${t.work} ${t.name}`,e=_(t.input,Object.keys(c)),r=n.strictObject({...e.shape,...c,input:c.input.describe(e.inputOnly.length?`${c.input.description??""}. Fields only it gives: ${e.inputOnly.join(", ")}`:c.input.description??"")}),s=[...e.fields].filter(([,i])=>e.required.includes(i)).map(([i,o])=>`--${H(i)} <${o}>`);return{spec:{name:a,summary:t.description,input:r,output:n.looseObject({tool:n.string(),output:n.record(n.string(),n.unknown()).optional(),credits:n.number().optional(),file:n.string().optional(),gen:n.string().optional(),words:n.string().optional(),jobId:n.string().optional()}),examples:[`allyhub ${[a,...s].join(" ")}`]},about:{lines:[t.title,"","A call is charged once, when it worked, as the description says; a failed call is free.",...t.long?["A long tool: the command waits for it (--no-wait returns its call, --resume waits again)."]:[]],value:{work:t.work,title:t.title,long:t.long,inputSchema:t.input,outputSchema:t.output}},run:(i,o)=>f(async()=>{const l=i,b=i,k=u(o),j=await q(o),y=K(e,b,l.input===void 0?{}:await Q(l.input,o));let O=0;const S={base:j,signal:o.signal,onRunning:d=>{Date.now()-O<3e4||(O=Date.now(),o.progress(`${t.name}: working · ${P((Date.now()-Date.parse(d.createdAt))/1e3)} (call ${d.id})`))},onRetry:(d,C,J)=>{o.progress(`${t.name}: ${C.message}; reading call ${d} again in ${String(J)} s`)}};if(l.resume!==void 0){if(Object.keys(y).length>0||l.file!==void 0)throw $("--resume waits for a call as it was made: give it no input or --file.");const d=await L(k,l.resume,{...S,tool:t.name});return{value:{...d},text:W(d,a)}}const v=B(e,y);if(v.length>0)throw $(`${t.name} needs ${v.join(", ")}.`,`allyhub help ${a} shows its options.`);const A=await F(k,t.name,y,{...S,outDir:D(j,E,t.work,t.name),...l.file===void 0?{}:{file:x(o.cwd,l.file)},force:l.force,wait:l.wait});return{value:{...A},text:W(A,a)}})}}const V=t=>p(u(t)).catch(()=>{});export const CLOUD_SOURCE={entries:[{name:"<work>",summary:"List a work's cloud tools (AllyHub's catalog), a line each; allyhub help lists the works"},{name:"<work> <tool>",summary:"Run a cloud tool with the account's credits, its input as options (allyhub help <work> <tool>, which says how its credits are counted)"}],async nouns(t){return(await p(u(t))).works.map(e=>({name:e.id,summary:`${e.title}: ${e.description}`}))},resolve:(t,a)=>f(async()=>{const[e,r]=t;if(e===void 0||e.startsWith("-"))return;let s=await V(a),i=s?.works.find(l=>l.id===e);if(i||(s=await p(u(a),{refresh:!0}).catch(()=>s),i=s?.works.find(l=>l.id===e)),!s||!i)return;if(r===void 0||r.startsWith("-"))return{command:T(i),rest:t.slice(1),list:!0};const o=s.tools.find(l=>l.name===r);if(o?.work!==i.id)throw new w("unknown-tool",o?`${r} is not a ${i.id} tool: it is in allyhub ${o.work}.`:`No ${i.id} tool ${r}.`,{exit:h.notFound,hint:o?`allyhub ${o.work} ${r}`:`allyhub ${i.id} lists its tools.`});return{command:toolCommand(o),rest:t.slice(2),list:!1}})},upload=m({name:"upload",summary:"Upload files from this computer for a cloud tool whose input takes a URL (a presenter photo, speech audio, a reference clip), and print a signed URL for each, which works for a few hours",input:n.strictObject({files:n.array(n.string()).min(1).describe("The files: images (.jpg, .png, .webp, .gif), sound (.mp3, .wav, .m4a, .aac, .ogg, .flac) or video (.mp4, .mov, .webm), 50 MB at most")}),positional:["files"],output:n.looseObject({files:n.array(n.looseObject({file:n.string(),ok:n.boolean(),url:n.string().optional()}))}),examples:["allyhub upload assets/media/presenter.jpg"]},(t,a)=>f(async()=>{const e=await M(u(a),t.files,{base:a.cwd}),r=e.filter(o=>!o.ok),s=e.map(o=>o.ok?`${o.file}
|
|
9
8
|
${o.url}${o.expiresAt===void 0?"":` (works until ${o.expiresAt})`}`:`${o.file}
|
|
10
|
-
failed: ${o.error.message}${o.error.hint?` ${o.error.hint}`:""}`);
|
|
11
|
-
`),...i?{exit:i.error.exit}:{}}})),cloudList=
|
|
12
|
-
`)};const r=
|
|
9
|
+
failed: ${o.error.message}${o.error.hint?` ${o.error.hint}`:""}`);e.length>1&&s.push(r.length===0?`${g(e.length,"file")} uploaded.`:`${String(e.length-r.length)} of ${g(e.length,"file")} uploaded; ${String(r.length)} failed.`);const i=r[0];return{value:{files:e.map(o=>o.ok?{...o}:{file:o.file,ok:!1,error:{code:o.error.code,message:o.error.message,...o.error.hint?{hint:o.error.hint}:{}}})},text:s.join(`
|
|
10
|
+
`),...i?{exit:i.error.exit}:{}}})),cloudList=m({name:"cloud list",summary:"List AllyHub's cloud works, or one work's tools, a line each",input:n.strictObject({work:n.string().optional().describe("The work whose tools to list; none lists the works")}),output:n.looseObject({})},(t,a)=>f(async()=>{const e=await p(u(a));if(t.work===void 0)return{value:{works:e.works},text:["AllyHub's cloud works:",...R(e.works.map(i=>[i.id,i.description]))].join(`
|
|
11
|
+
`)};const r=e.works.find(i=>i.id===t.work);if(!r)throw new w("unknown-work",`No work ${t.work}.`,{exit:h.notFound,hint:`The works are ${e.works.map(i=>i.id).join(", ")}.`});const s=await T(r).run({fresh:!1},a);return{value:s.value,text:s.text}})),cloudTool=m({name:"cloud tool",summary:"Show a cloud tool: what it does and how its credits are counted, and its input (as cloud call's input takes it)",input:n.strictObject({tool:n.string().describe("The tool's name, as cloud list lists it")}),output:n.looseObject({name:n.string()})},(t,a)=>f(async()=>{const e=toolCommand(await N(u(a),t.tool));return{value:{name:t.tool,summary:e.spec.summary,about:e.about?.lines??[],...e.about?.value},text:U(e.spec,e.about?.lines)}})),cloudCall=m({name:"cloud call",summary:"Run a cloud tool with the account's credits: its output, the credits used, and the file it makes with its record; waits for a long one",input:n.strictObject({tool:n.string().describe("The tool's name, as cloud list lists it"),input:n.record(n.string(),n.unknown()).default({}).describe("Its input, by its input schema (cloud tool)"),file:c.file,force:c.force,wait:c.wait,resume:c.resume}),output:n.looseObject({tool:n.string()})},(t,a)=>f(async()=>{const{tool:e,input:r,...s}=t,i=toolCommand(await N(u(a),e)),o=i.spec.input.safeParse({...s,...Object.keys(r).length?{input:JSON.stringify(r)}:{}});if(!o.success)throw $(o.error.message);const l=await i.run(o.data,a);return{...l,value:{tool:e,...l.value}}}));
|
package/dist/commands/dev.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{
|
|
3
|
-
Press Ctrl+C to stop.`),r.open&&
|
|
2
|
+
import{mkdir as y,readFile as f,rm as b,writeFile as S}from"node:fs/promises";import{dirname as m,join as p}from"node:path";import{fileURLToPath as E}from"node:url";import{z as a}from"zod";import{listFiles as R}from"@allyhub-next/build";import{openBrowser as h}from"@allyhub-next/cloud";import{startDevServer as u}from"@allyhub-next/dev-server";import{DEV_FILE as w,scanItems as T}from"@allyhub-next/formats";import{EXIT as I}from"@allyhub-next/protocol";import{CommandError as g,defineCommand as $}from"../command.js";import{dir as O,indexing as D}from"../fields.js";import{projectRoot as P}from"../project.js";export const PAGE=p(m(E(import.meta.url)),"../../editor-web");const l=4340,j=20;export async function start(r,e,n){const s={root:r,ui:PAGE,index:n};if(e!==void 0)return u({...s,port:e}).catch(t=>{throw t.code==="EADDRINUSE"?new g("port-in-use",`Port ${String(e)} is in use.`,{hint:"Choose another with --port, or leave it out."}):t});for(let t=l;t<l+j;t++)try{return await u({...s,port:t})}catch(o){if(o.code!=="EADDRINUSE")throw o}return u(s)}async function F(r){try{const e=JSON.parse(await f(p(r,w),"utf8"));return typeof e.url!="string"||typeof e.pid!="number"?void 0:(process.kill(e.pid,0),(await fetch(e.url,{signal:AbortSignal.timeout(2e3)})).ok?e.url:void 0)}catch{return}}async function v(r,e,n){if(n===void 0)return e;const{items:s}=T(await R(r)),t=n.replace(/^\.\//u,"").replace(/\/+$/u,""),o=s.find(i=>i.dir===t||i.entry===t);if(!o)throw new g("not-found",`There is no item ${n} in the project.`,{exit:I.notFound,hint:`Its items: ${s.map(i=>i.dir).join(", ")||"none"}.`});return`${e}?${new URLSearchParams({item:o.dir}).toString()}`}export const dev=$({name:"dev",summary:"The project's items in the browser, each in its editor (docs, sheets, videos, 3D sceneries), as their files change; runs until stopped, and run again while it runs, opens its page and ends",input:a.strictObject({item:a.string().optional().describe("Open the page on this item: its folder or its entry file"),dir:O,port:a.number().int().min(1).max(65535).optional().describe(`The port; default the first free one from ${String(l)}`),open:a.boolean().default(!0).describe("Open the page in the browser; --no-open only prints it")}),positional:["item"],output:a.strictObject({url:a.string()}),mcp:!1,examples:["allyhub dev","allyhub dev launch/plan","allyhub dev --port 4400 --no-open"]},async(r,e)=>{const n=await P(e.cwd,r.dir),s=r.port===void 0?await F(n):void 0;if(s!==void 0){const i=await v(n,s,r.item);return e.progress(`allyhub dev is already running at ${i}`),r.open&&h(i,e.env),{value:{url:i},text:""}}const t=await start(n,r.port,D(e.env)),o=p(n,w);try{const i=await v(n,t.url,r.item);return await y(m(o),{recursive:!0}),await S(o,JSON.stringify({url:t.url,pid:process.pid})),e.progress(`allyhub dev is at ${i}
|
|
3
|
+
Press Ctrl+C to stop.`),r.open&&h(i,e.env),await new Promise(c=>{const d=()=>{process.off("SIGTERM",d),e.signal.removeEventListener("abort",d),c()};e.signal.aborted&&c(),e.signal.addEventListener("abort",d),process.once("SIGTERM",d)}),{value:{url:i},text:""}}finally{(await f(o,"utf8").catch(()=>"")).includes(`"pid":${String(process.pid)}`)&&await b(o,{force:!0}),await t.close()}});
|
package/dist/commands/mcp.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{McpServer as
|
|
2
|
+
import{McpServer as y}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as b}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as S,ListResourcesRequestSchema as g,ListToolsRequestSchema as k,ReadResourceRequestSchema as v}from"@modelcontextprotocol/sdk/types.js";import{z as f}from"zod";import{describeCommand as R,toolName as d}from"@allyhub-next/protocol";import{CommandError as m,defineCommand as C}from"../command.js";import{CLI_VERSION as j}from"../cli-version.js";import{CardApp as M}from"./mcp-app.js";import{docResources as O,readDoc as A}from"./mcp-docs.js";export const MCP_INSTRUCTIONS=["AllyHub makes videos, decks, docs, sheets and 3D sceneries as code in a project folder, checks, previews and renders them on this computer, and runs AI models and research tools in its cloud, which cost the person's credits.","Each tool here is one of its commands: `allyhub help` on the command line (`npx -y allyhub help`) is their reference and says where the SDK's docs are.",`\`allyhub skills\` (${d("skills")}) lists AllyHub's work skills, each how to make one kind of work; \`allyhub skills show <name>\` (${d("skills show")}) prints one, and \`allyhub add skill/<name>\` puts it in the project.`].join(" ");async function N(i,t,u){const c=(e,o=!1)=>({content:[{type:"text",text:JSON.stringify(e,null,2)}],...o?{isError:o}:{}}),a=i.spec.input.safeParse(t??{});if(!a.success){const e=a.error.issues[0];return c({error:{code:"usage",message:`${e?.path.join(".")??i.spec.name}: ${e?.message??"not valid"}.`}},!0)}try{const e=await i.run(a.data,u);return c(e.value)}catch(e){const o=e instanceof m?e:new m("failed",e instanceof Error?e.message:String(e));return c({error:{code:o.code,message:o.message,...o.hint===void 0?{}:{hint:o.hint}}},!0)}}export const mcp=C({name:"mcp",summary:"The commands as MCP tools, over stdio",input:f.strictObject({}),output:f.looseObject({}),examples:["claude mcp add allyhub -- allyhub mcp"],mcp:!1},async(i,t)=>{const{COMMANDS:u,MCP_COMMANDS:c}=await import("./index.js"),a=new Map([...u,...c].filter(s=>s.spec.mcp!==!1).map(s=>[d(s.spec.name),s]));console.log=console.error,console.info=console.error;const e=new y({name:"allyhub",version:j},{capabilities:{tools:{},resources:{}},instructions:MCP_INSTRUCTIONS}),o=new M(t),l=e.server;l.setRequestHandler(k,()=>({tools:[...o.tools(),...[...a].map(([s,r])=>{const n=Object.fromEntries(Object.entries(R(r.spec).input).filter(([p])=>p!=="$schema"));return{name:s,description:r.spec.summary,inputSchema:{type:"object",...n}}})]})),l.setRequestHandler(g,async()=>({resources:[...o.resources(),...await O(t.cwd)]})),l.setRequestHandler(v,async s=>{const{uri:r}=s.params;if(r===o.resources()[0]?.uri)return{contents:[await o.resource()]};const n=await A(t.cwd,r);if(n===void 0)throw new m("not-found",`allyhub has no resource ${r}.`);return{contents:[n]}}),l.setRequestHandler(S,(s,r)=>{if(o.has(s.params.name))return o.call(s.params.arguments);const n=a.get(s.params.name);if(!n)throw new m("unknown-tool",`allyhub has no tool ${s.params.name}.`);const p=AbortSignal.any([t.signal,r.signal]);return N(n,s.params.arguments,{...t,signal:p})});const h=new b,w=new Promise(s=>{h.onclose=s});return await e.connect(h),process.stdin.once("end",()=>{e.close()}),t.signal.addEventListener("abort",()=>{e.close()}),await w,await o.close(),{value:{},text:""}});
|
package/dist/commands/model.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
2
|
import{stat as j}from"node:fs/promises";import{basename as c,dirname as u,join as f,resolve as p}from"node:path";import{z as i}from"zod";import{CACHE_DIR as y,OUT_DIR as h}from"@allyhub-next/formats";import{BUILD_DEFAULTS as x,ModelError as S,buildModule as O,capabilities as b}from"@allyhub-next/model/build";import{EXIT as m}from"@allyhub-next/protocol";import{CommandError as n,defineCommand as g}from"../command.js";import{projectAt as v,projectRoot as w}from"../project.js";import{parameters as A}from"../parameters.js";const $=`${y}/model`,T=t=>t.toFixed(3);function C(t){const r=c(t).replace(/\.[^.]+$/u,"");return r==="model"?c(u(t)):r}function B(t,r){const a=t.objects.filter(e=>e.triangles===0&&!e.curve);return[`${r}: ${String(t.objects.length)} objects, ${String(t.triangles)} triangles (${t.upAxis} up, ${t.units}s).`,...t.objects.map(e=>{const l=e.bounds?e.bounds.max.map((s,d)=>T(s-(e.bounds?.min[d]??0))).join(" × "):void 0,o=e.materials.flatMap(s=>s?[s.name]:[]);return` ${e.name}${e.parent?` (in ${e.parent})`:""}: ${String(e.triangles)} triangles${l?`, ${l} m`:""}${o.length>0?`, ${o.join(", ")}`:""}${e.curve?`, a curve of ${String(e.curve.splines.length)} splines`:""}${e.instance?`, an instance of ${e.instance.object}`:""}`}),...a.length>0?[`No triangles after their modifiers: ${a.map(e=>e.name).join(", ")}.`]:[]].join(`
|
|
3
|
-
`)}export const model=g({name:"model",summary:"Builds a
|
|
3
|
+
`)}export const model=g({name:"3d-model",summary:"Builds a 3D model's TypeScript module (defineModel) into a GLB; --inspect measures it without writing one",input:i.strictObject({file:i.string().describe("The model module, a .ts, .mts, .js or .mjs file whose default export is defineModel(build)"),inspect:i.boolean().default(!1).describe("Measure it without writing a GLB: each object's parent, matrix, bounds (Blender Z-up metres), triangles, materials as glTF reads them, UV layers, a curve's splines"),args:i.string().default("{}").describe("What the module's build is given (defineModel's parameters), a JSON object"),out:i.string().optional().describe(`The GLB to write (default ${h}/<module>.glb, the folder's name for a model.ts); one there is replaced only after the build succeeds`),dir:i.string().optional().describe("The project, where the module's image paths start (default the one the module is in, else the folder it is run in)"),fresh:i.boolean().default(!1).describe(`Build anew instead of reusing the build kept in ${$} (one is reused while the module, the files it read, its parameters, seed and the modelling runtime are unchanged); the new build is kept too`),params:A({seed:i.int().default(x.seed).describe("Seed of the build's random generator (bpy.random, 32 bits)")})}),positional:["file"],output:i.looseObject({}),examples:["allyhub 3d-model table/model.ts",`allyhub 3d-model table/model.ts --inspect --args '{"width":1.8}'`]},async(t,r)=>{const a=p(r.cwd,t.file);if(!(await j(a).catch(()=>{}))?.isFile())throw new n("not-found",`There is no file ${t.file}.`,{exit:m.notFound});if(!/\.(?:ts|mts|js|mjs)$/u.test(a))throw new n("usage","A model module is a .ts, .mts, .js or .mjs file.",{exit:m.usage});let e;try{e=JSON.parse(t.args)}catch{e=void 0}if(typeof e!="object"||e===null||Array.isArray(e))throw new n("usage","--args is a JSON object.",{exit:m.usage});const l=t.dir===void 0?await v(u(a))??await w(r.cwd):await w(r.cwd,t.dir),o=t.inspect?void 0:p(r.cwd,t.out??f(l,h,`${C(a)}.glb`));if(o&&!o.toLowerCase().endsWith(".glb"))throw new n("usage","--out is a .glb file.",{exit:m.usage});try{const s=await O(a,{parameters:e,seed:t.params.seed,root:l,...o?{out:o}:{},cache:f(l,$),fresh:t.fresh}),d=s.cache==="hit"?" (cached)":"";return{value:{...s.report,...s.glb?{glb:s.glb}:{},cache:s.cache},text:B(s.report,s.glb?`Wrote ${s.glb}${d}`:`${t.file}${d}`)}}catch(s){throw s instanceof S?new n(`model-${s.code.toLowerCase().replace(/^model[-_]/u,"").replaceAll(/[^a-z0-9]+/gu,"-")}`,s.message):s}}),modelCapabilities=g({name:"3d-model capabilities",summary:"What the modelling API supports (the Blender subset, its limits and deliberate differences), as JSON",input:i.strictObject({}),output:i.looseObject({}),examples:["allyhub 3d-model capabilities"]},()=>Promise.resolve({value:b,text:JSON.stringify(b,null,2)}));
|
package/dist/commands/orgs.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{z as
|
|
3
|
-
`)}})),orgsSwitch=
|
|
2
|
+
import{z as o}from"zod";import{chooseOrganization as f,organizations as l,readCredentials as p}from"@allyhub-next/cloud";import{API_KEY_ENV as h,EXIT as u}from"@allyhub-next/protocol";import{defineCommand as c}from"../command.js";import{cloudOf as g,cloudWork as d}from"./cloud.js";const y=o.looseObject({id:o.string(),name:o.string(),slug:o.string(),role:o.string(),current:o.boolean()});export const orgsList=c({name:"orgs list",summary:"The organizations you are in, with your role; the one this computer acts in and pays from is marked",input:o.strictObject({}),output:o.looseObject({organizations:o.array(y)})},(r,a)=>d(async()=>{const e=g(a),s=await l(e),i=(await p(e.config))?.account.organization?.id,n=s.filter(t=>t.dissolvedAt===null).map((t,m)=>({id:t.id,name:t.name,slug:t.slug,role:t.role,current:i===void 0?m===0:t.id===i}));return{value:{organizations:n},text:n.map(t=>`${t.current?"*":" "} ${t.slug} ${t.name} ${t.role}`).join(`
|
|
3
|
+
`)}})),orgsSwitch=c({name:"orgs switch",summary:"Act in and pay from another organization on this computer (Studio too), by its slug or id",input:o.strictObject({org:o.string().min(1).describe("The organization: its slug or id")}),positional:["org"],output:o.looseObject({id:o.string(),name:o.string()}),examples:["allyhub orgs switch apollo"]},(r,a)=>d(async()=>{const e=g(a);if(e.config.apiKey!==void 0)return{value:{id:"",name:""},text:`A key in ${h} acts in the organization it was made for; unset it to choose one here.`,exit:u.usage};const i=(await l(e)).filter(n=>n.dissolvedAt===null).find(n=>n.slug===r.org||n.id===r.org);return i===void 0?{value:{id:"",name:""},text:`You are in no organization ${r.org}. allyhub orgs list says which you are in.`,exit:u.usage}:(await f(e.config,{id:i.id,name:i.name}),{value:{id:i.id,name:i.name},text:`This computer acts in ${i.name} now.`})}));
|
package/dist/commands/render.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{join as u,resolve as b}from"node:path";import{z as a}from"zod";import{formatConsole as
|
|
2
|
+
import{join as u,resolve as b}from"node:path";import{z as a}from"zod";import{formatConsole as g,formatProblem as y}from"../text/index.js";import{exportProject as x}from"@allyhub-next/export";import{SHARE_ENCODE as s}from"@allyhub-next/render";import{consoleJson as m}from"@allyhub-next/project";import{OUT_DIR as v}from"@allyhub-next/formats";import{EXIT as d}from"@allyhub-next/protocol";import{defineCommand as w}from"../command.js";import{parameters as $}from"../parameters.js";import{projectRoot as k}from"../project.js";import{combosOf as P,commandError as O}from"../version.js";import{dir as j,indexing as B}from"../fields.js";const S={codec:a.enum(["h264","h265"]).default("h264").describe("The mp4's video codec; h265 is smaller"),crf:a.number().int().min(0).max(63).optional().describe(`Quality, lower is better: default ${String(s.crf)} for an mp4, ready to share (a platform profile's format its own), 30 for a webm`),maxBitrate:a.number().int().min(0).max(5e5).optional().describe(`An mp4's most video bitrate, kbit/s, 0 for none: default ${String(s.maxKbps)} at 1080p ${String(s.fps)} fps, scaled by the frame's pixels and the frames a second (16000 at 1080p 60, 32000 at 4K 30), so the file is ready to share; a platform profile's format its own`),audioBitrate:a.number().int().min(32).max(512).optional().describe("The sound's bitrate, kbit/s: default 192 (AAC in an mp4), 160 (Opus in a webm); a mov keeps PCM")},T=(o,r)=>`${String(o)} ${r}${o===1?"":"s"}`;export const render=w({name:"render",summary:"The files: a video, its frames, subtitles, cover and mastered mix; a batch's table of ads; a deck's PDF, PPTX and PNGs; a doc's PDF and Markdown; a sheet's xlsx, CSV, Markdown and JSON; a 3D model's GLB",input:a.strictObject({items:a.array(a.string()).optional().describe("Only these items: an id, a path into one, or a folder of items; default every one"),combo:a.array(a.string()).optional().describe("Only the combos matching name=value pairs joined with commas (lang=zh-cn,hook=b), or a combo's id (c03)"),type:a.array(a.string()).optional().describe("File types: mp4, mov, webm, gif, png, srt, vtt (cues cut as the piece's captions layer cuts them, else by default), cover, wav (the mix, mastered as the render masters it: 48 kHz, 16 bits, the film's length), pdf, pptx; csv for a piece with slots, its table of ads (<piece>/ads.csv: a row per ad with its combo, picks, length, file, name and generated media); a doc's pdf, png, md; a sheet's xlsx, csv, md, json; a 3D model's glb. Default mp4 for a video, pdf for a deck and a doc, xlsx for a sheet, glb for a model; a type an item does not have is skipped"),out:a.string().optional().describe("The folder the files go in; default .allyhub/out"),name:a.string().optional().describe("Name a video's or deck's files <name>.<ext> in its folder of the output, with what tells its versions apart before the extension when there are several (<name>.zh-cn.mp4, <name>.c03.mp4); default <output>.<combo>.<ext>"),params:$(S),dir:j}),positional:["items"],output:a.looseObject({out:a.string(),files:a.array(a.looseObject({name:a.string(),path:a.string(),type:a.string()})),failed:a.array(a.looseObject({name:a.string(),code:a.string()}))}),examples:["allyhub render","allyhub render launch/film --type mp4,srt","allyhub render launch/film --type wav","allyhub render ads/tidyform --type csv","allyhub render launch/plan --type pdf,md","allyhub render --combo lang=zh-cn --param crf=16","allyhub render launch/film --name launch-film --param max-bitrate=0"]},async(o,r)=>{const n=await k(r.cwd,o.dir),l=b(r.cwd,o.out??u(n,v)),i=o.params,f={codec:i.codec,...i.crf===void 0?{}:{crf:i.crf},...i.maxBitrate===void 0?{}:{maxBitrate:i.maxBitrate},...i.audioBitrate===void 0?{}:{audioBitrate:i.audioBitrate}};let t;try{t=await x({root:n,out:l,...o.items===void 0?{}:{items:o.items},combos:P(o),...o.type===void 0?{}:{types:o.type},...o.name===void 0?{}:{name:o.name},encode:f,index:B(r.env),log:e=>{r.progress(e)},signal:r.signal})}catch(e){throw O(e)}const p=e=>e?` (${e.integrated.toFixed(1)} LUFS, true peak ${e.truePeak===void 0?"–":e.truePeak.toFixed(1)} dBTP)`:"",c=t.problems.filter(e=>e.level==="error"),h=[`${T(t.files.length,"file")} in ${t.out}:`,...t.files.map(e=>` ${e.path}${p(e.loudness)}`),...t.failed.length>0?["Not made:",...t.failed.map(e=>` ${e.name}: ${e.message}${e.hint?` ${e.hint}`:""}`)]:[],...t.unindexed.map(e=>`Not indexed, drawn the fallback way: ${e.file} (${e.error})`),...c.map(y),...g(m(t.console))];return{value:{out:t.out,files:t.files.map(e=>({...e})),failed:t.failed.map(e=>({...e})),problems:t.problems,...t.unindexed.length>0?{unindexed:t.unindexed}:{},...m(t.console)},text:h.join(`
|
|
3
3
|
`),exit:t.failed.length>0?d.failed:d.ok}});
|
package/dist/commands/skills.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{z as r}from"zod";import{EXIT as m}from"@allyhub-next/protocol";import{RegistryError as y}from"@allyhub-next/registry";import{workSkills as b}from"@allyhub-next/scaffold";import{CommandError as d,defineCommand as f}from"../command.js";import{resourcesIndex as
|
|
3
|
-
`)}}),skillsShow=f({name:"skills show",summary:"Prints one of AllyHub's skills in full, its SKILL.md and the names of its other files, without adding it to the project",input:r.strictObject({name:r.string().min(1).describe("The skill, as allyhub skills lists it (product-demos)")}),positional:["name"],output:r.looseObject({}),examples:["allyhub skills show product-demos"]},async(i,c)=>{const s=await
|
|
4
|
-
`)}}catch(e){throw e instanceof y?new d(e.code,e.message,{exit:e.code==="no-registry"?m.platform:m.failed,hint:e.hint??
|
|
2
|
+
import{z as r}from"zod";import{EXIT as m}from"@allyhub-next/protocol";import{RegistryError as y}from"@allyhub-next/registry";import{workSkills as b}from"@allyhub-next/scaffold";import{CommandError as d,defineCommand as f}from"../command.js";import{resourcesIndex as k}from"../resources.js";const p="Check the connection and run the same command again.";function w(i){if(i.index===void 0)throw new d("no-registry",`AllyHub's skills could not be read from ${i.source.name}.`,{exit:m.platform,hint:p})}export const skills=f({name:"skills",summary:"Lists AllyHub's work skills, each how to make one kind of work, with what it is for: allyhub skills show <name> prints one, allyhub add skill/<name> puts it in the project",input:r.strictObject({}),output:r.looseObject({}),examples:["allyhub skills","allyhub skills show product-demos"]},async(i,c)=>{const s=await k(c);w(s);const a=b(s.index.items).map(t=>{const o=s.index.items.find(h=>h.name===t.name)?.version;return{...t,...o===void 0?{}:{version:o}}}),e=s.from==="stale",l=Math.max(0,...a.map(t=>t.name.length));return{value:{skills:a,stale:e},text:[`AllyHub's work skills (allyhub skills show <name> prints one; allyhub add skill/<name> puts it in the project, in .agents/skills)${e?", as last read (the registry cannot be read now)":""}:`,...a.length===0?[" none"]:a.map(t=>` ${t.name.padEnd(l)} ${t.description}`)].join(`
|
|
3
|
+
`)}}),skillsShow=f({name:"skills show",summary:"Prints one of AllyHub's skills in full, its SKILL.md and the names of its other files, without adding it to the project",input:r.strictObject({name:r.string().min(1).describe("The skill, as allyhub skills lists it (product-demos)")}),positional:["name"],output:r.looseObject({}),examples:["allyhub skills show product-demos"]},async(i,c)=>{const s=await k(c);if(w(s),s.index.items.find(e=>e.name===i.name)?.type!=="allyhub:skill")throw new d("no-item",`AllyHub has no skill ${i.name}.`,{exit:m.notFound,hint:"allyhub skills lists them."});try{const e=await s.source.item(i.name);if(!e)throw new d("no-item",`AllyHub has no skill ${i.name}.`,{exit:m.notFound,hint:"allyhub skills lists them."});const l=`.agents/skills/${e.name}/`,t=n=>n.startsWith(l)?n.slice(l.length):n,o=e.files.find(n=>t(n.target)==="SKILL.md");if(!o)throw new d("bad-registry",`The registry's ${e.name} has no SKILL.md.`);const h=o.content??new TextDecoder().decode(await s.source.file(o.path)),u=e.files.map(n=>t(n.target)).filter(n=>n!=="SKILL.md");return{value:{name:e.name,...e.version===void 0?{}:{version:e.version},skill:h,files:u},text:[h.trimEnd(),"",u.length===0?`It has no other files. allyhub add skill/${e.name} puts it in ${l}.`:`Its other files, which allyhub add skill/${e.name} puts beside it in ${l}: ${u.join(", ")}.`].join(`
|
|
4
|
+
`)}}catch(e){throw e instanceof y?new d(e.code,e.message,{exit:e.code==="no-registry"?m.platform:m.failed,hint:e.hint??p}):e}});
|
package/dist/commands/voice.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{z as
|
|
3
|
-
`)}
|
|
2
|
+
import{z as t}from"zod";import{projectSays as f}from"@allyhub-next/project";import{makeSay as u}from"@allyhub-next/cloud";import{EXIT as y}from"@allyhub-next/protocol";import{CommandError as g,defineCommand as $}from"../command.js";import{projectRoot as v}from"../project.js";import{cloudOf as w,cloudWork as b,plural as n}from"./cloud.js";import{dir as j}from"../fields.js";const h=i=>Math.round(i*1e6)/1e6;export const voice=$({name:"voice",summary:"Make the voice files a project's say(text) parts need, with their cloud voice tool, one per say that has none (assets/media/gen/say/<hash>, its words and its record); --dry-run lists them first, with their tool and characters",input:t.strictObject({item:t.string().optional().describe("Only this item's says: its id, a path into it, or a folder of items"),dir:j,dryRun:t.boolean().default(!1).describe("List the says without a file, each with its tool and characters, making nothing")}),positional:["item"],output:t.looseObject({says:t.number(),missing:t.array(t.looseObject({part:t.string(),stem:t.string()})).optional(),made:t.array(t.looseObject({part:t.string(),file:t.string()})).optional(),credits:t.number().optional()}),examples:["allyhub voice --dry-run","allyhub voice launch/film"]},async(i,s)=>{const c=await v(s.cwd,i.dir),o=await f(c,i.item===void 0?{}:{piece:i.item});if(i.item!==void 0&&o.pieces.length===0)throw new g("no-item",`No video ${i.item} in the project.`,{exit:y.notFound});const a=o.says.filter(l=>l.file===void 0),d=`Every say has its file (${n(o.says.length,"say")}). Nothing to make.`;return await b(async()=>{const l=w(s);if(i.dryRun)return{value:{says:o.says.length,missing:a.map(e=>({piece:e.piece,part:e.part,tool:e.tool,...e.voice===void 0?{}:{voice:e.voice},...e.params===void 0?{}:{params:e.params},characters:e.text.length,stem:e.stem}))},text:a.length===0?d:[`${n(a.length,"say")} without a file:`,...a.map(e=>` ${e.piece} · ${e.part}: ${e.tool}, ${n(e.text.length,"character")}`),"Nothing was made; allyhub voice makes them, priced as each tool's description says."].join(`
|
|
3
|
+
`)};const r=[];for(const e of a){s.progress(`${e.piece} · ${e.part}: ${e.tool}…`);const m=await u(l,c,e,{base:c,signal:s.signal});r.push({piece:e.piece,part:e.part,...m})}const p=h(r.reduce((e,m)=>e+m.credits,0));return{value:{says:o.says.length,made:r,kept:o.says.length-a.length,credits:p},text:r.length===0?d:[`Made ${n(r.length,"file")}:`,...r.map(e=>` ${e.file} (${e.piece} · ${e.part}, ${String(h(e.seconds))} s)`),`Credits used: ${String(p)}.`].join(`
|
|
4
4
|
`)}})});
|
package/dist/main.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
import{
|
|
3
|
-
`:`${
|
|
4
|
-
`)},
|
|
5
|
-
`)},signal:v.signal
|
|
6
|
-
`):
|
|
7
|
-
${
|
|
8
|
-
`),
|
|
2
|
+
import{EXIT as m,describeCommand as O}from"@allyhub-next/protocol";import{readArgs as D}from"./args.js";import{CLI_VERSION as S}from"./cli-version.js";import{CommandError as h}from"./command.js";import{COMMAND_SOURCES as M,COMMANDS as N}from"./commands/index.js";import{commandHelp as E,listHelp as T,workHelp as H}from"./help.js";import{sdkDocs as R}from"./sdk-docs.js";import{WORKS as G,cloudNouns as J,workNamed as W,workTitle as j}from"./works.js";const _={stdout:e=>process.stdout.write(e),stderr:e=>process.stderr.write(e),cwd:process.cwd(),env:process.env};export function findCommand(e,s=N){let i;for(const c of s){const l=c.spec.name.split(" ");l.every((o,a)=>e[a]===o)&&l.length>(i?.length??0)&&(i={command:c,length:l.length})}return i?{command:i.command,rest:e.slice(i.length)}:{rest:[...e]}}export async function resolveCommand(e,s,i=N,c=M){const l=findCommand(e,i);if(l.command)return l;for(const o of c){const a=await o.resolve(e,s);if(a)return a}return l}const A=e=>({...O(e.spec),...e.about?.value});export async function main(e,s=_,i=N,c=M){const l=e.includes("--json"),o=e.filter(n=>n!=="--json"),a=(n,t)=>{s.stdout(l?`${JSON.stringify(n,null,2)}
|
|
3
|
+
`:`${t}
|
|
4
|
+
`)},b=i.map(n=>n.spec),v=new AbortController,y={cwd:s.cwd,env:s.env,progress:n=>{s.stderr(`${n}
|
|
5
|
+
`)},signal:v.signal};if(o[0]==="--version"||o[0]==="-v")return a({version:S},S),m.ok;if(o.length===0||o[0]==="help"||o[0]==="--help"||o[0]==="-h"){const n=o.slice(1),t=await R(s.cwd).catch(()=>{}),k=async()=>{const r=await Promise.all(c.map(u=>u.nouns(y).catch(()=>{})));return r.some(u=>u===void 0)?void 0:r.flatMap(u=>u??[])};if(n.length===0){const r=await k();return a({version:S,docs:t?.dir,works:G.map(u=>({...u,title:j(u,r)})),commands:b.map(O),made:[...c.flatMap(u=>u.entries),...r??[]]},T(b,c,r,t?.dir)),m.ok}const d=n.length===1?W(n[0]??""):void 0;if(d){const r=d.cloud===void 0?[]:await k();return a({...d,title:j(d,r),...d.cloud===void 0?{}:{cloudWorks:r&&J(d,r)},docsDir:t?.dir},H(d,b,c,t?.dir,r)),m.ok}let p;try{p=await resolveCommand(n,y,i,c)}catch(r){return g(r)}const{command:f,rest:I}=p;return f&&p.list===!0?await $(f,I):!f||I.length>0?g(new h("unknown-command",`allyhub has no command "${n.join(" ")}".`,{exit:m.usage,hint:"allyhub help lists them and the works."})):(a(A(f),E(f.spec,f.about?.lines)),m.ok)}let C;try{C=await resolveCommand(o,y,i,c)}catch(n){return g(n)}const{command:w,rest:x}=C;if(!w)return g(new h("unknown-command",`allyhub has no command "${o[0]??""}".`,{exit:m.usage,hint:"allyhub help lists them."}));if(x.includes("--help")||x.includes("-h"))return a(A(w),E(w.spec,w.about?.lines)),m.ok;return await $(w,x);async function $(n,t){const k=()=>{v.abort(new h("interrupted","Stopped.",{exit:m.interrupted}))};process.once("SIGINT",k);try{const d=D(n.spec,t),p=await n.run(d,y);return a(p.value,p.text),p.exit??m.ok}catch(d){return g(d)}finally{process.off("SIGINT",k)}}function g(n){const t=n instanceof h?n:v.signal.aborted?new h("interrupted","Stopped.",{exit:m.interrupted}):new h("failed",n instanceof Error?n.message:String(n));return l?s.stdout(`${JSON.stringify({error:{code:t.code,message:t.message,...t.hint?{hint:t.hint}:{}}},null,2)}
|
|
6
|
+
`):s.stderr(`${t.message}${t.hint?`
|
|
7
|
+
${t.hint}`:""}
|
|
8
|
+
`),t.exit}}
|
package/dist/works.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! AllyHub. Copyright (c) 2026 AllyHub, Inc. All rights reserved. Use is subject to LICENSE.md. */
|
|
2
|
-
export const WORKS=[{name:"video",title:"Making a video (one piece, or a batch of ads in combos)",commands:["check","frames","inspect","inspect layout","inspect timeline","inspect motion","inspect still","inspect contrast","inspect seams","inspect flash","inspect loop","inspect combos","audio","add","dev","render"],docs:["video.md","layers.md","speech.md","sound.md"]},{name:"footage",title:"Cutting recorded footage: a talking head, an interview",commands:["words","words edits","align","frames cuts","audio recording","render"],docs:["footage.md","speech.md"]},{name:"slides",title:"Making a deck",commands:["check","frames","inspect layout","dev","render"],docs:["slides.md","layers.md"]},{name:"docs",title:"Writing a doc",commands:["check","dev","render"],docs:["docs.md"]},{name:"sheets",title:"Making a sheet",commands:["sheet import","sheet","check","dev","render"],docs:["sheets.md"]},{name:"websites",title:"Showing a project's videos in a website (an Astro project)",commands:["site media","render"],docs:["project.md"]},{name:"generating",title:"Making media with AI models",commands:["<work>","<work> <tool>","upload","voice"],cloud:{works:["ai-media"]}},{name:"researching",title:"Researching a market online",commands:["<work>","<work> <tool>","frames web"],cloud:{}},{name:"references",title:"Studying reference videos, and a piece against them",commands:["reference","reference compare","reference served","reference set","frames","frames compare","words","audio","align"]},{name:"3d",title:"Building a 3D scenery and its cameras",commands:["scenery","scenery view","scenery map","scenery see","scenery measure","scenery motion","scenery solve","scenery bake","inspect fidelity","dev"],docs:["scenery.md"]},{name:"modeling",title:"Modelling a prop in code, or adding one from a library",commands:["add search","add","model","model capabilities"],docs:["modeling.md","scenery.md"]},{name:"setup",title:"This computer, the account and AllyHub's skills",commands:["skills","skills show","auth login","auth status","auth logout","auth token","orgs list","orgs switch","doctor","mcp"]}],workNamed=e=>WORKS.find(n=>n.name===e);export function cloudNouns(e,n){if(e.cloud===void 0)return[];const s=new Set(WORKS.flatMap(o=>o.cloud?.works??[])),t=e.cloud.works;return n.filter(o=>t===void 0?!s.has(o.name):t.includes(o.name))}export function workTitle(e,n){if(e.cloud===void 0)return e.title;if(n===void 0)return`${e.title} (the cloud catalog could not be read)`;const s=cloudNouns(e,n);return s.length===0?`${e.title}: no cloud tools yet`:`${e.title}: ${s.map(t=>t.name).join(", ")}`}
|
|
2
|
+
export const WORKS=[{name:"video",title:"Making a video (one piece, or a batch of ads in combos)",commands:["check","frames","inspect","inspect layout","inspect timeline","inspect motion","inspect still","inspect contrast","inspect seams","inspect flash","inspect loop","inspect combos","audio","add","dev","render"],docs:["video.md","layers.md","speech.md","sound.md"]},{name:"footage",title:"Cutting recorded footage: a talking head, an interview",commands:["words","words edits","align","frames cuts","audio recording","render"],docs:["footage.md","speech.md"]},{name:"slides",title:"Making a deck",commands:["check","frames","inspect layout","dev","render"],docs:["slides.md","layers.md"]},{name:"docs",title:"Writing a doc",commands:["check","dev","render"],docs:["docs.md"]},{name:"sheets",title:"Making a sheet",commands:["sheet import","sheet","check","dev","render"],docs:["sheets.md"]},{name:"websites",title:"Showing a project's videos in a website (an Astro project)",commands:["site media","render"],docs:["project.md"]},{name:"generating",title:"Making media with AI models",commands:["<work>","<work> <tool>","upload","voice"],cloud:{works:["ai-media"]}},{name:"researching",title:"Researching a market online",commands:["<work>","<work> <tool>","frames web"],cloud:{}},{name:"references",title:"Studying reference videos, and a piece against them",commands:["reference","reference compare","reference served","reference set","frames","frames compare","words","audio","align"]},{name:"3d",title:"Building a 3D scenery and its cameras",commands:["scenery","scenery view","scenery map","scenery see","scenery measure","scenery motion","scenery solve","scenery bake","inspect fidelity","dev"],docs:["scenery.md"]},{name:"modeling",title:"Modelling a prop in code, or adding one from a library",commands:["add search","add","3d-model","3d-model capabilities"],docs:["modeling.md","scenery.md"]},{name:"setup",title:"This computer, the account and AllyHub's skills",commands:["skills","skills show","auth login","auth status","auth logout","auth token","orgs list","orgs switch","doctor","mcp"]}],workNamed=e=>WORKS.find(n=>n.name===e);export function cloudNouns(e,n){if(e.cloud===void 0)return[];const s=new Set(WORKS.flatMap(o=>o.cloud?.works??[])),t=e.cloud.works;return n.filter(o=>t===void 0?!s.has(o.name):t.includes(o.name))}export function workTitle(e,n){if(e.cloud===void 0)return e.title;if(n===void 0)return`${e.title} (the cloud catalog could not be read)`;const s=cloudNouns(e,n);return s.length===0?`${e.title}: no cloud tools yet`:`${e.title}: ${s.map(t=>t.name).join(", ")}`}
|