flash-story-app 1.0.0 → 1.1.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/README.md +14 -2
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/serve.js +194 -193
- package/package.json +2 -2
- package/static/assets/{index-3MnGe9um.js → index-DeZBKepj.js} +199 -194
- package/static/index.html +1 -1
package/README.md
CHANGED
|
@@ -36,8 +36,10 @@ Environment:
|
|
|
36
36
|
| `FLASHSTORY_OPENAI_MODELS` | = MODEL | **fallback** selectable model list (comma/space separated), used only when the endpoint's live `/v1/models` probe fails |
|
|
37
37
|
| `FLASHSTORY_SERVER` | `http://127.0.0.1:8787` | CLI client target (flag `--server` wins) |
|
|
38
38
|
|
|
39
|
-
Serve-mode
|
|
40
|
-
`--data-dir <dir>` `--open
|
|
39
|
+
Serve-mode flags (override env / .env):
|
|
40
|
+
`--port <n>` `--host <h>` `--data-dir <dir>` `--open`. The editor opens in the
|
|
41
|
+
default browser automatically after boot; pass `--no-open` to keep it
|
|
42
|
+
headless (server still prints its URL).
|
|
41
43
|
|
|
42
44
|
### .env support
|
|
43
45
|
|
|
@@ -72,6 +74,16 @@ The settings dialog reads the model list from the server: a live probe of the
|
|
|
72
74
|
endpoint's `/v1/models` (cached 60s with a 2.5s timeout), falling back to
|
|
73
75
|
`FLASHSTORY_OPENAI_MODELS` (or the default model) when the probe fails.
|
|
74
76
|
|
|
77
|
+
### Custom endpoint / key (settings-AI)
|
|
78
|
+
|
|
79
|
+
The settings dialog's AI tab can set a custom **API Base URL** and **API Key**
|
|
80
|
+
that override the environment. They are stored ON THE SERVER
|
|
81
|
+
(`~/.flashstory/llm-override.json` — behaving like a `.env` overlay: applied
|
|
82
|
+
globally for every browser and the CLI, hot without a restart, and "clear"
|
|
83
|
+
removes the override so the env config wins again). The browser never persists
|
|
84
|
+
the key, and no server response ever returns it. The "test connection" button
|
|
85
|
+
probes whatever the draft fields hold before you commit them.
|
|
86
|
+
|
|
75
87
|
## Dev mode (vite)
|
|
76
88
|
|
|
77
89
|
In dev the frontend calls the backend **directly** (`http://127.0.0.1:8787` by
|
package/dist/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawn as
|
|
2
|
+
import{spawn as N}from"node:child_process";import{mkdirSync as P,writeFileSync as $,readFileSync as F}from"node:fs";import{join as j}from"node:path";import{homedir as R}from"node:os";import{l as C}from"./env.js";class w extends Error{}async function E(e,t,r,o){const c=await fetch(`${e}${r}`,{method:t,headers:o!==void 0?{"content-type":"application/json"}:void 0,body:o!==void 0?JSON.stringify(o):void 0}),u=await c.json().catch(()=>null);return{status:c.status,data:u}}async function q(e,t,r){const o=await fetch(`${e}${r}`,{method:t});return{status:o.status,text:await o.text()}}async function A(e,t){const r=await fetch(`${e}${t}`);return{status:r.status,bytes:new Uint8Array(await r.arrayBuffer())}}function v(e,t){if(e.status>=200&&e.status<300)return e.data;const r=e.data?.detail??e.data?.error??`HTTP ${e.status}`;throw new w(`${t} failed: ${r}`)}const B={get:E,post:E,binary:A,text:q};function D(e){const t=[],r={};for(let o=0;o<e.length;o++){const c=e[o];if(c.startsWith("--")){const u=c.slice(2),s=e[o+1];s!==void 0&&!s.startsWith("--")?(r[u]=s,o+=1):r[u]=!0}else t.push(c)}return{positionals:t,flags:r}}function n(e,t){const r=e[t];return typeof r=="string"?r:void 0}function G(e){const t=n(e,"project");if(!t)throw new w("--project <id> is required");return t}function g(e,t){if(!e)throw new w(`--json <${t}> is required`);try{return JSON.parse(e)}catch{throw new w(`--json <${t}> is not valid JSON`)}}async function l(e,t,r,o,c=!1){const u=await e.post(t,"POST",c?"/api/tools/batch":"/api/tools/execute",{projectId:r,...c?{actions:o}:{action:o}});if(u.status===404)return{data:{error:"project not found"},exit:1};const s=u.data;return s.ok?{data:{ok:!0,rev:s.rev},exit:0}:{data:{ok:!1,error:s.error??"rejected"},exit:1}}const h=e=>e().catch(t=>({data:{error:t instanceof Error?t.message:String(t)},exit:1}));async function H(e,t,r=B){const[o,...c]=e,{positionals:u,flags:s}=D(c),p=()=>G(s);switch(o){case"health":return h(async()=>{const d=await r.get(t,"GET","/health");return{data:v(d,"health"),exit:0}});case"scene":{const d=u[0];if(d==="list")return h(async()=>{const a=await r.get(t,"GET","/api/projects");return{data:v(a,"list projects"),exit:0}});if(d==="get")return h(async()=>{const a=await r.get(t,"GET",`/api/projects/${p()}`);if(a.status===404)throw new w("project not found");return{data:a.data,exit:0}});throw f("flashstory scene list|get --project <id>")}case"entity":{const d=u[0],a=p(),i=n(s,"id"),m=n(s,"name");switch(d){case"add":return l(r,t,a,{type:"addEntity",entity:{...i?{id:i}:{},name:m??"未命名",kind:n(s,"kind")??"character",...n(s,"color")?{color:n(s,"color")}:{}}});case"remove":if(!i)throw f("--id is required");return l(r,t,a,{type:"removeEntity",id:i});case"update":{if(!i)throw f("--id is required");const x={};return m&&(x.name=m),n(s,"color")&&(x.color=n(s,"color")),n(s,"heightCm")&&(x.heightCm=Number(n(s,"heightCm"))),l(r,t,a,{type:"updateEntity",id:i,patch:x})}default:throw f("flashstory entity add|remove|update --project <id> [--id] [--name]")}}case"transform":if(u[0]!=="set"||!n(s,"id"))throw f("flashstory transform set --project --id --json <keys>");return l(r,t,p(),{type:"setTransformTrack",id:n(s,"id"),keys:g(n(s,"json"),"keys")});case"pose":{const d=u[0];if(d==="list")return h(async()=>{const a=await r.get(t,"GET",`/api/projects/${p()}`);if(a.status===404)throw new w("project not found");return{data:{customPoses:a.data.doc.customPoses??{}},exit:0}});if(d==="set-keys"){if(!n(s,"id"))throw f("--id is required");return l(r,t,p(),{type:"setPoseTrack",id:n(s,"id"),keys:g(n(s,"json"),"keys")})}throw f("flashstory pose list|set-keys --project --id --json")}case"camera":if(u[0]!=="set-keys")throw f("flashstory camera set-keys --project --json");return l(r,t,p(),{type:"setCameraTrack",keys:g(n(s,"json"),"keys")});case"settings":return l(r,t,p(),{type:"setSettings",patch:g(n(s,"json"),"patch")});case"marker":{const d=Number(n(s,"t")??NaN);if(u[0]!=="add"||!Number.isFinite(d))throw f("flashstory marker add --project --t <sec> --label <text>");return l(r,t,p(),{type:"addMarker",t:d,label:n(s,"label")??""})}case"batch":return l(r,t,p(),g(n(s,"json"),"actions"),!0);case"screenshot":return h(async()=>{const d=await r.post(t,"POST","/api/tools/screenshot",{projectId:p(),t:Number(n(s,"t")??0),camera:n(s,"camera")??"edit"}),a=v(d,"screenshot"),i=n(s,"out");if(a.kind==="image"&&i){const m=a.dataUrl?.split(",")[1];return m&&$(i,Buffer.from(m,"base64")),{data:{kind:"image",saved:i},exit:0}}return{data:a,exit:0}});case"export":{const d=u[0],a=u[1];switch(d){case"submit":return h(async()=>{const i=await r.post(t,"POST","/api/export",{projectId:p(),includeVideo:s["no-video"]!==!0,includeStills:s.stills===!0});return{data:v(i,"export submit"),exit:0}});case"status":if(!a)throw f("usage: flashstory export status <exportId>");return h(async()=>{const i=await r.get(t,"GET",`/api/export/${a}`);if(i.status===404)throw new w("export not found");return{data:i.data,exit:0}});case"result":if(!a)throw f("usage: flashstory export result <exportId> --out <dir>");return h(async()=>{const i=n(s,"out")??"exports";P(i,{recursive:!0});const x=((await r.get(t,"GET",`/api/export/${a}/files`)).data?.files??[]).filter(Boolean),S=[];for(const k of x){const T=await r.binary(t,`/api/export/${a}/files/${encodeURIComponent(k)}`);T.status===200&&($(j(i,k),T.bytes),S.push(j(i,k)))}return{data:{exportId:a,downloaded:S},exit:0}});case"cancel":if(!a)throw f("usage: flashstory export cancel <exportId>");return h(async()=>({data:(await r.post(t,"POST",`/api/export/${a}/cancel`,{})).data,exit:0}));default:throw f("flashstory export submit|status|result|cancel")}}default:throw f(`unknown command: ${o}`)}}function f(e){return new w(e)}const J="http://127.0.0.1:8787";function L(){return j(R(),".flashstory","config.json")}function U(){try{const e=F(L(),"utf8"),t=JSON.parse(e);return typeof t.server=="string"&&t.server?t.server:void 0}catch{return}}function _(e){return e??process.env.FLASHSTORY_SERVER??U()??J}function V(e){const t={},r=[];for(let o=0;o<e.length;o++){const c=e[o];switch(c){case"--server":t.server=e[o+1],o+=1;break;case"--port":t.port=Number(e[o+1]),o+=1;break;case"--host":t.host=e[o+1],o+=1;break;case"--data-dir":t.dataDir=e[o+1],o+=1;break;case"--open":t.open=!0;break;case"--no-open":t.noOpen=!0;break;default:r.push(c)}}return{flags:t,args:r}}function Y(e){return e.noOpen===!0?!1:e.open??!0}C();const{flags:y,args:b}=V(process.argv.slice(2)),O=b[0];if(!O||O==="serve"){const{startServer:e}=await import("./serve.js"),t={};if(y.port!==void 0&&Number.isFinite(y.port)&&(t.port=y.port),y.host&&(t.hostname=y.host),y.dataDir&&(t.dataDir=y.dataDir),await e(t),Y(y)){const r=`http://${t.hostname??process.env.FLASHSTORY_HOST??"127.0.0.1"}:${t.port??process.env.FLASHSTORY_PORT??8787}/`;W(r)}}else{const e=_(y.server),{data:t,exit:r}=await H(b,e);console.log(JSON.stringify(t)),process.exit(r)}function W(e){const t=process.platform,c=N(t==="darwin"?"open":t==="win32"?"cmd":"xdg-open",t==="win32"?["/c","start","",e]:[e],{stdio:"ignore",detached:!0});c.on("error",()=>{}),c.unref?.()}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{startServer as r}from"./serve.js";import{l as o}from"./env.js";import"@hono/node-server";import"node:module";import"hono";import"@hono/node-server/serve-static";import"node:fs";import"node:fs/promises";import"node:path";import"node:url";import"hono/streaming";import"stream";import"events";import"buffer";import"util";import"ws";
|
|
1
|
+
import{startServer as r}from"./serve.js";import{l as o}from"./env.js";import"@hono/node-server";import"node:module";import"hono";import"@hono/node-server/serve-static";import"node:fs";import"node:fs/promises";import"node:path";import"node:url";import"node:os";import"hono/streaming";import"stream";import"events";import"buffer";import"util";import"ws";o();await r();
|