@salsita-ai/sdk 0.49.0 → 0.50.0-develop.2331d4a6b7
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/application-spec/generate-application/code/templates/index.d.ts +6 -6
- package/dist/application-spec/generate-application/code/templates/index.js +1 -1
- package/dist/application-spec/generate-application/code/templates/skills/agents-md.js +2 -0
- package/dist/application-spec/generate-application/code/templates/skills/phoenix-cli-skill.js +1 -0
- package/dist/application-spec/generate-application/code/templates/{phoenix-create-configurator-skill.d.ts → skills/phoenix-create-configurator-skill.d.ts} +1 -1
- package/dist/application-spec/generate-application/code/templates/{phoenix-create-configurator-skill.js → skills/phoenix-create-configurator-skill.js} +1 -1
- package/dist/application-spec/generate-application/code/templates/{phoenix-feedback-skill.js → skills/phoenix-feedback-skill.js} +1 -1
- package/dist/application-spec/generate-application/code/templates/{phoenix-review-skill.js → skills/phoenix-review-skill.js} +2 -2
- package/dist/application-spec/generate-application/code/templates/skills/phoenix-skill.js +1 -0
- package/dist/application-spec/generate-application/code/templates/{common → skills}/sdk-content.d.ts +21 -0
- package/dist/application-spec/generate-application/code/templates/skills/sdk-content.js +67 -0
- package/dist/client/phoenix-api.d.ts +5 -1
- package/dist/configurator/application-runtime/extensions/configurator-extension-systems.d.ts +2 -1
- package/dist/configurator/application-runtime/extensions/configurator-extension-systems.js +1 -1
- package/dist/configurator/application-runtime/extensions/selectors.d.ts +2 -1
- package/dist/configurator/application-runtime/extensions/selectors.js +1 -1
- package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.d.ts +35 -0
- package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.js +1 -0
- package/dist/configurator/{assistant → application-runtime/extensions/systems/assistant-system}/browser-details.d.ts +1 -1
- package/dist/configurator/application-runtime/extensions/systems/assistant-system/browser-details.js +1 -0
- package/dist/configurator/{assistant → application-runtime/extensions/systems/assistant-system}/graphql-tools.d.ts +13 -14
- package/dist/configurator/application-runtime/extensions/systems/assistant-system/graphql-tools.js +1 -0
- package/dist/configurator/application-runtime/extensions/systems/index.d.ts +1 -0
- package/dist/configurator/application-runtime/extensions/systems/index.js +1 -1
- package/dist/configurator/assistant/use-assistant-chat.js +1 -1
- package/dist/docs/index.json +1 -1
- package/dist/docs/phoenix/migrations.mdx +45 -5
- package/dist/docs/phoenix/phoenix-cli.mdx +5 -3
- package/dist/docs/phoenix/sdk-builder-workflow.mdx +6 -4
- package/dist/docs/phoenix/state-management.mdx +1 -1
- package/dist/phoenix/cli.js +1 -1
- package/dist/phoenix/commands/deploy.js +2 -2
- package/dist/phoenix/commands/login.d.ts +24 -6
- package/dist/phoenix/commands/login.js +2 -2
- package/package.json +3 -3
- package/dist/application-spec/generate-application/code/templates/agents-md.js +0 -2
- package/dist/application-spec/generate-application/code/templates/common/sdk-content.js +0 -67
- package/dist/application-spec/generate-application/code/templates/phoenix-cli-skill.js +0 -1
- package/dist/application-spec/generate-application/code/templates/phoenix-skill.js +0 -1
- package/dist/configurator/assistant/browser-details.js +0 -1
- package/dist/configurator/assistant/graphql-tools.js +0 -1
- /package/dist/application-spec/generate-application/code/templates/{common → skills}/agent-skill.d.ts +0 -0
- /package/dist/application-spec/generate-application/code/templates/{common → skills}/agent-skill.js +0 -0
- /package/dist/application-spec/generate-application/code/templates/{agents-md.d.ts → skills/agents-md.d.ts} +0 -0
- /package/dist/application-spec/generate-application/code/templates/{phoenix-cli-skill.d.ts → skills/phoenix-cli-skill.d.ts} +0 -0
- /package/dist/application-spec/generate-application/code/templates/{phoenix-feedback-skill.d.ts → skills/phoenix-feedback-skill.d.ts} +0 -0
- /package/dist/application-spec/generate-application/code/templates/{phoenix-review-skill.d.ts → skills/phoenix-review-skill.d.ts} +0 -0
- /package/dist/application-spec/generate-application/code/templates/{phoenix-skill.d.ts → skills/phoenix-skill.d.ts} +0 -0
|
@@ -36,11 +36,11 @@ The starter `spec/application.yaml` begins with `project: default`, which means
|
|
|
36
36
|
pnpm phoenix login <workspace>
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
`phoenix login` opens Studio, where you approve the sign-in. Studio sends a one-time code back to the CLI on `127.0.0.1`,
|
|
39
|
+
`phoenix login` opens Studio, where you name the token and approve the sign-in. The CLI suggests `phoenix CLI on <computer>`; a name of your own, such as the agent and the machine, tells your tokens apart later. Studio sends a one-time code back to the CLI on `127.0.0.1`, the CLI exchanges it for a personal token and returns the browser to Studio, which confirms the sign-in. The code only works for the CLI that asked for it and expires after five minutes. **Deny** stops the waiting CLI at once and creates no token. Use `--no-open` to print the link instead of opening a browser.
|
|
40
40
|
|
|
41
41
|
The CLI stores the token in `~/.phoenix/credentials.json`, readable only by you, with one entry per server. `PHOENIX_CREDENTIALS_FILE` moves the file. The token acts for you in your workspace until you revoke it. It stops working when you are removed from the workspace or banned.
|
|
42
42
|
|
|
43
|
-
`pnpm phoenix logout` revokes the token and removes it from the file. Studio's **CLI tokens** page lists your tokens with when they were last used, and revokes any of them, for example one left on another computer.
|
|
43
|
+
`pnpm phoenix logout` revokes the token and removes it from the file. Studio's **CLI tokens** page lists your tokens by the names you gave them, with when they were last used, and revokes any of them, for example one left on another computer. A revoked token leaves the list.
|
|
44
44
|
|
|
45
45
|
`login`, `logout` and `deploy` follow the region, not the `SERVER_URL` in the project's `.env`. `dev` follows the region too when `.env` has no `SERVER_URL`:
|
|
46
46
|
|
|
@@ -77,8 +77,9 @@ pnpm phoenix deploy
|
|
|
77
77
|
|
|
78
78
|
1. It validates the application spec.
|
|
79
79
|
2. It packs the project files: the `.yaml` files in `spec`, everything in `src`, `mocks`, `assets`, `public` and `templates`, and `package.json`, `pnpm-lock.yaml`, `pnpm-workspace.yaml`, `.gitignore`, `CLAUDE.md` and `.cursor/rules/phoenix.mdc`. Every `node_modules`, `.phoenix` and `__generated` folder, every `.DS_Store` and `._*` file and every `.env` and `.env.*` file are left out, at any depth.
|
|
80
|
-
3. It
|
|
81
|
-
4. It
|
|
80
|
+
3. It asks the server for a build. The server compares your domain model with the deployed one and refuses, before anything is uploaded, a model that changed under an already deployed model version; see [Migrations](?path=/docs/phoenix-migrations--docs).
|
|
81
|
+
4. It uploads the archive, which may be up to 200 MB.
|
|
82
|
+
5. It starts the build, prints a link to the build's page in Studio and follows the build until your configurator is live, then prints its URL.
|
|
82
83
|
|
|
83
84
|
On the server, the install follows your `pnpm-lock.yaml` and `pnpm-workspace.yaml`, so it allows the same build scripts and package versions as `pnpm install` on your computer. The build runs without platform secrets. It sees only your own environment variables and the public platform values, the [build environment](?path=/docs/phoenix-phoenix-cli--docs) that `phoenix deployment:build-envs` writes. The trusted deploy step then publishes the frontend, webhooks and assets.
|
|
84
85
|
|
|
@@ -100,6 +101,7 @@ Coding agents working in your project use the same command, guided by the genera
|
|
|
100
101
|
## Known limits
|
|
101
102
|
|
|
102
103
|
- You can deploy once the workspace's first deployment is live. Until then, `phoenix deploy` tells you the workspace is still being set up.
|
|
104
|
+
- The first deployment is the starter, so the starter's model is version 1 in production. Replacing it with your own model needs the starter's model kept as `v1` and a migration to version 2; [Migrations](?path=/docs/phoenix-migrations--docs) shows the migration for replacing a model entirely.
|
|
103
105
|
- One workspace has one project, one `production` environment and one development environment per user.
|
|
104
106
|
- `phoenix deploy` always deploys to the workspace's default project; it doesn't read `project` from the spec yet.
|
|
105
107
|
- Only `phoenix dev` works from the sign-in. `phoenix deployment:prepare-dev` still needs the `.env` block of a Studio development environment.
|
|
@@ -61,7 +61,7 @@ interface ConfigurationSchema {
|
|
|
61
61
|
|
|
62
62
|
When you save work, Phoenix validates the entity data against this schema using AJV (Another JSON Schema Validator). If the data doesn't match the schema rules, the save fails. This prevents corrupt or mismatched data from entering your system.
|
|
63
63
|
|
|
64
|
-
Phoenix also checks the schema hash during deployment registration. If you try to deploy the same model version with different schema content, registration fails
|
|
64
|
+
Phoenix also checks the schema hash during deployment registration. If you try to deploy the same model version with different schema content, registration fails with a message that names the model version and the environment: a deployed model version cannot change, because saved configurations depend on it. Keep the deployed model as that version, put the change in a new model version and add a [migration](?path=/docs/phoenix-migrations--docs). Development and testing environments replace the deployed schema instead, as does the `--overrideSchema` flag, which is for development and testing only.
|
|
65
65
|
|
|
66
66
|
### Revisions: Your Version History
|
|
67
67
|
|
package/dist/phoenix/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{bool as e,str as o}from"envalid";import{readFileSync as t}from"fs";import{readFile as i}from"fs/promises";import{arch as r,platform as n}from"os";import{dirname as a,join as s,resolve as l}from"path";import{P as p,match as d}from"ts-pattern";import{fileURLToPath as c}from"url";import u from"yargs";import{hideBin as E}from"yargs/helpers";import{z as v}from"zod";import{createEnvReader as f}from"@salsita-ai/common/env";import{DEFAULT_PROJECT_ALIAS as g,FeedbackType as m}from"@salsita-ai/contracts/domain";import{phoenixCli as y}from"#package/legacy";import{readSpecProject as R}from"./application-spec/read-spec-project.js";import{prepareDevelopmentEnvironment as h,prepareLocalEnvironment as S,runActivateDeploymentCommand as _,runBuildCommand as U,runChangelogCommand as O,runCheckCommand as P,runCleanCommand as b,runCleanupEnvironmentCommand as L,runCreateEnvironmentCommand as I,runDataCommand as N,runDeployCommand as T,runDeploymentBuildEnvsCommand as w,runDevCommand as k,runDocsCommand as D,runExtractSourcesCommand as j,runFeedbackCommand as G,runFinishDeploymentCommand as C,runFixCommand as A,runInitCommand as K,runInspectAssetsCommand as V,runLinkCommand as M,runListEnvironmentsCommand as J,runLoginCommand as B,runLogoutCommand as F,runPrepareCiCommand as Y,runPrepareDeploymentCommand as q,runRegisterDeploymentCommand as x,runSceneCommand as H,runScreenshotCommand as W,runStateCommand as X,runStoryCommand as $,runSyncCommand as z,runUnlinkCommand as Q}from"./commands/index.js";import{DEFAULT_PHOENIX_REGION as Z,PHOENIX_REGIONS as ee,PUBLIC_PHOENIX_REGIONS as eo,getRegionServerUrl as et,getRegionStudioUrl as ei,resolveSignedInDevelopmentEnvironment as er}from"./services/index.js";import{getIsEditorEnabled as en}from"./utils/get-is-editor-enabled.js";import{createLogger as ea}from"./utils/index.js";let es=(e,o,t)=>{e?.info(`Using ${o?"application-spec":"domain-spec"} flow (${t})`)},el=(e,o,t)=>{let i=t?.logger??ea();if(void 0!==e)return i.detail(`Application spec: ${e} (from CLI flag)`),es(t?.logger,e,"from CLI flag"),e;let r=process.env.USE_APPLICATION_SPEC;if(void 0!==r){let e="true"===r||"1"===r;return i.detail(`Application spec: ${e} (from environment variable)`),es(t?.logger,e,"from environment variable"),e}return void 0!==o?(i.detail(`Application spec: ${o} (from package.json phoenix.applicationFlow)`),es(t?.logger,o,"from package.json phoenix.applicationFlow"),o):(i.detail("Application spec: false (default)"),es(t?.logger,!1,"default"),!1)},ep=t(s(a(c(import.meta.url)),"../../package.json"),"utf-8");if(!ep)throw Error("Project package.json is required, please provide it in the package.json file");let ed=v.object({version:v.string({required_error:"Project version is required, please provide it in the package.json file"}),name:v.string({required_error:"Project name is required, please provide it in the package.json file"})}).parse(JSON.parse(ep)),ec=async()=>{try{let e=await i("./package.json","utf-8"),o=JSON.parse(e);return{name:o.name,applicationFlow:o.phoenix?.applicationFlow}}catch{return{name:void 0,applicationFlow:void 0}}};await u(E(process.argv)).scriptName("phoenix").usage("$0 <command> [options]").command(["build","b"],"Build the project",e=>e.option("workspace",{alias:"w",type:"boolean",description:"Override workspace mode (uses .phoenix.json config by default)"}).option("editor",{type:"boolean",description:"Enable or disable editor files generation (defaults to ENABLE_EDITOR env or true)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, defaults to project name in package.json)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the environment (env: ENVIRONMENT_SLUG, defaults to project name in package.json)"}).option("onlyFrontend",{alias:"F",type:"boolean",description:"Build only frontend bundle"}).option("onlyWebhook",{alias:"W",type:"boolean",description:"Build only webhooks"}).option("force",{alias:"f",type:"boolean",description:"Force full rebuild, skip cache (env: FORCE_REBUILD, default: false)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}),async t=>{let i,r=f({PROJECT_SLUG:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),ENABLE_EDITOR:e({default:!0}),DEBUG:e({default:!1}),BUILD_TARGET:o({choices:["frontend","webhook","both"],default:"both"}),FORCE_REBUILD:e({default:!1})})(),n=ea({debug:t.debug??r.DEBUG}),a=en(t.editor,r.ENABLE_EDITOR),s=t.force??r.FORCE_REBUILD,l=await ec(),p=el(t.applicationSpec,l.applicationFlow,{logger:n}),d=t.projectSlug??r.PROJECT_SLUG??l.name,c=t.environmentSlug??r.ENVIRONMENT_SLUG??l.name;if(!d)throw Error("Project slug is required, provide via --projectSlug, set PROJECT_SLUG env, or ensure package.json has a name field");if(!c)throw Error("Environment slug is required, provide via --environmentSlug, set ENVIRONMENT_SLUG env, or ensure package.json has a name field");let u=t.onlyFrontend,E=t.onlyWebhook;if(u&&E)throw Error("Cannot use --onlyFrontend and --onlyWebhook flags together, they are mutually exclusive");i=u?"frontend":E?"webhook":r.BUILD_TARGET,await (p?U:y.runBuildCommand)({sdkVersion:ed.version,projectSlug:d,environmentSlug:c,cliUseWorkspace:t.workspace,enableEditor:a,buildTarget:i,force:s},{logger:n})}).command(["clean","cl"],"Clean build artifacts, reinstall dependencies, and rebuild specs",e=>e.option("workspace",{alias:"w",type:"boolean",description:"Override workspace mode (uses .phoenix.json config by default)"}).option("editor",{type:"boolean",description:"Enable or disable editor files generation (defaults to ENABLE_EDITOR env or true)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, defaults to project name in package.json)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the environment (env: ENVIRONMENT_SLUG, defaults to project name in package.json)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}),async t=>{let i=f({PROJECT_SLUG:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),ENABLE_EDITOR:e({default:!0}),DEBUG:e({default:!1})})(),r=ea({debug:t.debug??i.DEBUG}),n=en(t.editor,i.ENABLE_EDITOR),a=await ec(),s=el(t.applicationSpec,a.applicationFlow,{logger:r}),l=t.projectSlug??i.PROJECT_SLUG??a.name,p=t.environmentSlug??i.ENVIRONMENT_SLUG??a.name;if(!l)throw Error("Project slug is required, provide via --projectSlug, set PROJECT_SLUG env, or ensure package.json has a name field");if(!p)throw Error("Environment slug is required, provide via --environmentSlug, set ENVIRONMENT_SLUG env, or ensure package.json has a name field");await (s?b:y.runCleanCommand)({sdkVersion:ed.version,projectSlug:l,environmentSlug:p,cliUseWorkspace:t.workspace,enableEditor:n},{logger:r})}).command(["dev","d"],"Start development mode (Vite, spec watching, and the webhook tunnel)",e=>e.option("workspace",{alias:"w",type:"boolean",description:"Override workspace mode (uses .phoenix.json config by default)"}).option("editor",{type:"boolean",description:"Enable or disable editor files generation (defaults to ENABLE_EDITOR env or true)"}).option("editorWsPort",{alias:"ep",type:"string",description:"Port for the editor WebSocket server (defaults to EDITOR_WS_PORT env or 3020)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG; required in server mode unless --local; offline modes default to the package name)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the environment (env: ENVIRONMENT_SLUG; required in server mode unless --local; offline modes default to the package name)"}).option("withLingui",{alias:"wl",type:"boolean",description:"Enable or disable i18n messages extraction and compilation (defaults to WITH_LINGUI env or false)"}).option("persistence",{alias:"P",type:"string",description:"Persistence mode for the configurator (defaults to PERSISTENCE_MODE env or server)",choices:["memory","local-storage","server"]}).option("force",{alias:"f",type:"boolean",description:"Force full rebuild, skip cache (env: FORCE_REBUILD, default: false)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}).option("tui",{alias:"T",type:"boolean",description:"Render logs in a terminal UI with per-stream pages and split view; requires an interactive terminal (env: PHOENIX_TUI, default: false)"}).option("local",{type:"boolean",description:"Use local-mode development environment defaults (env: PHOENIX_LOCAL, default: false)"}).option("region",{choices:eo,description:`Phoenix region of the workspace you are signed in to, used when .env has no SERVER_URL (default: ${Z})`}).option("serverUrl",{type:"string",description:"URL of the Phoenix server, instead of SERVER_URL or the region default"}).option("skipUpload",{alias:"su",type:"boolean",description:"Skip upload of resources to S3 bucket when the development deployment is prepared (env: SKIP_UPLOAD, default: false)"}),async t=>{let i=f({ENABLE_EDITOR:e({default:!0}),PROJECT_SLUG:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),EDITOR_WS_PORT:o({default:"3020"}),DEBUG:e({default:!1}),WITH_LINGUI:e({default:!1}),PERSISTENCE_MODE:o({default:void 0}),FORCE_REBUILD:e({default:!1}),PHOENIX_TUI:e({default:!1}),SERVER_URL:o({default:void 0}),DEVELOPMENT_KEY:o({default:void 0}),PHOENIX_LOCAL:e({default:!1}),PHOENIX_REGION:o({choices:ee,default:void 0}),SKIP_UPLOAD:e({default:!1})})(),r=t.debug??i.DEBUG,n=ea({debug:r}),a=en(t.editor,i.ENABLE_EDITOR),s=t.editorWsPort??i.EDITOR_WS_PORT,l=t.force??i.FORCE_REBUILD,c=t.withLingui??i.WITH_LINGUI,u=t.persistence??i.PERSISTENCE_MODE,E=!u||"server"===u,v=t.tui??i.PHOENIX_TUI,m=await ec(),h=el(t.applicationSpec,m.applicationFlow,{logger:n}),S=t.local??i.PHOENIX_LOCAL,_=t.projectSlug??i.PROJECT_SLUG,U=E&&h&&!S&&!_?.length?await R(process.cwd()):void 0,{serverUrl:O,developmentKey:P,apiToken:b,projectSlug:L,environmentSlug:I}=await d({useServer:E,local:S,serverUrl:t.serverUrl??i.SERVER_URL,developmentKey:i.DEVELOPMENT_KEY,projectSlug:_?.length?_:U,environmentSlug:t.environmentSlug??i.ENVIRONMENT_SLUG}).with({useServer:!1},async({serverUrl:e,developmentKey:o,projectSlug:t,environmentSlug:i})=>({serverUrl:e,developmentKey:o,apiToken:void 0,projectSlug:t??m.name,environmentSlug:i??m.name})).with({local:!0},async({serverUrl:e,developmentKey:o,projectSlug:t,environmentSlug:i})=>({serverUrl:e?.length?e:"http://localhost:3000",developmentKey:o?.length?o:"dev_local-dev-key-12345",apiToken:void 0,projectSlug:t?.length?t:"local",environmentSlug:i?.length?i:"dev-local"})).with({developmentKey:p.string.minLength(1)},()=>U===g,()=>{throw Error(`phoenix dev has a DEVELOPMENT_KEY, but the spec says \`project: ${g}\`, which only a signed-in workspace can resolve. Set PROJECT_SLUG in .env by pasting the .env block of your Studio development environment, or name the project's slug in the spec.`)}).with({serverUrl:p.string.minLength(1),developmentKey:p.string.minLength(1),projectSlug:p.string.minLength(1),environmentSlug:p.string.minLength(1)},async({serverUrl:e,developmentKey:o,projectSlug:t,environmentSlug:i})=>({serverUrl:e,developmentKey:o,apiToken:void 0,projectSlug:t,environmentSlug:i})).with({developmentKey:p.union(void 0,""),projectSlug:p.string.minLength(1)},()=>h,async({serverUrl:e,projectSlug:o})=>{let r=e?.length?e:et(t.region??i.PHOENIX_REGION??Z),a=await er({serverUrl:r,project:o});return n.info(`Developing in ${a.projectSlug}/${a.environmentSlug} of workspace "${a.workspaceName}" on ${r}`),{serverUrl:r,developmentKey:void 0,apiToken:a.apiToken,projectSlug:a.projectSlug,environmentSlug:a.environmentSlug}}).with({developmentKey:p.union(void 0,""),projectSlug:p.union(void 0,"")},()=>h,()=>{throw Error(`phoenix dev does not know which project to develop in. Add \`project: ${g}\` to spec/application.yaml to use the default project of the workspace you are signed in to, or paste the .env block of a Studio development environment into .env. Pass --local to use the local-mode server.`)}).otherwise(()=>{throw Error("phoenix dev needs SERVER_URL, PROJECT_SLUG, ENVIRONMENT_SLUG, and DEVELOPMENT_KEY in .env. Create a development environment for your project in Studio and paste its .env block, or pass --local to use the local-mode server.")});if(!L)throw Error("Project slug is required, provide via --projectSlug, set PROJECT_SLUG env, or ensure package.json has a name field");if(!I)throw Error("Environment slug is required, provide via --environmentSlug, set ENVIRONMENT_SLUG env, or ensure package.json has a name field");let N={sdkVersion:ed.version,projectSlug:L,environmentSlug:I,cliUseWorkspace:t.workspace,enableEditor:a,editorWsPort:s,debug:r,withLingui:c,persistenceMode:u,force:l,tui:v,serverUrl:O,skipUpload:t.skipUpload??i.SKIP_UPLOAD};if(h){let e=P?{developmentKey:P}:b?{apiToken:b}:void 0;await k({...N,credential:e},{logger:n})}else await y.runDevCommand({...N,developmentKey:P},{logger:n})}).command(["link","l"],"Link local SDK for development",e=>e.option("sdk-path",{type:"string",description:"Path to the SDK repository",default:"../configurator-phoenix"}),async e=>{let o=ea();await M({sdkPath:e.sdkPath},{logger:o})}).command(["unlink","ul"],"Remove local SDK linking",()=>{},async()=>{let e=ea();await Q({logger:e})}).command(["sync","s"],"Sync project files and compile specs without building vite/webhooks",e=>e.option("workspace",{alias:"w",type:"boolean",description:"Override workspace mode (uses .phoenix.json config by default)"}).option("editor",{type:"boolean",description:"Enable or disable editor files generation (defaults to ENABLE_EDITOR env or true)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, defaults to project name in package.json)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the environment (env: ENVIRONMENT_SLUG, defaults to project name in package.json)"}).option("force",{alias:"f",type:"boolean",description:"Force full rebuild, skip cache (env: FORCE_REBUILD, default: false)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}).option("analyze",{alias:"a",type:"boolean",description:"Print pipeline metrics flamegraph after build (requires --applicationSpec)"}),async t=>{let i=f({ENABLE_EDITOR:e({default:!0}),DEBUG:e({default:!1}),PROJECT_SLUG:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),FORCE_REBUILD:e({default:!1})})(),r=ea({debug:t.debug??i.DEBUG}),n=en(t.editor,i.ENABLE_EDITOR),a=t.force??i.FORCE_REBUILD,s=await ec(),l=el(t.applicationSpec,s.applicationFlow,{logger:r}),p=t.projectSlug??i.PROJECT_SLUG??s.name,d=t.environmentSlug??i.ENVIRONMENT_SLUG??s.name;if(!p)throw Error("Project slug is required, provide via --projectSlug, set PROJECT_SLUG env, or ensure package.json has a name field");if(!d)throw Error("Environment slug is required, provide via --environmentSlug, set ENVIRONMENT_SLUG env, or ensure package.json has a name field");await (l?z:y.runSyncCommand)({sdkVersion:ed.version,projectSlug:p,environmentSlug:d,cliUseWorkspace:t.workspace,enableEditor:n,force:a,analyze:t.analyze},{logger:r})}).command("init [folder]","Start a Phoenix project: write package.json when the folder has none, a starter spec and pnpm-workspace.yaml with the pnpm settings the install needs. Continue with phoenix sync, phoenix login and phoenix dev",e=>e.positional("folder",{type:"string",description:"Folder to create the project in (default: the working directory)"}).option("scaffold",{type:"boolean",hidden:!0,description:"Accepted for compatibility and ignored: init always only writes the starter project"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging"}),async e=>{let o=ea({debug:e.debug??!1});try{await K({sdkVersion:ed.version,projectRoot:void 0===e.folder?void 0:l(e.folder)},{logger:o})}catch(e){o.error(e instanceof Error?e.message:String(e)),process.exit(1)}}).command(["story","st"],"Storybook example utilities",e=>$(e),()=>{}).command(["check","c"],"Run checks (TypeScript, ESLint, Prettier). Runs all by default, or only selected when any of --types/--lint/--format is passed.",e=>e.option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("types",{type:"boolean",description:"Run TypeScript check"}).option("lint",{type:"boolean",description:"Run ESLint check"}).option("format",{type:"boolean",description:"Run Prettier check"}),async o=>{let t=f({DEBUG:e({default:!1})})(),i=ea({debug:o.debug??t.DEBUG});await P({types:o.types,lint:o.lint,format:o.format},{logger:i})}).command(["fix","f"],"Fix linting and formatting issues. Runs all by default, or only selected when any of --lint/--format is passed.",e=>e.option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("lint",{type:"boolean",description:"Run ESLint fix"}).option("format",{type:"boolean",description:"Run Prettier fix"}),async o=>{let t=f({DEBUG:e({default:!1})})(),i=ea({debug:o.debug??t.DEBUG});await A({lint:o.lint,format:o.format},{logger:i})}).command(["changelog","clog"],"Display SDK changelog",e=>e.option("ver",{type:"string",description:"Show specific version (e.g., 0.36.0)"}).option("all",{alias:"a",type:"boolean",description:"Show all versions (warning: large output)"}).option("page",{alias:"p",type:"number",description:"Page number (3 versions per page)"}).option("list",{alias:"l",type:"boolean",description:"List version numbers only"}),async e=>{let o=ea();await O({version:e.ver,all:e.all,page:e.page,list:e.list},{logger:o})}).command(["inspect:assets","ia"],"Inspect 3D assets (glTF/GLB) — nodes, transforms, bounds, origin, materials, morph targets, animations",e=>e.option("file",{alias:"f",type:"string",description:"Path to specific glTF/GLB file"}).option("objects",{alias:"O",type:"boolean",description:"Show only object/node names"}).option("materials",{alias:"m",type:"boolean",description:"Show only material names"}).option("morphs",{alias:"M",type:"boolean",description:"Show only morph target names"}).option("animations",{alias:"a",type:"boolean",description:"Show only animation names"}).option("json",{alias:"j",type:"boolean",description:"Output as JSON"}),async e=>{let o=ea();await V({file:e.file,objects:e.objects,materials:e.materials,morphs:e.morphs,animations:e.animations,json:e.json},{logger:o})}).command(["screenshot","ss"],"Capture a screenshot of the configurator canvas",e=>e.option("port",{alias:"p",type:"string",description:"WebSocket server port (defaults to EDITOR_WS_PORT env or 3020)"}).option("output",{alias:"o",type:"string",description:"Output file path (defaults to SCREENSHOT_OUTPUT env or ./screenshot.png)"}).option("width",{alias:"w",type:"number",description:"Width in pixels (default: 1920)"}).option("height",{alias:"H",type:"number",description:"Height in pixels (default: 1080)"}).option("format",{alias:"f",type:"string",description:"Image format: PNG or JPEG (default: PNG)"}),async e=>{let t=f({EDITOR_WS_PORT:o({default:"3020"}),SCREENSHOT_OUTPUT:o({default:"./screenshot.png"})})(),i=ea();await W({port:e.port??t.EDITOR_WS_PORT,output:e.output??t.SCREENSHOT_OUTPUT,width:e.width,height:e.height,format:e.format},{logger:i})}).command(["inspect:state","is"],"Get the current editor state as JSON (entities, navigation, validation)",e=>e.option("port",{alias:"p",type:"string",description:"WebSocket server port (defaults to EDITOR_WS_PORT env or 3020)"}).option("output",{alias:"o",type:"string",description:"Output file path (prints to stdout if omitted)"}).option("sections",{alias:"s",type:"string",description:"Comma-separated sections: entities,navigation,validation (default: all)"}).option("pretty",{alias:"P",type:"boolean",description:"Pretty-print JSON output (default: true)",default:!0}),async e=>{let t=f({EDITOR_WS_PORT:o({default:"3020"})})(),i=ea();await X({port:e.port??t.EDITOR_WS_PORT,output:e.output,sections:e.sections,pretty:e.pretty},{logger:i})}).command(["inspect:data","id"],"Get the current editor context data as JSON (published, frontend, backend, session, access, web component)",e=>e.option("port",{alias:"p",type:"string",description:"WebSocket server port (defaults to EDITOR_WS_PORT env or 3020)"}).option("output",{alias:"o",type:"string",description:"Output file path (prints to stdout if omitted)"}).option("pretty",{alias:"P",type:"boolean",description:"Pretty-print JSON output (default: true)",default:!0}),async e=>{let t=f({EDITOR_WS_PORT:o({default:"3020"})})(),i=ea();await N({port:e.port??t.EDITOR_WS_PORT,output:e.output,pretty:e.pretty},{logger:i})}).command(["inspect:scene","isc"],"Get the current Three.js scene graph as JSON",e=>e.option("port",{alias:"p",type:"string",description:"WebSocket server port (defaults to EDITOR_WS_PORT env or 3020)"}).option("output",{alias:"o",type:"string",description:"Output file path (prints to stdout if omitted)"}).option("pretty",{alias:"P",type:"boolean",description:"Pretty-print JSON output (default: true)",default:!0}),async e=>{let t=f({EDITOR_WS_PORT:o({default:"3020"})})(),i=ea();await H({port:e.port??t.EDITOR_WS_PORT,output:e.output,pretty:e.pretty},{logger:i})}).command(["docs","doc"],"Browse SDK documentation",e=>e.option("read",{alias:"r",type:"string",description:"Read a specific doc file (e.g., docs/phoenix/admin.mdx)"}).option("category",{alias:"c",type:"string",description:"Show all docs in a category"}).option("list",{alias:"l",type:"boolean",description:"List all docs with paths and titles"}).option("search",{alias:"s",type:"string",description:"Search doc content for a term (case-insensitive)"}).option("dir",{type:"boolean",description:"Print the absolute path of the docs directory"}),async e=>{let o=ea();await D({read:e.read,category:e.category,list:e.list,search:e.search,dir:e.dir},{logger:o})}).command(["prepare:ci","pci","ci"],"Prepare CI environment by copying .env.ci to .env",()=>{},async()=>{let e=ea();await Y({logger:e})}).command({command:"environment:create",aliases:["env:create"],describe:"Create a new deployment environment",deprecated:"Switch to a new workflow and use deployment:prepare instead",builder:e=>e.option("server",{alias:"s",type:"string",description:"URL of the Phoenix server (defaults to SERVER_URL env)"}).option("apiKey",{alias:"k",type:"string",description:"API key for server access (defaults to ENVIRONMENT_API_KEY env)"}).option("name",{alias:"n",type:"string",description:"Name of the environment to be created"}).option("slug",{type:"string",description:"Slug of the customer to be created"}).option("uuid",{alias:"u",type:"string",description:"UUID of the environment to be created"}).option("outFile",{alias:"o",type:"string",description:"Output file to write the environment UUID to",default:".env.generated"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}),handler:async o=>{let t=f({DEBUG:e({default:!1})})(),i=o.debug??t.DEBUG,r=ea({debug:i});await I({server:o.server,apiKey:o.apiKey,name:o.name,slug:o.slug,uuid:o.uuid,outFile:o.outFile,debug:i},{logger:r})}}).command({command:"environment:list",aliases:["env:list"],describe:"List all deployment environments",deprecated:"Switch to a new workflow and use the prepare environment flow instead",builder:e=>e.option("server",{alias:"s",type:"string",description:"URL of the Phoenix server (defaults to SERVER_URL env)"}).option("apiKey",{alias:"k",type:"string",description:"API key for server access (defaults to ENVIRONMENT_API_KEY env)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}),handler:async o=>{let t=f({DEBUG:e({default:!1})})(),i=o.debug??t.DEBUG,r=ea({debug:i});await J({server:o.server,apiKey:o.apiKey,debug:i},{logger:r})}}).command(["environment:cleanup","env:cleanup","ec"],"Cleanup a transient deployment environment",e=>e.option("serverUrl",{alias:"su",type:"string",description:"URL of the Phoenix server (defaults to SERVER_URL env)"}).option("apiKey",{alias:"a",type:"string",description:"API key for server access (env: ENVIRONMENT_API_KEY, required)"}).option("projectKey",{alias:"k",type:"string",description:"Project key (env: PROJECT_KEY, required)"}).option("projectSlug",{alias:"p",type:"string",description:"Project slug (env: PROJECT_SLUG, required)"}).option("environmentSlug",{alias:"e",type:"string",description:"Environment slug (env: ENVIRONMENT_SLUG, defaults to project name in package.json)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("outFile",{alias:"o",type:"string",description:"Output file to write cleanup result env variables to (env: OUT_FILE, default: .env.generated)",default:".env.generated"}),async t=>{let i=f({DEBUG:e({default:!1}),ENVIRONMENT_API_KEY:o({default:void 0}),PROJECT_KEY:o({default:void 0}),PROJECT_SLUG:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),SERVER_URL:o({default:void 0}),OUT_FILE:o({default:void 0})})(),r=t.debug??i.DEBUG,n=t.apiKey??i.ENVIRONMENT_API_KEY,a=t.projectKey??i.PROJECT_KEY,s=t.projectSlug??i.PROJECT_SLUG,l=await ec(),p=t.environmentSlug??i.ENVIRONMENT_SLUG??l.name,d=t.serverUrl??i.SERVER_URL,c=t.outFile??i.OUT_FILE??".env.generated";if(!n)throw Error("API key is required, provide via --apiKey or -a, or set ENVIRONMENT_API_KEY environment variable");if(!a)throw Error("Project key is required, provide via --projectKey or -k, or set PROJECT_KEY environment variable");if(!s)throw Error("Project slug is required, provide via --projectSlug or -p, or set PROJECT_SLUG environment variable");if(!p)throw Error("Environment slug is required, provide via --environmentSlug or -e, or set ENVIRONMENT_SLUG environment variable");if(!d)throw Error("Server URL is required, provide via --serverUrl or -su, or set SERVER_URL environment variable");let u=ea({debug:r});await L({server:d,apiKey:n,projectKey:a,projectSlug:s,environmentSlug:p,debug:r,outFile:c},{logger:u})}).command(["login <customer>"],"Sign the CLI in to an SDK-builder workspace; you approve it in Studio",e=>e.positional("customer",{type:"string",demandOption:!0,description:"Slug of the SDK-builder workspace (customer)"}).option("region",{choices:eo,description:`Phoenix region the workspace lives in (default: ${Z})`}).option("serverUrl",{alias:"su",type:"string",description:"URL of the Phoenix server, instead of the region default"}).option("studioUrl",{type:"string",description:"URL of Studio for the workspace, instead of the region default"}).option("open",{type:"boolean",default:!0,description:"Open the approval page in the default browser (--no-open to only print the link)"}),async e=>{let t=f({PHOENIX_REGION:o({choices:ee,default:void 0})})(),i=e.region??t.PHOENIX_REGION??Z;await B({customer:e.customer,serverUrl:e.serverUrl??et(i),studioUrl:e.studioUrl??ei(i,e.customer),open:e.open},{logger:ea()})}).command(["deploy"],"Upload this SDK-builder project and follow its build until it is live",e=>e.option("region",{choices:eo,description:`Phoenix region the workspace lives in (default: ${Z})`}).option("serverUrl",{alias:"su",type:"string",description:"URL of the Phoenix server, instead of the region default"}).option("wait",{type:"boolean",default:!0,description:"Follow the build until it finishes (--no-wait to return once it starts)"}),async e=>{let t=f({PHOENIX_REGION:o({choices:ee,default:void 0})})(),i=e.region??t.PHOENIX_REGION??Z;await T({serverUrl:e.serverUrl??et(i),sdkVersion:ed.version,wait:e.wait,projectDir:process.cwd(),pollIntervalMs:3e3},{logger:ea()})}).command(["logout"],"Revoke the API token of an SDK-builder workspace and forget it on this computer",e=>e.option("region",{choices:eo,description:`Phoenix region to sign out of (default: ${Z})`}).option("serverUrl",{alias:"su",type:"string",description:"URL of the Phoenix server, instead of the region default"}),async e=>{let t=f({PHOENIX_REGION:o({choices:ee,default:void 0})})(),i=e.region??t.PHOENIX_REGION??Z;await F({serverUrl:e.serverUrl??et(i)},{logger:ea()})}).command(["feedback <message>"],"Send feedback about the SDK, CLI, docs or Studio to the Phoenix team",e=>e.positional("message",{type:"string",demandOption:!0,description:"What you want to tell the Phoenix team"}).option("type",{choices:[m.Bug,m.Idea,m.Other],default:m.Other,description:"What the feedback is about"}).option("contact",{type:"string",description:"How to reach you, when you want a reply"}).option("agent",{type:"string",description:"Name of the coding agent that writes the feedback"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the workspace project the feedback is about (env: PROJECT_SLUG, defaults to `project` of the application spec)"}).option("region",{choices:eo,description:`Phoenix region the workspace lives in (default: ${Z})`}).option("serverUrl",{alias:"su",type:"string",description:"URL of the Phoenix server, instead of the region default"}),async e=>{let t=f({PHOENIX_REGION:o({choices:ee,default:void 0}),PROJECT_SLUG:o({default:void 0})})(),i=ea(),a=e.region??t.PHOENIX_REGION??Z,s=e.projectSlug??t.PROJECT_SLUG,l=s?.length?s:await R(process.cwd()).catch(()=>{i.warn("The feedback is sent without a project, because `project` could not be read from the application spec. Pass --projectSlug to name the project.")});await G({serverUrl:e.serverUrl??et(a),message:e.message,type:e.type,contact:e.contact,agent:e.agent,project:l,sdkVersion:ed.version,clientInfo:`${n()} ${r()}, Node.js ${process.versions.node}`},{logger:i})}).command({command:"deployment:register",aliases:["dep:register","dr"],describe:"Register deployment configuration",deprecated:"Switch to a new workflow and use deployment:prepare and deployment:finish instead",builder:e=>e.option("server",{alias:"s",type:"string",description:"URL of the Phoenix server (defaults to SERVER_URL env)"}).option("apiKey",{alias:"k",type:"string",description:"API key for server access (defaults to ENVIRONMENT_API_KEY env)"}).option("outFile",{alias:"o",type:"string",description:"Output file to write the deployment ID to",default:".env.generated"}).option("skipUpload",{alias:"su",type:"boolean",description:"Skip uploading assets",default:!1}).option("activate",{alias:"a",type:"boolean",description:"Activate deployment after registration",default:!0}).option("overrideSchema",{alias:"os",type:"boolean",description:"Override existing schema",default:!1}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}),handler:async o=>{let t=f({DEBUG:e({default:!1})})(),i=o.debug??t.DEBUG,r=ea({debug:i});await x({server:o.server,apiKey:o.apiKey,outFile:o.outFile,skipUpload:o.skipUpload,activate:o.activate,overrideSchema:o.overrideSchema,debug:i},{logger:r})}}).command({command:"deployment:activate",aliases:["dep:activate","da"],describe:"Activate a deployment",deprecated:"Switch to a new workflow and use deployment:prepare and deployment:finish instead",builder:e=>e.option("server",{alias:"s",type:"string",description:"URL of the Phoenix server (defaults to SERVER_URL env)"}).option("apiKey",{alias:"k",type:"string",description:"API key for server access (defaults to ENVIRONMENT_API_KEY env)"}).option("uuid",{alias:"u",type:"string",description:"UUID of the deployment to activate"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}),handler:async o=>{let t=f({DEBUG:e({default:!1})})(),i=o.debug??t.DEBUG,r=ea({debug:i});await _({server:o.server,apiKey:o.apiKey,uuid:o.uuid,debug:i},{logger:r})}}).command(["deployment:prepare","dep:prepare","dp"],"Prepare environment and register deployment (env: ENVIRONMENT_API_KEY, PROJECT_KEY, PROJECT_SLUG, PROJECT_REF, PROJECT_SHA, ENVIRONMENT_SLUG, OUT_FILE, SKIP_UPLOAD, OVERRIDE_SCHEMA, SERVER_URL)",e=>e.option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, required)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the environment (will be created if it does not exist) (env: ENVIRONMENT_SLUG, required)"}).option("projectRef",{type:"string",description:"Source branch, tag, or ref recorded as deployment provenance (env: PROJECT_REF)"}).option("projectSha",{type:"string",description:"Full commit SHA of the checked-out project revision (env: PROJECT_SHA)"}).option("outFile",{alias:"o",type:"string",description:"Output file to write the environment variables to (env: OUT_FILE, default: .env.generated)"}).option("skipUpload",{alias:"su",type:"boolean",description:"Skip upload of resources to S3 bucket (env: SKIP_UPLOAD, default: false)"}).option("overrideSchema",{alias:"os",type:"boolean",description:"Allows to override deployment schemas (env: OVERRIDE_SCHEMA, default: false)"}).option("apiKey",{alias:"a",type:"string",description:"API key for server access (env: ENVIRONMENT_API_KEY, required)"}).option("projectKey",{alias:"k",type:"string",description:"Project key to access the Project resources (env: PROJECT_KEY, required)"}).option("uploadLinksFile",{alias:"ulf",type:"string",description:"File to write upload links to (used by finish command) (default: .upload-links.json)"}).option("serverUrl",{alias:"s",type:"string",description:"PHX server URL (env: SERVER_URL, required)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (env: DEBUG, default: false)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}),async t=>{let i=f({DEBUG:e({default:!1}),ENVIRONMENT_API_KEY:o({default:void 0}),PROJECT_KEY:o({default:void 0}),PROJECT_SLUG:o({default:void 0}),PROJECT_REF:o({default:void 0}),PROJECT_SHA:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),OUT_FILE:o({default:".env.generated"}),SKIP_UPLOAD:e({default:!1}),OVERRIDE_SCHEMA:e({default:!1}),SERVER_URL:o({default:void 0})})(),r=t.debug??i.DEBUG,n=t.apiKey??i.ENVIRONMENT_API_KEY;if(!n)throw Error("API key is required, provide via --apiKey or -a, or set ENVIRONMENT_API_KEY environment variable");let a=t.projectKey??i.PROJECT_KEY;if(!a)throw Error("Project key is required, provide via --projectKey or -k, or set PROJECT_KEY environment variable");let s=t.projectSlug??i.PROJECT_SLUG;if(!s)throw Error("Project slug is required, provide via --projectSlug or -p, or set PROJECT_SLUG environment variable");let l=t.environmentSlug??i.ENVIRONMENT_SLUG;if(!l)throw Error("Environment slug is required, provide via --environmentSlug or -e, or set ENVIRONMENT_SLUG environment variable");let p=t.serverUrl??i.SERVER_URL;if(!p)throw Error("Server URL is required, provide via --serverUrl or -s, or set SERVER_URL environment variable");let d=await ec(),c=ea({debug:r}),u=el(t.applicationSpec,d.applicationFlow,{logger:c});await (u?q:y.runPrepareDeploymentCommand)({apiKey:n,projectKey:a,projectSlug:s,projectRef:t.projectRef??i.PROJECT_REF,projectSha:t.projectSha??i.PROJECT_SHA,environmentSlug:l,outFile:t.outFile??i.OUT_FILE,skipUpload:t.skipUpload??i.SKIP_UPLOAD,overrideSchema:t.overrideSchema??i.OVERRIDE_SCHEMA,uploadLinksFile:t.uploadLinksFile??".upload-links.json",serverUrl:p,debug:r,projectVersion:ed.version},{logger:c})}).command(["deployment:prepare-dev","dep:prepare-dev","dpd"],"Prepare a development deployment (env: SERVER_URL, PROJECT_SLUG, ENVIRONMENT_SLUG, DEVELOPMENT_KEY, OUT_FILE, SKIP_UPLOAD, OVERRIDE_SCHEMA)",e=>e.option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, required unless --local)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the development environment (env: ENVIRONMENT_SLUG, required unless --local)"}).option("outFile",{alias:"o",type:"string",description:"Output file to write the environment variables to (env: OUT_FILE, default: .env.generated)"}).option("skipUpload",{alias:"su",type:"boolean",description:"Skip upload of resources to S3 bucket (env: SKIP_UPLOAD, default: false)"}).option("overrideSchema",{alias:"os",type:"boolean",description:"Allows overriding deployment schemas (env: OVERRIDE_SCHEMA, default: true)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (env: DEBUG, default: false)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}).option("local",{type:"boolean",description:"Use local-mode development environment defaults (env: PHOENIX_LOCAL, default: false)"}),async t=>{let i=f({DEBUG:e({default:!1}),PROJECT_SLUG:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),SERVER_URL:o({default:void 0}),DEVELOPMENT_KEY:o({default:void 0}),PHOENIX_LOCAL:e({default:!1}),OUT_FILE:o({default:".env.generated"}),SKIP_UPLOAD:e({default:!1}),OVERRIDE_SCHEMA:e({default:!0})})(),r=t.debug??i.DEBUG,n=ea({debug:r}),a=t.local??i.PHOENIX_LOCAL,s=i.SERVER_URL,l=t.projectSlug??i.PROJECT_SLUG,p=t.environmentSlug??i.ENVIRONMENT_SLUG,d=i.DEVELOPMENT_KEY;if(a&&(s=s?.length?s:"http://localhost:3000",l=l?.length?l:"local",p=p?.length?p:"dev-local",d=d?.length?d:"dev_local-dev-key-12345"),!s||!l||!p||!d)throw Error("phoenix deployment:prepare-dev needs SERVER_URL, PROJECT_SLUG, ENVIRONMENT_SLUG, and DEVELOPMENT_KEY in .env. Create a development environment for your project in Studio and paste its .env block, or pass --local to use the local-mode server.");let c=await ec(),u=el(t.applicationSpec,c.applicationFlow,{logger:n}),E={serverUrl:s,projectSlug:l,environmentSlug:p,outFile:t.outFile??i.OUT_FILE,skipUpload:t.skipUpload??i.SKIP_UPLOAD,overrideSchema:t.overrideSchema??i.OVERRIDE_SCHEMA,debug:r,projectVersion:ed.version};try{u?await h({...E,credential:{developmentKey:d}},{logger:n}):await y.prepareDevelopmentEnvironment({...E,developmentKey:d},{logger:n})}catch(e){n.error(`Development environment preparation failed: ${e instanceof Error?e.message:String(e)}`,e),process.exit(1)}}).command(["deployment:prepare-local","dep:prepare-local","dpl"],"Prepare local environment for development (env: PROJECT_KEY, PROJECT_SLUG, OUT_FILE, SKIP_UPLOAD, OVERRIDE_SCHEMA, SERVER_URL, LAMBDA_URL)",e=>e.option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, default: local)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the environment (env: ENVIRONMENT_SLUG, default: project name in package.json)"}).option("outFile",{alias:"o",type:"string",description:"Output file to write the environment variables to (env: OUT_FILE, default: .env.generated)"}).option("skipUpload",{alias:"su",type:"boolean",description:"Skip upload of resources to S3 bucket (env: SKIP_UPLOAD, default: false)"}).option("overrideSchema",{alias:"os",type:"boolean",description:"Allows to override deployment schemas (env: OVERRIDE_SCHEMA, default: true)"}).option("projectKey",{alias:"k",type:"string",description:"Project key to access the Project resources (env: PROJECT_KEY, required)"}).option("serverUrl",{alias:"s",type:"string",description:"PHX server URL (env: SERVER_URL, default: http://localhost:3000)"}).option("lambdaUrl",{alias:"l",type:"string",description:"Webhook URL (env: LAMBDA_URL, default: http://localhost:8080)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (env: DEBUG, default: false)"}).option("apiKey",{alias:"a",type:"string",description:"API key for server access (env: ENVIRONMENT_API_KEY, required)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}),async t=>{let i=f({DEBUG:e({default:!1}),ENVIRONMENT_SLUG:o({default:void 0}),PROJECT_KEY:o({default:"project_local-dev-key-12345"}),PROJECT_SLUG:o({default:"local"}),OUT_FILE:o({default:".env.generated"}),SKIP_UPLOAD:e({default:!1}),OVERRIDE_SCHEMA:e({default:!0}),SERVER_URL:o({default:"http://localhost:3000"}),LAMBDA_URL:o({default:"http://localhost:8080"}),ENVIRONMENT_API_KEY:o({default:"local-dev-key-12345"})})(),r=t.debug??i.DEBUG,n=t.projectKey??i.PROJECT_KEY;if(!n)throw Error("Project key is required, provide via --projectKey or -k, or set PROJECT_KEY environment variable");let a=await ec(),s=t.environmentSlug??i.ENVIRONMENT_SLUG??a.name;if(!s)throw Error("Environment slug is required, provide via --environmentSlug or -e, or set ENVIRONMENT_SLUG environment variable");let l=t.apiKey??i.ENVIRONMENT_API_KEY;if(!l)throw Error("API key is required, provide via --apiKey or -a, or set ENVIRONMENT_API_KEY environment variable");let p=ea({debug:r}),d=el(t.applicationSpec,a.applicationFlow,{logger:p});try{await (d?S:y.prepareLocalEnvironment)({apiKey:l,projectKey:n,projectSlug:t.projectSlug??i.PROJECT_SLUG,environmentSlug:s,outFile:t.outFile??i.OUT_FILE,skipUpload:t.skipUpload??i.SKIP_UPLOAD,overrideSchema:t.overrideSchema??i.OVERRIDE_SCHEMA,serverUrl:t.serverUrl??i.SERVER_URL,lambdaUrl:t.lambdaUrl??i.LAMBDA_URL,debug:r,projectVersion:ed.version},{logger:p})}catch(e){p.error(`Local environment preparation failed: ${e instanceof Error?e.message:String(e)}`,e),process.exit(1)}}).command(["deployment:extract-sources <archive> <folder>"],"Validate the source archive of a phoenix deploy and extract its project files into a new folder. Links, special files, unsafe paths and oversized content are refused; entries that are not project files are left out",e=>e.positional("archive",{type:"string",demandOption:!0,description:"The source archive (.tgz)"}).positional("folder",{type:"string",demandOption:!0,description:"New or empty folder to extract the project files into"}),async e=>{let o=ea();try{await j({archivePath:e.archive,targetDir:e.folder},{logger:o})}catch(e){o.error(e instanceof Error?e.message:String(e)),process.exit(1)}}).command(["deployment:build-envs","dep:build-envs","dbe"],"Write the environment variables for the build step of a prepared deployment that builds apart from its deploy (env: DEPLOYMENT_ID, ENVIRONMENT_API_KEY, PROJECT_KEY, PROJECT_SLUG, OUT_FILE, SERVER_URL)",e=>e.option("uuid",{alias:"u",type:"string",description:"Id of the prepared deployment (env: DEPLOYMENT_ID, required)"}).option("outFile",{alias:"o",type:"string",description:"Output file to write the environment variables to (env: OUT_FILE, default: .env.generated)"}).option("apiKey",{alias:"a",type:"string",description:"API key for server access (env: ENVIRONMENT_API_KEY, required)"}).option("projectKey",{alias:"k",type:"string",description:"Project key to access the Project resources (env: PROJECT_KEY, required)"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, required)"}).option("serverUrl",{alias:"s",type:"string",description:"PHX server URL (env: SERVER_URL, required)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (env: DEBUG, default: false)"}),async t=>{let i=f({DEBUG:e({default:!1}),DEPLOYMENT_ID:o({default:void 0}),ENVIRONMENT_API_KEY:o({default:void 0}),PROJECT_KEY:o({default:void 0}),PROJECT_SLUG:o({default:void 0}),OUT_FILE:o({default:".env.generated"}),SERVER_URL:o({default:void 0})})(),r=t.debug??i.DEBUG,n=t.uuid??i.DEPLOYMENT_ID;if(!n)throw Error("Deployment ID is required, provide via --uuid or -u, or set DEPLOYMENT_ID environment variable");let a=t.apiKey??i.ENVIRONMENT_API_KEY;if(!a)throw Error("API key is required, provide via --apiKey or -a, or set ENVIRONMENT_API_KEY environment variable");let s=t.projectKey??i.PROJECT_KEY;if(!s)throw Error("Project key is required, provide via --projectKey or -k, or set PROJECT_KEY environment variable");let l=t.projectSlug??i.PROJECT_SLUG;if(!l)throw Error("Project slug is required, provide via --projectSlug or -p, or set PROJECT_SLUG environment variable");let p=t.serverUrl??i.SERVER_URL;if(!p)throw Error("Server URL is required, provide via --serverUrl or -s, or set SERVER_URL environment variable");let d=ea({debug:r});await w({uuid:n,apiKey:a,projectKey:s,projectSlug:l,outFile:t.outFile??i.OUT_FILE,serverUrl:p,debug:r},{logger:d})}).command(["deployment:finish","dep:finish","df"],"Upload files to S3 and activate deployment (env: DEPLOYMENT_ID, ENVIRONMENT_API_KEY, PROJECT_KEY, PROJECT_SLUG, LAMBDA_URL, SERVER_URL, SKIP_UPLOAD)",e=>e.option("uuid",{alias:"u",type:"string",description:"Id of the deployment to be activated (env: DEPLOYMENT_ID, required)"}).option("uploadLinksFile",{alias:"ulf",type:"string",description:"File containing upload links (generated by prepare command) (default: .upload-links.json)"}).option("apiKey",{alias:"a",type:"string",description:"API key for server access (env: ENVIRONMENT_API_KEY, required)"}).option("projectKey",{alias:"k",type:"string",description:"Project key to access the Project resources (env: PROJECT_KEY, required)"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, required)"}).option("lambdaUrl",{alias:"l",type:"string",description:"Lambda webhook URL for the deployment (env: LAMBDA_URL, required)"}).option("serverUrl",{alias:"s",type:"string",description:"PHX server URL (env: SERVER_URL, required)"}).option("skipUpload",{alias:"su",type:"boolean",description:"Skip upload of resources to S3 bucket (env: SKIP_UPLOAD, default: false)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (env: DEBUG, default: false)"}),async t=>{let i=f({DEBUG:e({default:!1}),DEPLOYMENT_ID:o({default:void 0}),ENVIRONMENT_API_KEY:o({default:void 0}),PROJECT_KEY:o({default:void 0}),PROJECT_SLUG:o({default:void 0}),LAMBDA_URL:o({default:void 0}),SERVER_URL:o({default:void 0}),SKIP_UPLOAD:e({default:!1})})(),r=t.debug??i.DEBUG,n=t.uuid??i.DEPLOYMENT_ID;if(!n)throw Error("Deployment ID is required, provide via --uuid or -u, or set DEPLOYMENT_ID environment variable");let a=t.apiKey??i.ENVIRONMENT_API_KEY;if(!a)throw Error("API key is required, provide via --apiKey or -a, or set ENVIRONMENT_API_KEY environment variable");let s=t.projectKey??i.PROJECT_KEY;if(!s)throw Error("Project key is required, provide via --projectKey or -k, or set PROJECT_KEY environment variable");let l=t.projectSlug??i.PROJECT_SLUG;if(!l)throw Error("Project slug is required, provide via --projectSlug or -p, or set PROJECT_SLUG environment variable");let p=t.lambdaUrl??i.LAMBDA_URL;if(!p)throw Error("Lambda URL is required, provide via --lambdaUrl or -l, or set LAMBDA_URL environment variable");let d=t.serverUrl??i.SERVER_URL;if(!d)throw Error("Server URL is required, provide via --serverUrl or -s, or set SERVER_URL environment variable");let c=ea({debug:r});await C({uuid:n,uploadLinksFile:t.uploadLinksFile??".upload-links.json",apiKey:a,projectKey:s,projectSlug:l,lambdaUrl:p,serverUrl:d,skipUpload:t.skipUpload??i.SKIP_UPLOAD,debug:r},{logger:c})}).demandCommand(1,"Please specify a command").help().alias("help","h").version(ed.version).alias("version","v").strict().parse();
|
|
2
|
+
import{bool as e,str as o}from"envalid";import{readFileSync as t}from"fs";import{readFile as i}from"fs/promises";import{arch as r,platform as n}from"os";import{dirname as a,join as s,resolve as l}from"path";import{P as p,match as d}from"ts-pattern";import{fileURLToPath as c}from"url";import u from"yargs";import{hideBin as E}from"yargs/helpers";import{z as v}from"zod";import{createEnvReader as f}from"@salsita-ai/common/env";import{DEFAULT_PROJECT_ALIAS as g,FeedbackType as m}from"@salsita-ai/contracts/domain";import{phoenixCli as y}from"#package/legacy";import{readSpecProject as h}from"./application-spec/read-spec-project.js";import{prepareDevelopmentEnvironment as R,prepareLocalEnvironment as S,runActivateDeploymentCommand as _,runBuildCommand as U,runChangelogCommand as O,runCheckCommand as P,runCleanCommand as b,runCleanupEnvironmentCommand as L,runCreateEnvironmentCommand as I,runDataCommand as N,runDeployCommand as T,runDeploymentBuildEnvsCommand as w,runDevCommand as k,runDocsCommand as D,runExtractSourcesCommand as j,runFeedbackCommand as G,runFinishDeploymentCommand as C,runFixCommand as A,runInitCommand as K,runInspectAssetsCommand as V,runLinkCommand as M,runListEnvironmentsCommand as J,runLoginCommand as B,runLogoutCommand as F,runPrepareCiCommand as Y,runPrepareDeploymentCommand as q,runRegisterDeploymentCommand as x,runSceneCommand as H,runScreenshotCommand as W,runStateCommand as $,runStoryCommand as X,runSyncCommand as z,runUnlinkCommand as Q}from"./commands/index.js";import{DEFAULT_PHOENIX_REGION as Z,PHOENIX_REGIONS as ee,PUBLIC_PHOENIX_REGIONS as eo,getRegionServerUrl as et,getRegionStudioUrl as ei,resolveSignedInDevelopmentEnvironment as er}from"./services/index.js";import{getIsEditorEnabled as en}from"./utils/get-is-editor-enabled.js";import{createLogger as ea}from"./utils/index.js";let es=(e,o,t)=>{e?.info(`Using ${o?"application-spec":"domain-spec"} flow (${t})`)},el=(e,o,t)=>{let i=t?.logger??ea();if(void 0!==e)return i.detail(`Application spec: ${e} (from CLI flag)`),es(t?.logger,e,"from CLI flag"),e;let r=process.env.USE_APPLICATION_SPEC;if(void 0!==r){let e="true"===r||"1"===r;return i.detail(`Application spec: ${e} (from environment variable)`),es(t?.logger,e,"from environment variable"),e}return void 0!==o?(i.detail(`Application spec: ${o} (from package.json phoenix.applicationFlow)`),es(t?.logger,o,"from package.json phoenix.applicationFlow"),o):(i.detail("Application spec: false (default)"),es(t?.logger,!1,"default"),!1)},ep=t(s(a(c(import.meta.url)),"../../package.json"),"utf-8");if(!ep)throw Error("Project package.json is required, please provide it in the package.json file");let ed=v.object({version:v.string({required_error:"Project version is required, please provide it in the package.json file"}),name:v.string({required_error:"Project name is required, please provide it in the package.json file"})}).parse(JSON.parse(ep)),ec=async()=>{try{let e=await i("./package.json","utf-8"),o=JSON.parse(e);return{name:o.name,applicationFlow:o.phoenix?.applicationFlow}}catch{return{name:void 0,applicationFlow:void 0}}},eu=e=>{if(!(e instanceof Error))return String(e);let o=(e=>{if(!(e instanceof Error))return;if(e.message.length>0)return e.message;let o=(e instanceof AggregateError?e.errors:[]).find(e=>e instanceof Error&&e.message.length>0);return o instanceof Error?o.message:"code"in e&&"string"==typeof e.code?e.code:void 0})(e.cause);return void 0===o?e.message:`${e.message}: ${o}`};await u(E(process.argv)).scriptName("phoenix").usage("$0 <command> [options]").command(["build","b"],"Build the project",e=>e.option("workspace",{alias:"w",type:"boolean",description:"Override workspace mode (uses .phoenix.json config by default)"}).option("editor",{type:"boolean",description:"Enable or disable editor files generation (defaults to ENABLE_EDITOR env or true)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, defaults to project name in package.json)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the environment (env: ENVIRONMENT_SLUG, defaults to project name in package.json)"}).option("onlyFrontend",{alias:"F",type:"boolean",description:"Build only frontend bundle"}).option("onlyWebhook",{alias:"W",type:"boolean",description:"Build only webhooks"}).option("force",{alias:"f",type:"boolean",description:"Force full rebuild, skip cache (env: FORCE_REBUILD, default: false)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}),async t=>{let i,r=f({PROJECT_SLUG:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),ENABLE_EDITOR:e({default:!0}),DEBUG:e({default:!1}),BUILD_TARGET:o({choices:["frontend","webhook","both"],default:"both"}),FORCE_REBUILD:e({default:!1})})(),n=ea({debug:t.debug??r.DEBUG}),a=en(t.editor,r.ENABLE_EDITOR),s=t.force??r.FORCE_REBUILD,l=await ec(),p=el(t.applicationSpec,l.applicationFlow,{logger:n}),d=t.projectSlug??r.PROJECT_SLUG??l.name,c=t.environmentSlug??r.ENVIRONMENT_SLUG??l.name;if(!d)throw Error("Project slug is required, provide via --projectSlug, set PROJECT_SLUG env, or ensure package.json has a name field");if(!c)throw Error("Environment slug is required, provide via --environmentSlug, set ENVIRONMENT_SLUG env, or ensure package.json has a name field");let u=t.onlyFrontend,E=t.onlyWebhook;if(u&&E)throw Error("Cannot use --onlyFrontend and --onlyWebhook flags together, they are mutually exclusive");i=u?"frontend":E?"webhook":r.BUILD_TARGET,await (p?U:y.runBuildCommand)({sdkVersion:ed.version,projectSlug:d,environmentSlug:c,cliUseWorkspace:t.workspace,enableEditor:a,buildTarget:i,force:s},{logger:n})}).command(["clean","cl"],"Clean build artifacts, reinstall dependencies, and rebuild specs",e=>e.option("workspace",{alias:"w",type:"boolean",description:"Override workspace mode (uses .phoenix.json config by default)"}).option("editor",{type:"boolean",description:"Enable or disable editor files generation (defaults to ENABLE_EDITOR env or true)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, defaults to project name in package.json)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the environment (env: ENVIRONMENT_SLUG, defaults to project name in package.json)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}),async t=>{let i=f({PROJECT_SLUG:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),ENABLE_EDITOR:e({default:!0}),DEBUG:e({default:!1})})(),r=ea({debug:t.debug??i.DEBUG}),n=en(t.editor,i.ENABLE_EDITOR),a=await ec(),s=el(t.applicationSpec,a.applicationFlow,{logger:r}),l=t.projectSlug??i.PROJECT_SLUG??a.name,p=t.environmentSlug??i.ENVIRONMENT_SLUG??a.name;if(!l)throw Error("Project slug is required, provide via --projectSlug, set PROJECT_SLUG env, or ensure package.json has a name field");if(!p)throw Error("Environment slug is required, provide via --environmentSlug, set ENVIRONMENT_SLUG env, or ensure package.json has a name field");await (s?b:y.runCleanCommand)({sdkVersion:ed.version,projectSlug:l,environmentSlug:p,cliUseWorkspace:t.workspace,enableEditor:n},{logger:r})}).command(["dev","d"],"Start development mode (Vite, spec watching, and the webhook tunnel)",e=>e.option("workspace",{alias:"w",type:"boolean",description:"Override workspace mode (uses .phoenix.json config by default)"}).option("editor",{type:"boolean",description:"Enable or disable editor files generation (defaults to ENABLE_EDITOR env or true)"}).option("editorWsPort",{alias:"ep",type:"string",description:"Port for the editor WebSocket server (defaults to EDITOR_WS_PORT env or 3020)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG; required in server mode unless --local; offline modes default to the package name)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the environment (env: ENVIRONMENT_SLUG; required in server mode unless --local; offline modes default to the package name)"}).option("withLingui",{alias:"wl",type:"boolean",description:"Enable or disable i18n messages extraction and compilation (defaults to WITH_LINGUI env or false)"}).option("persistence",{alias:"P",type:"string",description:"Persistence mode for the configurator (defaults to PERSISTENCE_MODE env or server)",choices:["memory","local-storage","server"]}).option("force",{alias:"f",type:"boolean",description:"Force full rebuild, skip cache (env: FORCE_REBUILD, default: false)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}).option("tui",{alias:"T",type:"boolean",description:"Render logs in a terminal UI with per-stream pages and split view; requires an interactive terminal (env: PHOENIX_TUI, default: false)"}).option("local",{type:"boolean",description:"Use local-mode development environment defaults (env: PHOENIX_LOCAL, default: false)"}).option("region",{choices:eo,description:`Phoenix region of the workspace you are signed in to, used when .env has no SERVER_URL (default: ${Z})`}).option("serverUrl",{type:"string",description:"URL of the Phoenix server, instead of SERVER_URL or the region default"}).option("skipUpload",{alias:"su",type:"boolean",description:"Skip upload of resources to S3 bucket when the development deployment is prepared (env: SKIP_UPLOAD, default: false)"}),async t=>{let i=f({ENABLE_EDITOR:e({default:!0}),PROJECT_SLUG:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),EDITOR_WS_PORT:o({default:"3020"}),DEBUG:e({default:!1}),WITH_LINGUI:e({default:!1}),PERSISTENCE_MODE:o({default:void 0}),FORCE_REBUILD:e({default:!1}),PHOENIX_TUI:e({default:!1}),SERVER_URL:o({default:void 0}),DEVELOPMENT_KEY:o({default:void 0}),PHOENIX_LOCAL:e({default:!1}),PHOENIX_REGION:o({choices:ee,default:void 0}),SKIP_UPLOAD:e({default:!1})})(),r=t.debug??i.DEBUG,n=ea({debug:r}),a=en(t.editor,i.ENABLE_EDITOR),s=t.editorWsPort??i.EDITOR_WS_PORT,l=t.force??i.FORCE_REBUILD,c=t.withLingui??i.WITH_LINGUI,u=t.persistence??i.PERSISTENCE_MODE,E=!u||"server"===u,v=t.tui??i.PHOENIX_TUI,m=await ec(),R=el(t.applicationSpec,m.applicationFlow,{logger:n}),S=t.local??i.PHOENIX_LOCAL,_=t.projectSlug??i.PROJECT_SLUG,U=E&&R&&!S&&!_?.length?await h(process.cwd()):void 0,{serverUrl:O,developmentKey:P,apiToken:b,projectSlug:L,environmentSlug:I}=await d({useServer:E,local:S,serverUrl:t.serverUrl??i.SERVER_URL,developmentKey:i.DEVELOPMENT_KEY,projectSlug:_?.length?_:U,environmentSlug:t.environmentSlug??i.ENVIRONMENT_SLUG}).with({useServer:!1},async({serverUrl:e,developmentKey:o,projectSlug:t,environmentSlug:i})=>({serverUrl:e,developmentKey:o,apiToken:void 0,projectSlug:t??m.name,environmentSlug:i??m.name})).with({local:!0},async({serverUrl:e,developmentKey:o,projectSlug:t,environmentSlug:i})=>({serverUrl:e?.length?e:"http://localhost:3000",developmentKey:o?.length?o:"dev_local-dev-key-12345",apiToken:void 0,projectSlug:t?.length?t:"local",environmentSlug:i?.length?i:"dev-local"})).with({developmentKey:p.string.minLength(1)},()=>U===g,()=>{throw Error(`phoenix dev has a DEVELOPMENT_KEY, but the spec says \`project: ${g}\`, which only a signed-in workspace can resolve. Set PROJECT_SLUG in .env by pasting the .env block of your Studio development environment, or name the project's slug in the spec.`)}).with({serverUrl:p.string.minLength(1),developmentKey:p.string.minLength(1),projectSlug:p.string.minLength(1),environmentSlug:p.string.minLength(1)},async({serverUrl:e,developmentKey:o,projectSlug:t,environmentSlug:i})=>({serverUrl:e,developmentKey:o,apiToken:void 0,projectSlug:t,environmentSlug:i})).with({developmentKey:p.union(void 0,""),projectSlug:p.string.minLength(1)},()=>R,async({serverUrl:e,projectSlug:o})=>{let r=e?.length?e:et(t.region??i.PHOENIX_REGION??Z),a=await er({serverUrl:r,project:o});return n.info(`Developing in ${a.projectSlug}/${a.environmentSlug} of workspace "${a.workspaceName}" on ${r}`),{serverUrl:r,developmentKey:void 0,apiToken:a.apiToken,projectSlug:a.projectSlug,environmentSlug:a.environmentSlug}}).with({developmentKey:p.union(void 0,""),projectSlug:p.union(void 0,"")},()=>R,()=>{throw Error(`phoenix dev does not know which project to develop in. Add \`project: ${g}\` to spec/application.yaml to use the default project of the workspace you are signed in to, or paste the .env block of a Studio development environment into .env. Pass --local to use the local-mode server.`)}).otherwise(()=>{throw Error("phoenix dev needs SERVER_URL, PROJECT_SLUG, ENVIRONMENT_SLUG, and DEVELOPMENT_KEY in .env. Create a development environment for your project in Studio and paste its .env block, or pass --local to use the local-mode server.")});if(!L)throw Error("Project slug is required, provide via --projectSlug, set PROJECT_SLUG env, or ensure package.json has a name field");if(!I)throw Error("Environment slug is required, provide via --environmentSlug, set ENVIRONMENT_SLUG env, or ensure package.json has a name field");let N={sdkVersion:ed.version,projectSlug:L,environmentSlug:I,cliUseWorkspace:t.workspace,enableEditor:a,editorWsPort:s,debug:r,withLingui:c,persistenceMode:u,force:l,tui:v,serverUrl:O,skipUpload:t.skipUpload??i.SKIP_UPLOAD};if(R){let e=P?{developmentKey:P}:b?{apiToken:b}:void 0;await k({...N,credential:e},{logger:n})}else await y.runDevCommand({...N,developmentKey:P},{logger:n})}).command(["link","l"],"Link local SDK for development",e=>e.option("sdk-path",{type:"string",description:"Path to the SDK repository",default:"../configurator-phoenix"}),async e=>{let o=ea();await M({sdkPath:e.sdkPath},{logger:o})}).command(["unlink","ul"],"Remove local SDK linking",()=>{},async()=>{let e=ea();await Q({logger:e})}).command(["sync","s"],"Sync project files and compile specs without building vite/webhooks",e=>e.option("workspace",{alias:"w",type:"boolean",description:"Override workspace mode (uses .phoenix.json config by default)"}).option("editor",{type:"boolean",description:"Enable or disable editor files generation (defaults to ENABLE_EDITOR env or true)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, defaults to project name in package.json)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the environment (env: ENVIRONMENT_SLUG, defaults to project name in package.json)"}).option("force",{alias:"f",type:"boolean",description:"Force full rebuild, skip cache (env: FORCE_REBUILD, default: false)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}).option("analyze",{alias:"a",type:"boolean",description:"Print pipeline metrics flamegraph after build (requires --applicationSpec)"}),async t=>{let i=f({ENABLE_EDITOR:e({default:!0}),DEBUG:e({default:!1}),PROJECT_SLUG:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),FORCE_REBUILD:e({default:!1})})(),r=ea({debug:t.debug??i.DEBUG}),n=en(t.editor,i.ENABLE_EDITOR),a=t.force??i.FORCE_REBUILD,s=await ec(),l=el(t.applicationSpec,s.applicationFlow,{logger:r}),p=t.projectSlug??i.PROJECT_SLUG??s.name,d=t.environmentSlug??i.ENVIRONMENT_SLUG??s.name;if(!p)throw Error("Project slug is required, provide via --projectSlug, set PROJECT_SLUG env, or ensure package.json has a name field");if(!d)throw Error("Environment slug is required, provide via --environmentSlug, set ENVIRONMENT_SLUG env, or ensure package.json has a name field");await (l?z:y.runSyncCommand)({sdkVersion:ed.version,projectSlug:p,environmentSlug:d,cliUseWorkspace:t.workspace,enableEditor:n,force:a,analyze:t.analyze},{logger:r})}).command("init [folder]","Start a Phoenix project: write package.json when the folder has none, a starter spec and pnpm-workspace.yaml with the pnpm settings the install needs. Continue with phoenix sync, phoenix login and phoenix dev",e=>e.positional("folder",{type:"string",description:"Folder to create the project in (default: the working directory)"}).option("scaffold",{type:"boolean",hidden:!0,description:"Accepted for compatibility and ignored: init always only writes the starter project"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging"}),async e=>{let o=ea({debug:e.debug??!1});try{await K({sdkVersion:ed.version,projectRoot:void 0===e.folder?void 0:l(e.folder)},{logger:o})}catch(e){o.error(e instanceof Error?e.message:String(e)),process.exit(1)}}).command(["story","st"],"Storybook example utilities",e=>X(e),()=>{}).command(["check","c"],"Run checks (TypeScript, ESLint, Prettier). Runs all by default, or only selected when any of --types/--lint/--format is passed.",e=>e.option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("types",{type:"boolean",description:"Run TypeScript check"}).option("lint",{type:"boolean",description:"Run ESLint check"}).option("format",{type:"boolean",description:"Run Prettier check"}),async o=>{let t=f({DEBUG:e({default:!1})})(),i=ea({debug:o.debug??t.DEBUG});await P({types:o.types,lint:o.lint,format:o.format},{logger:i})}).command(["fix","f"],"Fix linting and formatting issues. Runs all by default, or only selected when any of --lint/--format is passed.",e=>e.option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("lint",{type:"boolean",description:"Run ESLint fix"}).option("format",{type:"boolean",description:"Run Prettier fix"}),async o=>{let t=f({DEBUG:e({default:!1})})(),i=ea({debug:o.debug??t.DEBUG});await A({lint:o.lint,format:o.format},{logger:i})}).command(["changelog","clog"],"Display SDK changelog",e=>e.option("ver",{type:"string",description:"Show specific version (e.g., 0.36.0)"}).option("all",{alias:"a",type:"boolean",description:"Show all versions (warning: large output)"}).option("page",{alias:"p",type:"number",description:"Page number (3 versions per page)"}).option("list",{alias:"l",type:"boolean",description:"List version numbers only"}),async e=>{let o=ea();await O({version:e.ver,all:e.all,page:e.page,list:e.list},{logger:o})}).command(["inspect:assets","ia"],"Inspect 3D assets (glTF/GLB) — nodes, transforms, bounds, origin, materials, morph targets, animations",e=>e.option("file",{alias:"f",type:"string",description:"Path to specific glTF/GLB file"}).option("objects",{alias:"O",type:"boolean",description:"Show only object/node names"}).option("materials",{alias:"m",type:"boolean",description:"Show only material names"}).option("morphs",{alias:"M",type:"boolean",description:"Show only morph target names"}).option("animations",{alias:"a",type:"boolean",description:"Show only animation names"}).option("json",{alias:"j",type:"boolean",description:"Output as JSON"}),async e=>{let o=ea();await V({file:e.file,objects:e.objects,materials:e.materials,morphs:e.morphs,animations:e.animations,json:e.json},{logger:o})}).command(["screenshot","ss"],"Capture a screenshot of the configurator canvas",e=>e.option("port",{alias:"p",type:"string",description:"WebSocket server port (defaults to EDITOR_WS_PORT env or 3020)"}).option("output",{alias:"o",type:"string",description:"Output file path (defaults to SCREENSHOT_OUTPUT env or ./screenshot.png)"}).option("width",{alias:"w",type:"number",description:"Width in pixels (default: 1920)"}).option("height",{alias:"H",type:"number",description:"Height in pixels (default: 1080)"}).option("format",{alias:"f",type:"string",description:"Image format: PNG or JPEG (default: PNG)"}),async e=>{let t=f({EDITOR_WS_PORT:o({default:"3020"}),SCREENSHOT_OUTPUT:o({default:"./screenshot.png"})})(),i=ea();await W({port:e.port??t.EDITOR_WS_PORT,output:e.output??t.SCREENSHOT_OUTPUT,width:e.width,height:e.height,format:e.format},{logger:i})}).command(["inspect:state","is"],"Get the current editor state as JSON (entities, navigation, validation)",e=>e.option("port",{alias:"p",type:"string",description:"WebSocket server port (defaults to EDITOR_WS_PORT env or 3020)"}).option("output",{alias:"o",type:"string",description:"Output file path (prints to stdout if omitted)"}).option("sections",{alias:"s",type:"string",description:"Comma-separated sections: entities,navigation,validation (default: all)"}).option("pretty",{alias:"P",type:"boolean",description:"Pretty-print JSON output (default: true)",default:!0}),async e=>{let t=f({EDITOR_WS_PORT:o({default:"3020"})})(),i=ea();await $({port:e.port??t.EDITOR_WS_PORT,output:e.output,sections:e.sections,pretty:e.pretty},{logger:i})}).command(["inspect:data","id"],"Get the current editor context data as JSON (published, frontend, backend, session, access, web component)",e=>e.option("port",{alias:"p",type:"string",description:"WebSocket server port (defaults to EDITOR_WS_PORT env or 3020)"}).option("output",{alias:"o",type:"string",description:"Output file path (prints to stdout if omitted)"}).option("pretty",{alias:"P",type:"boolean",description:"Pretty-print JSON output (default: true)",default:!0}),async e=>{let t=f({EDITOR_WS_PORT:o({default:"3020"})})(),i=ea();await N({port:e.port??t.EDITOR_WS_PORT,output:e.output,pretty:e.pretty},{logger:i})}).command(["inspect:scene","isc"],"Get the current Three.js scene graph as JSON",e=>e.option("port",{alias:"p",type:"string",description:"WebSocket server port (defaults to EDITOR_WS_PORT env or 3020)"}).option("output",{alias:"o",type:"string",description:"Output file path (prints to stdout if omitted)"}).option("pretty",{alias:"P",type:"boolean",description:"Pretty-print JSON output (default: true)",default:!0}),async e=>{let t=f({EDITOR_WS_PORT:o({default:"3020"})})(),i=ea();await H({port:e.port??t.EDITOR_WS_PORT,output:e.output,pretty:e.pretty},{logger:i})}).command(["docs","doc"],"Browse SDK documentation",e=>e.option("read",{alias:"r",type:"string",description:"Read a specific doc file (e.g., docs/phoenix/admin.mdx)"}).option("category",{alias:"c",type:"string",description:"Show all docs in a category"}).option("list",{alias:"l",type:"boolean",description:"List all docs with paths and titles"}).option("search",{alias:"s",type:"string",description:"Search doc content for a term (case-insensitive)"}).option("dir",{type:"boolean",description:"Print the absolute path of the docs directory"}),async e=>{let o=ea();await D({read:e.read,category:e.category,list:e.list,search:e.search,dir:e.dir},{logger:o})}).command(["prepare:ci","pci","ci"],"Prepare CI environment by copying .env.ci to .env",()=>{},async()=>{let e=ea();await Y({logger:e})}).command({command:"environment:create",aliases:["env:create"],describe:"Create a new deployment environment",deprecated:"Switch to a new workflow and use deployment:prepare instead",builder:e=>e.option("server",{alias:"s",type:"string",description:"URL of the Phoenix server (defaults to SERVER_URL env)"}).option("apiKey",{alias:"k",type:"string",description:"API key for server access (defaults to ENVIRONMENT_API_KEY env)"}).option("name",{alias:"n",type:"string",description:"Name of the environment to be created"}).option("slug",{type:"string",description:"Slug of the customer to be created"}).option("uuid",{alias:"u",type:"string",description:"UUID of the environment to be created"}).option("outFile",{alias:"o",type:"string",description:"Output file to write the environment UUID to",default:".env.generated"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}),handler:async o=>{let t=f({DEBUG:e({default:!1})})(),i=o.debug??t.DEBUG,r=ea({debug:i});await I({server:o.server,apiKey:o.apiKey,name:o.name,slug:o.slug,uuid:o.uuid,outFile:o.outFile,debug:i},{logger:r})}}).command({command:"environment:list",aliases:["env:list"],describe:"List all deployment environments",deprecated:"Switch to a new workflow and use the prepare environment flow instead",builder:e=>e.option("server",{alias:"s",type:"string",description:"URL of the Phoenix server (defaults to SERVER_URL env)"}).option("apiKey",{alias:"k",type:"string",description:"API key for server access (defaults to ENVIRONMENT_API_KEY env)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}),handler:async o=>{let t=f({DEBUG:e({default:!1})})(),i=o.debug??t.DEBUG,r=ea({debug:i});await J({server:o.server,apiKey:o.apiKey,debug:i},{logger:r})}}).command(["environment:cleanup","env:cleanup","ec"],"Cleanup a transient deployment environment",e=>e.option("serverUrl",{alias:"su",type:"string",description:"URL of the Phoenix server (defaults to SERVER_URL env)"}).option("apiKey",{alias:"a",type:"string",description:"API key for server access (env: ENVIRONMENT_API_KEY, required)"}).option("projectKey",{alias:"k",type:"string",description:"Project key (env: PROJECT_KEY, required)"}).option("projectSlug",{alias:"p",type:"string",description:"Project slug (env: PROJECT_SLUG, required)"}).option("environmentSlug",{alias:"e",type:"string",description:"Environment slug (env: ENVIRONMENT_SLUG, defaults to project name in package.json)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}).option("outFile",{alias:"o",type:"string",description:"Output file to write cleanup result env variables to (env: OUT_FILE, default: .env.generated)",default:".env.generated"}),async t=>{let i=f({DEBUG:e({default:!1}),ENVIRONMENT_API_KEY:o({default:void 0}),PROJECT_KEY:o({default:void 0}),PROJECT_SLUG:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),SERVER_URL:o({default:void 0}),OUT_FILE:o({default:void 0})})(),r=t.debug??i.DEBUG,n=t.apiKey??i.ENVIRONMENT_API_KEY,a=t.projectKey??i.PROJECT_KEY,s=t.projectSlug??i.PROJECT_SLUG,l=await ec(),p=t.environmentSlug??i.ENVIRONMENT_SLUG??l.name,d=t.serverUrl??i.SERVER_URL,c=t.outFile??i.OUT_FILE??".env.generated";if(!n)throw Error("API key is required, provide via --apiKey or -a, or set ENVIRONMENT_API_KEY environment variable");if(!a)throw Error("Project key is required, provide via --projectKey or -k, or set PROJECT_KEY environment variable");if(!s)throw Error("Project slug is required, provide via --projectSlug or -p, or set PROJECT_SLUG environment variable");if(!p)throw Error("Environment slug is required, provide via --environmentSlug or -e, or set ENVIRONMENT_SLUG environment variable");if(!d)throw Error("Server URL is required, provide via --serverUrl or -su, or set SERVER_URL environment variable");let u=ea({debug:r});await L({server:d,apiKey:n,projectKey:a,projectSlug:s,environmentSlug:p,debug:r,outFile:c},{logger:u})}).command(["login <customer>"],"Sign the CLI in to an SDK-builder workspace; you approve it in Studio",e=>e.positional("customer",{type:"string",demandOption:!0,description:"Slug of the SDK-builder workspace (customer)"}).option("region",{choices:eo,description:`Phoenix region the workspace lives in (default: ${Z})`}).option("serverUrl",{alias:"su",type:"string",description:"URL of the Phoenix server, instead of the region default"}).option("studioUrl",{type:"string",description:"URL of Studio for the workspace, instead of the region default"}).option("open",{type:"boolean",default:!0,description:"Open the approval page in the default browser (--no-open to only print the link)"}),async e=>{let t=f({PHOENIX_REGION:o({choices:ee,default:void 0})})(),i=e.region??t.PHOENIX_REGION??Z,r=ea();try{await B({customer:e.customer,serverUrl:e.serverUrl??et(i),studioUrl:e.studioUrl??ei(i,e.customer),open:e.open},{logger:r})}catch(e){r.error(eu(e)),process.exit(1)}}).command(["deploy"],"Upload this SDK-builder project and follow its build until it is live",e=>e.option("region",{choices:eo,description:`Phoenix region the workspace lives in (default: ${Z})`}).option("serverUrl",{alias:"su",type:"string",description:"URL of the Phoenix server, instead of the region default"}).option("wait",{type:"boolean",default:!0,description:"Follow the build until it finishes (--no-wait to return once it starts)"}),async e=>{let t=f({PHOENIX_REGION:o({choices:ee,default:void 0})})(),i=e.region??t.PHOENIX_REGION??Z,r=ea();try{await T({serverUrl:e.serverUrl??et(i),sdkVersion:ed.version,wait:e.wait,projectDir:process.cwd(),pollIntervalMs:3e3},{logger:r})}catch(e){r.error(eu(e)),process.exit(1)}}).command(["logout"],"Revoke the API token of an SDK-builder workspace and forget it on this computer",e=>e.option("region",{choices:eo,description:`Phoenix region to sign out of (default: ${Z})`}).option("serverUrl",{alias:"su",type:"string",description:"URL of the Phoenix server, instead of the region default"}),async e=>{let t=f({PHOENIX_REGION:o({choices:ee,default:void 0})})(),i=e.region??t.PHOENIX_REGION??Z,r=ea();try{await F({serverUrl:e.serverUrl??et(i)},{logger:r})}catch(e){r.error(eu(e)),process.exit(1)}}).command(["feedback <message>"],"Send feedback about the SDK, CLI, docs or Studio to the Phoenix team",e=>e.positional("message",{type:"string",demandOption:!0,description:"What you want to tell the Phoenix team"}).option("type",{choices:[m.Bug,m.Idea,m.Other],default:m.Other,description:"What the feedback is about"}).option("contact",{type:"string",description:"How to reach you, when you want a reply"}).option("agent",{type:"string",description:"Name of the coding agent that writes the feedback"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the workspace project the feedback is about (env: PROJECT_SLUG, defaults to `project` of the application spec)"}).option("region",{choices:eo,description:`Phoenix region the workspace lives in (default: ${Z})`}).option("serverUrl",{alias:"su",type:"string",description:"URL of the Phoenix server, instead of the region default"}),async e=>{let t=f({PHOENIX_REGION:o({choices:ee,default:void 0}),PROJECT_SLUG:o({default:void 0})})(),i=ea(),a=e.region??t.PHOENIX_REGION??Z,s=e.projectSlug??t.PROJECT_SLUG,l=s?.length?s:await h(process.cwd()).catch(()=>{i.warn("The feedback is sent without a project, because `project` could not be read from the application spec. Pass --projectSlug to name the project.")});try{await G({serverUrl:e.serverUrl??et(a),message:e.message,type:e.type,contact:e.contact,agent:e.agent,project:l,sdkVersion:ed.version,clientInfo:`${n()} ${r()}, Node.js ${process.versions.node}`},{logger:i})}catch(e){i.error(eu(e)),process.exit(1)}}).command({command:"deployment:register",aliases:["dep:register","dr"],describe:"Register deployment configuration",deprecated:"Switch to a new workflow and use deployment:prepare and deployment:finish instead",builder:e=>e.option("server",{alias:"s",type:"string",description:"URL of the Phoenix server (defaults to SERVER_URL env)"}).option("apiKey",{alias:"k",type:"string",description:"API key for server access (defaults to ENVIRONMENT_API_KEY env)"}).option("outFile",{alias:"o",type:"string",description:"Output file to write the deployment ID to",default:".env.generated"}).option("skipUpload",{alias:"su",type:"boolean",description:"Skip uploading assets",default:!1}).option("activate",{alias:"a",type:"boolean",description:"Activate deployment after registration",default:!0}).option("overrideSchema",{alias:"os",type:"boolean",description:"Override existing schema",default:!1}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}),handler:async o=>{let t=f({DEBUG:e({default:!1})})(),i=o.debug??t.DEBUG,r=ea({debug:i});await x({server:o.server,apiKey:o.apiKey,outFile:o.outFile,skipUpload:o.skipUpload,activate:o.activate,overrideSchema:o.overrideSchema,debug:i},{logger:r})}}).command({command:"deployment:activate",aliases:["dep:activate","da"],describe:"Activate a deployment",deprecated:"Switch to a new workflow and use deployment:prepare and deployment:finish instead",builder:e=>e.option("server",{alias:"s",type:"string",description:"URL of the Phoenix server (defaults to SERVER_URL env)"}).option("apiKey",{alias:"k",type:"string",description:"API key for server access (defaults to ENVIRONMENT_API_KEY env)"}).option("uuid",{alias:"u",type:"string",description:"UUID of the deployment to activate"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (defaults to DEBUG env or false)"}),handler:async o=>{let t=f({DEBUG:e({default:!1})})(),i=o.debug??t.DEBUG,r=ea({debug:i});await _({server:o.server,apiKey:o.apiKey,uuid:o.uuid,debug:i},{logger:r})}}).command(["deployment:prepare","dep:prepare","dp"],"Prepare environment and register deployment (env: ENVIRONMENT_API_KEY, PROJECT_KEY, PROJECT_SLUG, PROJECT_REF, PROJECT_SHA, ENVIRONMENT_SLUG, OUT_FILE, SKIP_UPLOAD, OVERRIDE_SCHEMA, SERVER_URL)",e=>e.option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, required)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the environment (will be created if it does not exist) (env: ENVIRONMENT_SLUG, required)"}).option("projectRef",{type:"string",description:"Source branch, tag, or ref recorded as deployment provenance (env: PROJECT_REF)"}).option("projectSha",{type:"string",description:"Full commit SHA of the checked-out project revision (env: PROJECT_SHA)"}).option("outFile",{alias:"o",type:"string",description:"Output file to write the environment variables to (env: OUT_FILE, default: .env.generated)"}).option("skipUpload",{alias:"su",type:"boolean",description:"Skip upload of resources to S3 bucket (env: SKIP_UPLOAD, default: false)"}).option("overrideSchema",{alias:"os",type:"boolean",description:"Allows to override deployment schemas (env: OVERRIDE_SCHEMA, default: false)"}).option("apiKey",{alias:"a",type:"string",description:"API key for server access (env: ENVIRONMENT_API_KEY, required)"}).option("projectKey",{alias:"k",type:"string",description:"Project key to access the Project resources (env: PROJECT_KEY, required)"}).option("uploadLinksFile",{alias:"ulf",type:"string",description:"File to write upload links to (used by finish command) (default: .upload-links.json)"}).option("serverUrl",{alias:"s",type:"string",description:"PHX server URL (env: SERVER_URL, required)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (env: DEBUG, default: false)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}),async t=>{let i=f({DEBUG:e({default:!1}),ENVIRONMENT_API_KEY:o({default:void 0}),PROJECT_KEY:o({default:void 0}),PROJECT_SLUG:o({default:void 0}),PROJECT_REF:o({default:void 0}),PROJECT_SHA:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),OUT_FILE:o({default:".env.generated"}),SKIP_UPLOAD:e({default:!1}),OVERRIDE_SCHEMA:e({default:!1}),SERVER_URL:o({default:void 0})})(),r=t.debug??i.DEBUG,n=t.apiKey??i.ENVIRONMENT_API_KEY;if(!n)throw Error("API key is required, provide via --apiKey or -a, or set ENVIRONMENT_API_KEY environment variable");let a=t.projectKey??i.PROJECT_KEY;if(!a)throw Error("Project key is required, provide via --projectKey or -k, or set PROJECT_KEY environment variable");let s=t.projectSlug??i.PROJECT_SLUG;if(!s)throw Error("Project slug is required, provide via --projectSlug or -p, or set PROJECT_SLUG environment variable");let l=t.environmentSlug??i.ENVIRONMENT_SLUG;if(!l)throw Error("Environment slug is required, provide via --environmentSlug or -e, or set ENVIRONMENT_SLUG environment variable");let p=t.serverUrl??i.SERVER_URL;if(!p)throw Error("Server URL is required, provide via --serverUrl or -s, or set SERVER_URL environment variable");let d=await ec(),c=ea({debug:r}),u=el(t.applicationSpec,d.applicationFlow,{logger:c});await (u?q:y.runPrepareDeploymentCommand)({apiKey:n,projectKey:a,projectSlug:s,projectRef:t.projectRef??i.PROJECT_REF,projectSha:t.projectSha??i.PROJECT_SHA,environmentSlug:l,outFile:t.outFile??i.OUT_FILE,skipUpload:t.skipUpload??i.SKIP_UPLOAD,overrideSchema:t.overrideSchema??i.OVERRIDE_SCHEMA,uploadLinksFile:t.uploadLinksFile??".upload-links.json",serverUrl:p,debug:r,projectVersion:ed.version},{logger:c})}).command(["deployment:prepare-dev","dep:prepare-dev","dpd"],"Prepare a development deployment (env: SERVER_URL, PROJECT_SLUG, ENVIRONMENT_SLUG, DEVELOPMENT_KEY, OUT_FILE, SKIP_UPLOAD, OVERRIDE_SCHEMA)",e=>e.option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, required unless --local)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the development environment (env: ENVIRONMENT_SLUG, required unless --local)"}).option("outFile",{alias:"o",type:"string",description:"Output file to write the environment variables to (env: OUT_FILE, default: .env.generated)"}).option("skipUpload",{alias:"su",type:"boolean",description:"Skip upload of resources to S3 bucket (env: SKIP_UPLOAD, default: false)"}).option("overrideSchema",{alias:"os",type:"boolean",description:"Allows overriding deployment schemas (env: OVERRIDE_SCHEMA, default: true)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (env: DEBUG, default: false)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}).option("local",{type:"boolean",description:"Use local-mode development environment defaults (env: PHOENIX_LOCAL, default: false)"}),async t=>{let i=f({DEBUG:e({default:!1}),PROJECT_SLUG:o({default:void 0}),ENVIRONMENT_SLUG:o({default:void 0}),SERVER_URL:o({default:void 0}),DEVELOPMENT_KEY:o({default:void 0}),PHOENIX_LOCAL:e({default:!1}),OUT_FILE:o({default:".env.generated"}),SKIP_UPLOAD:e({default:!1}),OVERRIDE_SCHEMA:e({default:!0})})(),r=t.debug??i.DEBUG,n=ea({debug:r}),a=t.local??i.PHOENIX_LOCAL,s=i.SERVER_URL,l=t.projectSlug??i.PROJECT_SLUG,p=t.environmentSlug??i.ENVIRONMENT_SLUG,d=i.DEVELOPMENT_KEY;if(a&&(s=s?.length?s:"http://localhost:3000",l=l?.length?l:"local",p=p?.length?p:"dev-local",d=d?.length?d:"dev_local-dev-key-12345"),!s||!l||!p||!d)throw Error("phoenix deployment:prepare-dev needs SERVER_URL, PROJECT_SLUG, ENVIRONMENT_SLUG, and DEVELOPMENT_KEY in .env. Create a development environment for your project in Studio and paste its .env block, or pass --local to use the local-mode server.");let c=await ec(),u=el(t.applicationSpec,c.applicationFlow,{logger:n}),E={serverUrl:s,projectSlug:l,environmentSlug:p,outFile:t.outFile??i.OUT_FILE,skipUpload:t.skipUpload??i.SKIP_UPLOAD,overrideSchema:t.overrideSchema??i.OVERRIDE_SCHEMA,debug:r,projectVersion:ed.version};try{u?await R({...E,credential:{developmentKey:d}},{logger:n}):await y.prepareDevelopmentEnvironment({...E,developmentKey:d},{logger:n})}catch(e){n.error(`Development environment preparation failed: ${e instanceof Error?e.message:String(e)}`,e),process.exit(1)}}).command(["deployment:prepare-local","dep:prepare-local","dpl"],"Prepare local environment for development (env: PROJECT_KEY, PROJECT_SLUG, OUT_FILE, SKIP_UPLOAD, OVERRIDE_SCHEMA, SERVER_URL, LAMBDA_URL)",e=>e.option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, default: local)"}).option("environmentSlug",{alias:"e",type:"string",description:"Slug of the environment (env: ENVIRONMENT_SLUG, default: project name in package.json)"}).option("outFile",{alias:"o",type:"string",description:"Output file to write the environment variables to (env: OUT_FILE, default: .env.generated)"}).option("skipUpload",{alias:"su",type:"boolean",description:"Skip upload of resources to S3 bucket (env: SKIP_UPLOAD, default: false)"}).option("overrideSchema",{alias:"os",type:"boolean",description:"Allows to override deployment schemas (env: OVERRIDE_SCHEMA, default: true)"}).option("projectKey",{alias:"k",type:"string",description:"Project key to access the Project resources (env: PROJECT_KEY, required)"}).option("serverUrl",{alias:"s",type:"string",description:"PHX server URL (env: SERVER_URL, default: http://localhost:3000)"}).option("lambdaUrl",{alias:"l",type:"string",description:"Webhook URL (env: LAMBDA_URL, default: http://localhost:8080)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (env: DEBUG, default: false)"}).option("apiKey",{alias:"a",type:"string",description:"API key for server access (env: ENVIRONMENT_API_KEY, required)"}).option("applicationSpec",{alias:"as",type:"boolean",description:"Use application-spec pipeline (env: USE_APPLICATION_SPEC, default: false)"}),async t=>{let i=f({DEBUG:e({default:!1}),ENVIRONMENT_SLUG:o({default:void 0}),PROJECT_KEY:o({default:"project_local-dev-key-12345"}),PROJECT_SLUG:o({default:"local"}),OUT_FILE:o({default:".env.generated"}),SKIP_UPLOAD:e({default:!1}),OVERRIDE_SCHEMA:e({default:!0}),SERVER_URL:o({default:"http://localhost:3000"}),LAMBDA_URL:o({default:"http://localhost:8080"}),ENVIRONMENT_API_KEY:o({default:"local-dev-key-12345"})})(),r=t.debug??i.DEBUG,n=t.projectKey??i.PROJECT_KEY;if(!n)throw Error("Project key is required, provide via --projectKey or -k, or set PROJECT_KEY environment variable");let a=await ec(),s=t.environmentSlug??i.ENVIRONMENT_SLUG??a.name;if(!s)throw Error("Environment slug is required, provide via --environmentSlug or -e, or set ENVIRONMENT_SLUG environment variable");let l=t.apiKey??i.ENVIRONMENT_API_KEY;if(!l)throw Error("API key is required, provide via --apiKey or -a, or set ENVIRONMENT_API_KEY environment variable");let p=ea({debug:r}),d=el(t.applicationSpec,a.applicationFlow,{logger:p});try{await (d?S:y.prepareLocalEnvironment)({apiKey:l,projectKey:n,projectSlug:t.projectSlug??i.PROJECT_SLUG,environmentSlug:s,outFile:t.outFile??i.OUT_FILE,skipUpload:t.skipUpload??i.SKIP_UPLOAD,overrideSchema:t.overrideSchema??i.OVERRIDE_SCHEMA,serverUrl:t.serverUrl??i.SERVER_URL,lambdaUrl:t.lambdaUrl??i.LAMBDA_URL,debug:r,projectVersion:ed.version},{logger:p})}catch(e){p.error(`Local environment preparation failed: ${e instanceof Error?e.message:String(e)}`,e),process.exit(1)}}).command(["deployment:extract-sources <archive> <folder>"],"Validate the source archive of a phoenix deploy and extract its project files into a new folder. Links, special files, unsafe paths and oversized content are refused; entries that are not project files are left out",e=>e.positional("archive",{type:"string",demandOption:!0,description:"The source archive (.tgz)"}).positional("folder",{type:"string",demandOption:!0,description:"New or empty folder to extract the project files into"}),async e=>{let o=ea();try{await j({archivePath:e.archive,targetDir:e.folder},{logger:o})}catch(e){o.error(e instanceof Error?e.message:String(e)),process.exit(1)}}).command(["deployment:build-envs","dep:build-envs","dbe"],"Write the environment variables for the build step of a prepared deployment that builds apart from its deploy (env: DEPLOYMENT_ID, ENVIRONMENT_API_KEY, PROJECT_KEY, PROJECT_SLUG, OUT_FILE, SERVER_URL)",e=>e.option("uuid",{alias:"u",type:"string",description:"Id of the prepared deployment (env: DEPLOYMENT_ID, required)"}).option("outFile",{alias:"o",type:"string",description:"Output file to write the environment variables to (env: OUT_FILE, default: .env.generated)"}).option("apiKey",{alias:"a",type:"string",description:"API key for server access (env: ENVIRONMENT_API_KEY, required)"}).option("projectKey",{alias:"k",type:"string",description:"Project key to access the Project resources (env: PROJECT_KEY, required)"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, required)"}).option("serverUrl",{alias:"s",type:"string",description:"PHX server URL (env: SERVER_URL, required)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (env: DEBUG, default: false)"}),async t=>{let i=f({DEBUG:e({default:!1}),DEPLOYMENT_ID:o({default:void 0}),ENVIRONMENT_API_KEY:o({default:void 0}),PROJECT_KEY:o({default:void 0}),PROJECT_SLUG:o({default:void 0}),OUT_FILE:o({default:".env.generated"}),SERVER_URL:o({default:void 0})})(),r=t.debug??i.DEBUG,n=t.uuid??i.DEPLOYMENT_ID;if(!n)throw Error("Deployment ID is required, provide via --uuid or -u, or set DEPLOYMENT_ID environment variable");let a=t.apiKey??i.ENVIRONMENT_API_KEY;if(!a)throw Error("API key is required, provide via --apiKey or -a, or set ENVIRONMENT_API_KEY environment variable");let s=t.projectKey??i.PROJECT_KEY;if(!s)throw Error("Project key is required, provide via --projectKey or -k, or set PROJECT_KEY environment variable");let l=t.projectSlug??i.PROJECT_SLUG;if(!l)throw Error("Project slug is required, provide via --projectSlug or -p, or set PROJECT_SLUG environment variable");let p=t.serverUrl??i.SERVER_URL;if(!p)throw Error("Server URL is required, provide via --serverUrl or -s, or set SERVER_URL environment variable");let d=ea({debug:r});await w({uuid:n,apiKey:a,projectKey:s,projectSlug:l,outFile:t.outFile??i.OUT_FILE,serverUrl:p,debug:r},{logger:d})}).command(["deployment:finish","dep:finish","df"],"Upload files to S3 and activate deployment (env: DEPLOYMENT_ID, ENVIRONMENT_API_KEY, PROJECT_KEY, PROJECT_SLUG, LAMBDA_URL, SERVER_URL, SKIP_UPLOAD)",e=>e.option("uuid",{alias:"u",type:"string",description:"Id of the deployment to be activated (env: DEPLOYMENT_ID, required)"}).option("uploadLinksFile",{alias:"ulf",type:"string",description:"File containing upload links (generated by prepare command) (default: .upload-links.json)"}).option("apiKey",{alias:"a",type:"string",description:"API key for server access (env: ENVIRONMENT_API_KEY, required)"}).option("projectKey",{alias:"k",type:"string",description:"Project key to access the Project resources (env: PROJECT_KEY, required)"}).option("projectSlug",{alias:"p",type:"string",description:"Slug of the project (env: PROJECT_SLUG, required)"}).option("lambdaUrl",{alias:"l",type:"string",description:"Lambda webhook URL for the deployment (env: LAMBDA_URL, required)"}).option("serverUrl",{alias:"s",type:"string",description:"PHX server URL (env: SERVER_URL, required)"}).option("skipUpload",{alias:"su",type:"boolean",description:"Skip upload of resources to S3 bucket (env: SKIP_UPLOAD, default: false)"}).option("debug",{alias:"D",type:"boolean",description:"Enable debug mode for detailed logging (env: DEBUG, default: false)"}),async t=>{let i=f({DEBUG:e({default:!1}),DEPLOYMENT_ID:o({default:void 0}),ENVIRONMENT_API_KEY:o({default:void 0}),PROJECT_KEY:o({default:void 0}),PROJECT_SLUG:o({default:void 0}),LAMBDA_URL:o({default:void 0}),SERVER_URL:o({default:void 0}),SKIP_UPLOAD:e({default:!1})})(),r=t.debug??i.DEBUG,n=t.uuid??i.DEPLOYMENT_ID;if(!n)throw Error("Deployment ID is required, provide via --uuid or -u, or set DEPLOYMENT_ID environment variable");let a=t.apiKey??i.ENVIRONMENT_API_KEY;if(!a)throw Error("API key is required, provide via --apiKey or -a, or set ENVIRONMENT_API_KEY environment variable");let s=t.projectKey??i.PROJECT_KEY;if(!s)throw Error("Project key is required, provide via --projectKey or -k, or set PROJECT_KEY environment variable");let l=t.projectSlug??i.PROJECT_SLUG;if(!l)throw Error("Project slug is required, provide via --projectSlug or -p, or set PROJECT_SLUG environment variable");let p=t.lambdaUrl??i.LAMBDA_URL;if(!p)throw Error("Lambda URL is required, provide via --lambdaUrl or -l, or set LAMBDA_URL environment variable");let d=t.serverUrl??i.SERVER_URL;if(!d)throw Error("Server URL is required, provide via --serverUrl or -s, or set SERVER_URL environment variable");let c=ea({debug:r});await C({uuid:n,uploadLinksFile:t.uploadLinksFile??".upload-links.json",apiKey:a,projectKey:s,projectSlug:l,lambdaUrl:p,serverUrl:d,skipUpload:t.skipUpload??i.SKIP_UPLOAD,debug:r},{logger:c})}).demandCommand(1,"Please specify a command").help().alias("help","h").version(ed.version).alias("version","v").strict().parse();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{openAsBlob as e}from"node:fs";import{createApiBaseClient as t}from"#package/client";import{resolveApplicationSpecDeploymentData as i}from"../application-spec/index.js";import{createSourceArchive as r,getServerCredentials as
|
|
1
|
+
import{openAsBlob as e}from"node:fs";import{createApiBaseClient as t}from"#package/client";import{resolveApplicationSpecDeploymentData as i}from"../application-spec/index.js";import{createSourceArchive as r,getServerCredentials as a}from"../services/index.js";import{ensureWorkspaceInstallSettings as o}from"../utils/index.js";let s={queued:"Waiting for a build runner",preparing:"Preparing the deployment",building:"Building the project",deploying:"Deploying the frontend, webhooks and assets",live:"Live",failed:"Failed",cancelled:"Cancelled"},l=e=>new Promise(t=>setTimeout(t,e)),n=async(t,i)=>{let r=new FormData;for(let[e,i]of Object.entries(t.fields))r.append(e,i);r.append("file",await e(i,{type:"application/gzip"}),"sources.tgz");let a=await fetch(t.url,{method:"POST",body:r});if(!a.ok)throw Error(`Uploading the sources failed with HTTP ${a.status}: ${await a.text()}`)};export const runDeployCommand=async(e,{logger:d})=>{let u=await a(e.serverUrl),{pollIntervalMs:p}=e;if(!u)throw Error(`You are not signed in to ${e.serverUrl}. Run \`phoenix login <workspace>\` first.`);let c=t(e.serverUrl),m={authorization:`Bearer ${u.token}`};d.step("Validating the application spec");let h=await i({skipUpload:!0,logger:d});d.success(`The spec is valid (application version ${h.applicationVersion})`),d.step(`Packing the project for ${u.customerName}`),o(e.projectDir);let f=await r(e.projectDir);try{let t;d.info(` ${f.fileCount} files, ${(t=f.size)<1048576?`${(t/1024).toFixed(1)} KB`:`${(t/1024/1024).toFixed(1)} MB`}`);let i=await c.POST("/deployments/builds",{body:{sdkVersion:e.sdkVersion,sizeBytes:f.size,configurationSchema:{version:h.schemaVersion,schema:h.schema},adminConfigurationSchema:h.adminSchema?{version:h.adminSchemaVersion,schema:h.adminSchema}:void 0},headers:m});if(i.error||!i.data)throw Error(`The server did not create a build: ${i.error?.message??"no response"}`);let{buildId:r,upload:a}=i.data;d.step("Uploading the sources"),await n(a,f.path);let o=await c.POST("/deployments/builds/{buildId}/start",{params:{path:{buildId:r}},headers:{...m,"content-type":null}});if(o.error)throw Error(`The server did not start the build: ${o.error.message}`);if(o.data?.status==="failed")throw Error(`Build ${r} could not be started: ${o.data.error??"the server gave no reason"}`);if(d.success(`Build ${r} started`),u.studioUrl){let e=new URL(`/builder/deployments/${r}`,u.studioUrl);e.searchParams.set("customer",u.customerSlug),d.info(`Follow the build in Studio: ${e.toString()}`)}if(!e.wait)return;let g=null,w=0;for(;;){let{data:e,error:t}=await c.GET("/deployments/builds/{buildId}",{params:{path:{buildId:r}},headers:m}).catch(e=>({data:void 0,error:{message:String(e)}}));if(t||!e){if((w+=1)>=5)throw Error(`Following build ${r} failed: ${t?.message??"no response"}. The build may still finish; check Deployments in Studio.`);await l(p);continue}if(w=0,e.status!==g&&(g=e.status,d.step(s[e.status])),"live"===e.status)return void d.success(`Your configurator is live at ${e.configuratorUrl}`);if("failed"===e.status||"cancelled"===e.status||e.timedOut){let t=await c.GET("/deployments/builds/{buildId}/log",{params:{path:{buildId:r}},headers:m}).catch(()=>({data:void 0})),i=(t.data?.log??"").trim().split("\n").slice(-40).join("\n");i&&d.info(`
|
|
2
2
|
Last lines of the build log:
|
|
3
3
|
${i}
|
|
4
|
-
`);let
|
|
4
|
+
`);let a=e.timedOut?"it took too long":e.error??"see the build log";throw Error(`Build ${r} did not go live: ${a}`)}await l(p)}}finally{await f.cleanup()}};
|
|
@@ -5,19 +5,37 @@ export interface LoginCommandProps {
|
|
|
5
5
|
readonly studioUrl: string;
|
|
6
6
|
readonly open: boolean;
|
|
7
7
|
}
|
|
8
|
+
type LoginOutcome = {
|
|
9
|
+
readonly signedIn: true;
|
|
10
|
+
} | {
|
|
11
|
+
readonly signedIn: false;
|
|
12
|
+
readonly message: string;
|
|
13
|
+
};
|
|
14
|
+
interface LoginCallback {
|
|
15
|
+
readonly code: string;
|
|
16
|
+
readonly tokenName: string | null;
|
|
17
|
+
readonly finish: (outcome: LoginOutcome) => Promise<void>;
|
|
18
|
+
}
|
|
8
19
|
interface LoginCallbackListener {
|
|
9
20
|
readonly port: number;
|
|
10
|
-
readonly
|
|
21
|
+
readonly callback: Promise<LoginCallback>;
|
|
11
22
|
readonly close: () => void;
|
|
12
23
|
}
|
|
24
|
+
interface LoginCallbackListenerProps {
|
|
25
|
+
readonly state: string;
|
|
26
|
+
readonly studioUrl: string;
|
|
27
|
+
readonly customer: string;
|
|
28
|
+
}
|
|
13
29
|
/**
|
|
14
|
-
* Receives the one-time code
|
|
15
|
-
* so another page cannot feed the CLI a code of its own.
|
|
30
|
+
* Receives Studio's answer on 127.0.0.1: the one-time code of an approval, or a denial. Only a callback carrying
|
|
31
|
+
* this session's state is accepted, so another page cannot feed the CLI a code of its own. The browser ends on a
|
|
32
|
+
* Studio page; its address is built from the CLI's own Studio URL, never from the request.
|
|
16
33
|
*/
|
|
17
|
-
export declare const startLoginCallbackListener: (
|
|
34
|
+
export declare const startLoginCallbackListener: (props: LoginCallbackListenerProps) => Promise<LoginCallbackListener>;
|
|
18
35
|
/**
|
|
19
|
-
* Signs the CLI in to an SDK-builder workspace: the user approves in Studio, Studio returns a
|
|
20
|
-
* CLI's loopback listener, and the CLI exchanges it with its PKCE verifier for an API token.
|
|
36
|
+
* Signs the CLI in to an SDK-builder workspace: the user names the token and approves in Studio, Studio returns a
|
|
37
|
+
* one-time code to this CLI's loopback listener, and the CLI exchanges it with its PKCE verifier for an API token.
|
|
38
|
+
* The browser waits on the callback meanwhile and ends on Studio's page for the outcome.
|
|
21
39
|
*/
|
|
22
40
|
export declare const runLoginCommand: (props: LoginCommandProps, { logger }: CommandContext) => Promise<void>;
|
|
23
41
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{spawn as e}from"node:child_process";import{createHash as t,randomBytes as r}from"node:crypto";import{createServer as o}from"node:http";import{hostname as n}from"node:os";import{createApiBaseClient as
|
|
1
|
+
import{spawn as e}from"node:child_process";import{createHash as t,randomBytes as r}from"node:crypto";import{createServer as o}from"node:http";import{hostname as n}from"node:os";import{createApiBaseClient as s}from"#package/client";import{getServerCredentials as i,saveServerCredentials as a}from"../services/index.js";let l={"&":"&","<":"<",">":">",'"':""","'":"'"},c=(e,t)=>`<!doctype html><html><head><meta charset="utf-8"><title>${e}</title></head><body style="font-family:system-ui,sans-serif;display:grid;place-items:center;height:100vh;margin:0"><main style="text-align:center"><h1>${e}</h1><p>${t.replace(/[&<>"']/g,e=>l[e]??e)}</p></main></body></html>`,d=(e,t,r,o)=>new Promise(n=>{e.destroyed?n():(e.once("close",n),e.writeHead(t,{...r,connection:"close"}).end(o))});export const startLoginCallbackListener=async e=>{let{state:t,studioUrl:r,customer:n}=e,s=(e,t)=>{let o=new URL(e,r);return o.searchParams.set("customer",n),t&&o.searchParams.set("name",t),o.toString()},i=null,a=!1,l=new Promise((e,t)=>{i={resolve:e,reject:t}}),m=o((e,r)=>{let o=new URL(e.url??"/","http://127.0.0.1"),n=o.searchParams.get("code"),l="access_denied"===o.searchParams.get("error");if("/callback"!==o.pathname)return void r.writeHead(404).end();if(o.searchParams.get("state")!==t||a||!n&&!l){d(r,400,{"content-type":"text/html"},c("Sign-in failed","This response does not belong to the waiting CLI. Run phoenix login again.")),a||i?.reject(Error("The sign-in response did not match this CLI session. Run `phoenix login` again."));return}if(a=!0,l||!n)return void d(r,302,{location:s("/builder/cli-login/denied",null)}).then(()=>{i?.reject(Error("The sign-in was denied in Studio. Run `phoenix login` again to sign in."))});let m=o.searchParams.get("name");i?.resolve({code:n,tokenName:m,finish:e=>e.signedIn?d(r,302,{location:s("/builder/cli-login/done",m)}):d(r,200,{"content-type":"text/html"},c("Sign-in failed",e.message))})}),h=await new Promise((e,t)=>{m.once("error",t),m.listen(0,"127.0.0.1",()=>{let r=m.address();null===r||"string"==typeof r?t(Error("The login callback listener did not get a port. Run `phoenix login` again.")):e(r.port)})}),u=setTimeout(()=>{i?.reject(Error("Nobody approved the sign-in within 5 minutes. Run `phoenix login` again."))},3e5);return{port:h,callback:l,close:()=>{clearTimeout(u),m.close()}}};let m=async(e,t)=>{try{let{error:r,response:o}=await s(e).DELETE("/auth/token",{headers:{authorization:`Bearer ${t}`,"content-type":null}});return r&&401!==o.status?r.message:null}catch(e){return e instanceof Error?e.message:String(e)}},h=async(e,t)=>{let{data:r,error:o}=await s(e.serverUrl).POST("/auth/token",{body:t});if(o||!r)throw Error(`The server did not accept the sign-in: ${o?.message??"no response"}`);if(r.customer.slug!==e.customer)throw await m(e.serverUrl,r.token),Error(`The sign-in was approved in workspace "${r.customer.slug}", not "${e.customer}". Check --region or --studioUrl and run \`phoenix login ${e.customer}\` again.`);let n=await i(e.serverUrl),l=await a(e.serverUrl,{token:r.token,userId:r.userId,customerSlug:r.customer.slug,customerName:r.customer.name,studioUrl:e.studioUrl,createdAt:new Date().toISOString()}),c=n?await m(e.serverUrl,n.token):null;return{customerName:r.customer.name,path:l,revokeError:c}};export const runLoginCommand=async(o,{logger:s})=>{let i=r(32).toString("base64url"),a=t("sha256").update(i).digest("base64url"),l=r(16).toString("base64url"),c=n(),d=`phoenix CLI on ${c}`,m=await startLoginCallbackListener({state:l,studioUrl:o.studioUrl,customer:o.customer});try{let t=new URL("/builder/cli-login",o.studioUrl);t.searchParams.set("customer",o.customer),t.searchParams.set("port",String(m.port)),t.searchParams.set("state",l),t.searchParams.set("challenge",a),t.searchParams.set("name",d),t.searchParams.set("host",c),t.searchParams.set("started",String(Date.now())),s.step(`Signing in to workspace "${o.customer}" on ${o.serverUrl}`),s.info(`Approve the CLI in your browser:
|
|
2
2
|
|
|
3
3
|
${t.toString()}
|
|
4
|
-
`),o.open&&(t=>{let[r,o]="darwin"===process.platform?["open",[t]]:"win32"===process.platform?["rundll32",["url.dll,FileProtocolHandler",t]]:["xdg-open",[t]];e(r,o,{stdio:"ignore",detached:!0}).on("error",()=>void 0).unref()})(t.toString());let r=await m.
|
|
4
|
+
`),o.open&&(t=>{let[r,o]="darwin"===process.platform?["open",[t]]:"win32"===process.platform?["rundll32",["url.dll,FileProtocolHandler",t]]:["xdg-open",[t]];e(r,o,{stdio:"ignore",detached:!0}).on("error",()=>void 0).unref()})(t.toString());let r=await m.callback;try{let e=await h(o,{code:r.code,codeVerifier:i,port:m.port,name:d});e.revokeError&&s.warn(`The server did not revoke the token this sign-in replaces (${e.revokeError}). It stays valid on the server. Contact Phoenix support to revoke it.`),await r.finish({signedIn:!0}),s.success(`Signed in to ${e.customerName}. The token is stored in ${e.path}; revoke it with phoenix logout.`)}catch(e){throw await r.finish({signedIn:!1,message:e instanceof Error?e.message:String(e)}),e}}finally{m.close()}};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salsita-ai/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0-develop.2331d4a6b7",
|
|
4
4
|
"description": "TypeScript SDK and CLI for building, running, and deploying Phoenix configurator applications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"salsita",
|
|
@@ -295,8 +295,8 @@
|
|
|
295
295
|
"yaml": "2.9.0",
|
|
296
296
|
"yargs": "17.7.2",
|
|
297
297
|
"zod": "3.25.76",
|
|
298
|
-
"@salsita-ai/common": "0.
|
|
299
|
-
"@salsita-ai/contracts": "0.
|
|
298
|
+
"@salsita-ai/common": "0.50.0-develop.2331d4a6b7",
|
|
299
|
+
"@salsita-ai/contracts": "0.50.0-develop.2331d4a6b7"
|
|
300
300
|
},
|
|
301
301
|
"devDependencies": {
|
|
302
302
|
"@clerk/clerk-react": "5.61.8",
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{sdkGuidanceSections as e}from"./common/sdk-content.js";export const generateAgentsMd=()=>`${[e.projectIntro,e.buildCommands,e.doNotEdit,"Phoenix SDK guidance lives in the `phoenix`, `phoenix-cli`, `phoenix-create-configurator`, `phoenix-feedback` and `phoenix-review` skills under `.claude/skills/` and `.agents/skills/`. Phoenix rewrites them on every sync, removes anything else inside their folders and removes other `phoenix`-prefixed skill folders, so to customise a skill, copy it to a folder whose name does not start with `phoenix`."].join("\n\n")}
|
|
2
|
-
`;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
export const sdkGuidanceSections={projectIntro:`## Phoenix Configurator Project
|
|
2
|
-
|
|
3
|
-
Declarative 3D product configurator built with Phoenix SDK. Domain model defined in YAML, custom logic in TypeScript.`,buildCommands:"## Build Commands\n- `pnpm phoenix build` — Full production build\n- `pnpm phoenix dev` — Development mode with hot reload\n- `pnpm phoenix sync` — Sync generated files without full build",devLogs:"## Dev Logs\n- `pnpm phoenix dev` writes all logs to `.phoenix/phoenix-dev.log`\n- Contains: spec parse errors, build errors, browser runtime errors, file watcher events\n- After making changes, always check the log for errors: `tail -50 .phoenix/phoenix-dev.log` or `grep ERROR .phoenix/phoenix-dev.log`\n- Rotated automatically at 10MB (`.log.1`, `.log.2` are older rotations)",projectStructure:"## Project Structure\n- `spec/` — Domain YAML specs (entities, relations, expressions, invariants, components, application config)\n- `src/expressions/` — Computed/derived entity properties (`phx.domain.implementCustomExpressions()`)\n- `src/invariants/` — Business rule constraints (`phx.domain.implementCustomInvariants()`)\n- `src/transformers/` — Automatic state fixers (`phx.frontend.transformerBuilder`)\n- `src/components/` — ECS system components (`phx.domain.attachComponent.withEntity()`)\n- `src/elements/` — Page-level React components (`phx.frontend.createCustomPhoenixLayoutElement()`)\n- `src/handlers/` — Event & lifecycle handlers\n- `src/webhooks/` — Server-side webhook handlers (`phx.webhooks.*Builder`)\n- `src/migrations/` — Schema version migrations (v*.ts)\n- `src/locales/` — Locale catalogs (authored .po sources; compiled .ts, do not edit)\n- `src/admin/` — Admin interface (mirrors main src/ structure)\n- `src/_shared/` — Shared utilities (NOT auto-imported, requires explicit imports)\n- `.phoenix/` — Auto-generated files (DO NOT EDIT)\n- `public/` — Static assets (3D models, textures, images, HDRI maps, fonts)\n- `assets/` — Uploadable resources (PDF templates, email assets)",architecturePrinciples:"## Architecture Principles\n- YAML-first: 99% of configuration in spec/*.yaml, custom code is last resort\n- ECS pattern: entities (domain objects) + components (behavior/UI) + systems (SDK runtime)\n- Reactive state: immutable domain state flows through RxJS pipelines\n- Data binding: `$read` (read-only), `$write` (write-only), `$bind` (bidirectional) connect components to domain\n- memoEval: all component implementations must use memoEval for stable object references",keyPatterns:"## Key Patterns\n- Expressions = computed properties on entities (prefix: `$`), implemented per-entity in src/expressions/\n- Invariants = validation rules returning violations, static or dynamic\n- Transformers = auto-fixers maintaining consistency after state changes\n- Components defined in YAML with `$read`/`$bind` bindings, or custom in src/components/ using attachComponent builder\n- Webhooks = server-side finalization tasks (PDF, email, CSV, image rendering)\n- Filters = contextual component activation via navigationStates, viewStates, modes, selectedEntityIds",fileConventions:`## File Conventions
|
|
4
|
-
- Components: PascalCase (.tsx)
|
|
5
|
-
- Utilities: kebab-case (.ts)
|
|
6
|
-
- Expressions: entity-name.ts
|
|
7
|
-
- Migrations: v*.ts (sequential)
|
|
8
|
-
- Specs: kebab-case.yaml
|
|
9
|
-
- Underscore folders (_shared/, _utils/) are NOT auto-imported`,exportRules:`## Export Rules
|
|
10
|
-
All files in src/expressions/, src/invariants/, src/transformers/, src/components/, src/handlers/, src/webhooks/ MUST use default exports. Can be a single item or an array. Named exports are ignored by the SDK auto-import system.`,webhookMembership:"## Webhook Membership\n- User-authored components, admin components, and handlers are frontend-only by default.\n- A handler that registers `createMapPublishedRevisionDataHandler`, `createMapPublishedChunkedDataHandler`, `createDataRowValidatorHandler`, or `createSheetValidatorHandler` is included in the webhook automatically.\n- To include another component or handler in the webhook, put `'use webhook'` as its first statement (leading comments are allowed).\n- A webhook-included file and its runtime local-import closure must not import browser SDK entrypoints (`application`, `admin`, `configurator`, `editor`, `react`, `ui`) or style/font/image assets. Spec parsing reports the unsafe import and inclusion reason as a diagnostic.\n- Keep browser rendering in an unpinned file. Move shared server-safe logic into a separate module when both frontend and webhook code need it.",doNotEdit:"## Do Not Edit\n- `.phoenix/` directory — completely regenerated on each build\n- `tsconfig.json`, `eslint.config.js`, `prettier.config.js`, `.prettierignore`, `.linguirc`, `.nvmrc`\n- `src/locales/` .ts files — compiled from .po files",sdkDocumentation:'## SDK Documentation\n\nAlways search SDK docs for relevant examples before implementing Phoenix features.\n\n### Commands\n- `pnpm phoenix docs` — Full documentation index with descriptions\n- `pnpm phoenix docs -s <term>` — Search all doc content and metadata (case-insensitive)\n- `pnpm phoenix docs --dir` — Print the absolute docs directory for grep or ripgrep\n- `pnpm phoenix docs -r <path>` — Read specific doc (raw text to stdout)\n- `pnpm phoenix docs -c <category>` — List docs in a category\n- `pnpm phoenix docs -l` — List all doc paths with titles\n\n### Key Docs\n- `docs/phoenix/getting-started.mdx` — Setup, prerequisites, first project\n- `docs/phoenix/quickstart.mdx` — End-to-end tutorial building a configurator\n- `docs/phoenix/domain-model.mdx` — Entities, attributes, relations, specs\n- `docs/phoenix/components.mdx` — ECS pattern, YAML components, custom components\n- `docs/phoenix/project-structure.mdx` — Files, folders, conventions\n- `docs/phoenix/best-practices.mdx` — YAML-first, code patterns, common pitfalls\n- `docs/phoenix/state-management.mdx` — Reactive state, RxJS pipelines, data flow\n- `docs/phoenix/expression-context.mdx` — Expression API, context object, helpers\n- `docs/phoenix/webhooks.mdx` — Server-side finalization workflows\n- `docs/phoenix/finalization.mdx` — Finalization system, PDF/email/CSV generation\n- `docs/phoenix/migrations.mdx` — Schema versioning, migration files\n\n### Agent Workflow\n1. Find relevant docs by content: `pnpm phoenix docs -s \'camera\'`\n2. Read matching doc: `pnpm phoenix docs -r docs/3d-scene/cameras/transitions.mdx`\n3. Search within a doc: `pnpm phoenix docs -r <path> | grep "example"`\n4. Search titles only as a fallback: `pnpm phoenix docs -l | grep "camera"`\n5. Search generated files directly when needed: `grep -rn "camera" "$(pnpm phoenix docs --dir)"`\n6. Browse a topic area: `pnpm phoenix docs -c "Layouts"`',assetInspection:"## 3D Asset Inspection\n\nRun `pnpm phoenix inspect:assets` to discover all glTF/GLB files in `public/` and get a summary table. Use `--file <path>` for detailed single-file inspection.\n\n**When to use:** before writing YAML/code that references objectName, materialsToOverride, morphTargetInfluences, or object positioning.\n\n**What it shows per node:**\n- Name, type (Mesh/Light/Camera/Empty), children\n- Transform: `pos=`, `rot=`, `scale=` (only non-default values shown)\n- Per-node morph targets: `morphs=Width,Height`\n- Bounding box: `bounds=WxHxD` (width x height x depth in meters)\n- Origin placement: `origin=center`, `bottom-center`, `top-center`, `bottom-corner`, etc. with numerical offset\n\n**Use cases:**\n- Find exact node names for `objectName` in scene entity components\n- Find material names for `materialsToOverride`\n- Find morph target names for `morphTargetInfluences`\n- Check model dimensions (bounds) for positioning, dimension indicators, or invariants\n- Check origin placement to understand how models anchor (center vs bottom-center)\n- Use `--json` for programmatic access to all data\n\n**Flags:** `--objects`, `--materials`, `--morphs`, `--animations`, `--json`",screenshotCli:"## Screenshot CLI\n\nCapture 3D canvas screenshots from a running dev server via `pnpm phoenix screenshot`.\n\n**Prerequisites:**\n1. `phoenix dev` must be running (starts the WebSocket server on port 3020)\n2. Configurator must be open in a browser (the browser does the actual rendering)\n\n**Options:**\n- `--output, -o` — Output file path (default: `./screenshot.png`)\n- `--width, -w` — Width in pixels (default: 1920)\n- `--height` — Height in pixels (default: 1080)\n- `--format, -f` — Image format: PNG or JPEG (default: PNG)\n- `--port` — WebSocket server port (default: 3020)\n\n**Example workflow:**\n1. Start dev server: `pnpm phoenix dev`\n2. Open configurator in browser (or via Playwright MCP)\n3. Take screenshot: `pnpm phoenix screenshot -o ./render.png -w 2560 --height 1440`\n\n**Use cases:** visual regression testing, generating product images, debugging 3D renders",inspectState:"## Inspect: State\n\nGet the current editor runtime state as JSON via `pnpm phoenix inspect:state`.\n\n**Prerequisites:** same as screenshot (dev server running + browser open)\n\n**Options:**\n- `--output, -o` — Output file path (prints to stdout if omitted)\n- `--sections, -s` — Comma-separated: entities, navigation, validation (default: all)\n- `--pretty` — Pretty-print JSON (default: true)\n- `--port` — WebSocket server port (default: 3020)\n\n**Example:** `pnpm phoenix inspect:state -o ./state.json -s entities,navigation`\n\n**Lifecycle status:** Always included in response. Shows which systems are ready:\n- `domainLoaded` — domain data loaded\n- `domainContextReady` — domain context initialized (entities available)\n- `configuratorReady` — 3D configurator initialized\n- `sessionAuthenticated` — session service active\n- `editorMode` — editor mode enabled\n\n**Tips:** Use `--sections` to limit payload size. Pipe through `head`/`tail` for partial output (e.g., `pnpm phoenix inspect:state | head -50`).\n\n**Use cases:** AI agent context, debugging entity state, inspecting navigation/validation",inspectData:`## Inspect: Data
|
|
11
|
-
|
|
12
|
-
Get the current editor context data as JSON via \`pnpm phoenix inspect:data\`.
|
|
13
|
-
|
|
14
|
-
**Prerequisites:** same as screenshot (dev server running + browser open)
|
|
15
|
-
|
|
16
|
-
**Options:**
|
|
17
|
-
- \`--output, -o\` — Output file path (prints to stdout if omitted)
|
|
18
|
-
- \`--pretty\` — Pretty-print JSON (default: true)
|
|
19
|
-
- \`--port\` — WebSocket server port (default: 3020)
|
|
20
|
-
|
|
21
|
-
**Returns:** publishedData, frontendData, backendData, sessionData, accessData, webComponentProperties
|
|
22
|
-
|
|
23
|
-
**Example:** \`pnpm phoenix inspect:data -o ./data.json\`
|
|
24
|
-
|
|
25
|
-
**Tips:** Pipe through \`head\`/\`tail\` for partial output (e.g., \`pnpm phoenix inspect:data | head -30\`).
|
|
26
|
-
|
|
27
|
-
**Use cases:** AI agent context, debugging published/session/access data`,inspectScene:`## Inspect: Scene
|
|
28
|
-
|
|
29
|
-
Get the current Three.js scene graph as JSON via \`pnpm phoenix inspect:scene\`.
|
|
30
|
-
|
|
31
|
-
**Prerequisites:** same as screenshot (dev server running + browser open)
|
|
32
|
-
|
|
33
|
-
**Options:**
|
|
34
|
-
- \`--output, -o\` — Output file path (prints to stdout if omitted)
|
|
35
|
-
- \`--pretty\` — Pretty-print JSON (default: true)
|
|
36
|
-
- \`--port\` — WebSocket server port (default: 3020)
|
|
37
|
-
|
|
38
|
-
**Returns:** Recursive scene tree with per-node: name, type, visible, position, rotation, scale, userData (entityId), and for meshes: geometry name, bounding box, material properties (color, metalness, roughness, opacity, textures), morph target influences. Lights include color, intensity, and type-specific properties.
|
|
39
|
-
|
|
40
|
-
**Example:** \`pnpm phoenix inspect:scene -o ./scene.json\`
|
|
41
|
-
|
|
42
|
-
**Tips:** Scene graphs can be large. Pipe through \`head\`/\`tail\` for partial output.
|
|
43
|
-
|
|
44
|
-
**Use cases:** AI agent context, debugging 3D scene layout, inspecting materials and lighting`,playwrightMcpSetup:`## Playwright MCP Setup (for AI agents)
|
|
45
|
-
|
|
46
|
-
To interact with the 3D configurator in a browser, Playwright MCP needs GPU-enabled flags for WebGL rendering. Add to \`~/.claude/.mcp.json\`:
|
|
47
|
-
|
|
48
|
-
\`\`\`json
|
|
49
|
-
{
|
|
50
|
-
"mcpServers": {
|
|
51
|
-
"playwright": {
|
|
52
|
-
"command": "npx",
|
|
53
|
-
"args": [
|
|
54
|
-
"@playwright/mcp@latest",
|
|
55
|
-
"--headed",
|
|
56
|
-
"--launch-options",
|
|
57
|
-
"{\\"args\\":[\\"--use-gl=swiftshader\\",\\"--enable-webgl\\",\\"--ignore-gpu-blocklist\\"]}"
|
|
58
|
-
]
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
\`\`\`
|
|
63
|
-
|
|
64
|
-
Key flags:
|
|
65
|
-
- \`--headed\` — visible browser (required for GPU rendering)
|
|
66
|
-
- \`--use-gl=swiftshader\` — software GPU fallback for environments without a physical GPU
|
|
67
|
-
- \`--enable-webgl\` + \`--ignore-gpu-blocklist\` — ensure WebGL is available`};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{renderAgentSkill as n}from"./common/agent-skill.js";import{sdkGuidanceSections as e}from"./common/sdk-content.js";export const generatePhoenixCliSkill=()=>n({name:"phoenix-cli",description:"Phoenix CLI tooling for building and inspecting this configurator, covering build, dev and sync commands, dev logs, glTF asset inspection, screenshots, runtime state, data and scene inspection, and Playwright MCP setup. Use when building, debugging build or runtime errors, checking 3D assets, or inspecting the running configurator.",sections:[e.buildCommands,e.devLogs,e.assetInspection,e.screenshotCli,e.inspectState,e.inspectData,e.inspectScene,e.playwrightMcpSetup]});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{renderAgentSkill as e}from"./common/agent-skill.js";import{sdkGuidanceSections as t}from"./common/sdk-content.js";export const followsCanaryBuilds=e=>!e.useWorkspace&&e.sdkVersion.includes("-develop.");export const generatePhoenixSkill=({checkLatestCanary:n})=>e({name:"phoenix",description:`Phoenix SDK project conventions, covering project structure, architecture principles, key patterns, file and export rules, webhook membership, showing the user the dev preview and the build of a deploy, and how to search the SDK documentation${n?", and the internal-beta check for the latest canary SDK build":""}. Use before writing or changing specs or source code in this Phoenix configurator project.`,sections:[...n?["## Stay on the Latest Canary\nDuring the internal beta this project uses the `canary` build of the SDK, which is published from every change to the platform. Once per conversation, before you change anything, compare the installed version with the newest canary:\n```bash\npnpm list @salsita-ai/sdk --depth 0\nnpm view @salsita-ai/sdk@canary version\n```\nWhen they differ, tell the user which version you are moving to, then update the project and regenerate its files:\n```bash\npnpm add @salsita-ai/sdk@canary\npnpm phoenix sync\n```\n`sync` rewrites the Phoenix skills, so read the ones you use again after it. When the user runs a globally installed `phoenix`, update that too with `npm install -g @salsita-ai/sdk@canary`. If the project no longer builds after the update, stop and tell the user; the `phoenix-feedback` skill covers reporting it."]:[],t.projectStructure,t.architecturePrinciples,t.keyPatterns,t.fileConventions,t.exportRules,t.webhookMembership,t.doNotEdit,"## Show the Preview While You Work\nThe user should see the configurator change as you build it. Before your first change in a conversation, make sure `pnpm phoenix dev` is running (start it in the background when it is not) and open the address it prints as `Preview: <url>` (also written to `.phoenix/phoenix-dev.log`) in the user's browser: `open '<url>'` on macOS, `xdg-open '<url>'` on Linux, `Start-Process '<url>'` in PowerShell, `start \"\" \"<url>\"` in cmd. Keep the quotes, the shell would otherwise read a `?` in the address as a pattern. The log keeps the lines of earlier runs, so when you have just started dev, wait for the `Preview:` line written after your start and use the last one. Open it once; the preview reloads on every change, so tell the user to keep that tab open instead of opening it again.","## Show the Build After a Deploy\n`pnpm phoenix deploy` starts a build on the server and waits for it to go live. Right after `Build <id> started` it prints `Follow the build in Studio: <url>`. Run the deploy so that you can read its output while it runs, and open that link in the user's browser, quoted as above, as soon as it appears, so they can follow the build they just triggered. When the line is missing, the sign-in is older than the link: tell the user the build is listed under Deployments in Studio, and that `pnpm phoenix login <workspace>` brings the link back.","## Code Review\nUse the `phoenix-review` skill to review code changes before committing.",t.sdkDocumentation]});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{browserDetailsTool as e}from"@salsita-ai/contracts/assistant";let t=e=>{let t=[];for(let i=0;i<e.length;i+=64)t.push(e.slice(i,i+64));return t};export const browserDetailsClientTool=e.client(()=>{let e=(()=>{let e=[`User agent: ${navigator.userAgent}`,`Viewport: ${window.innerWidth} x ${window.innerHeight} px`,`Screen: ${window.screen.width} x ${window.screen.height} px`,`Device pixel ratio: ${window.devicePixelRatio}`,`Language: ${navigator.language}`,`Time zone: ${Intl.DateTimeFormat().resolvedOptions().timeZone}`].flatMap(t),i=document.createElement("canvas");i.width=720,i.height=48+26*e.length;let n=i.getContext("2d");if(!n)throw Error("The browser details capture failed because the canvas has no 2D context. Retry in another browser.");return n.fillStyle="#ffffff",n.fillRect(0,0,i.width,i.height),n.fillStyle="#111111",n.font="16px monospace",n.textBaseline="top",e.forEach((e,t)=>n.fillText(e,24,24+26*t)),i.toDataURL("image/png")})();return[{type:"image",source:{type:"data",value:e.slice(e.indexOf(",")+1),mimeType:"image/png"}}]});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{AssistantGraphQLToolInput as e,applyTool as t,queryTool as o}from"@salsita-ai/contracts/assistant";let a=e=>({results:[],committed:!1,message:e}),s=e=>JSON.parse(JSON.stringify(e)),i=t=>{let o=e.safeParse(t);if(!o.success){let e=o.error.issues.map(e=>`${e.path.join(".")}: ${e.message}`).join("; ");return{ok:!1,refusal:a(`Nothing was run, because the tool input is not a list of operations (${e}). Send { "operations": [{ "query": "<one GraphQL operation>" }] } with at least one item.`)}}return{ok:!0,operations:o.data.operations.map(({query:e,variables:t,operationName:o})=>({document:e,variables:t??void 0,operationName:o??void 0}))}};export const queryClientTool=o.client(async(e,{context:t})=>{let o=i(e);return o.ok?t.storeSystem.isInitialized?s({results:(await t.graphQLSystem.prepare(t.storeSystem.stateSlices.committed.value.state,o.operations)).map(({result:e})=>e),committed:!1}):a("Nothing was run, because the configuration is not loaded yet, so there is no state to query. Call the tool again once the configurator has finished loading."):o.refusal});export const applyClientTool=t.client(async(e,{context:t})=>{if("owner"!==t.getActiveMode())return a("Nothing was run, because changes cannot be applied in this session: the user may view this configuration but not change it. The query tool still works here, including mutations, to show what a change would do without keeping it.");let o=i(e);return o.ok?s(await t.graphQLSystem.execute(o.operations)):o.refusal});
|
|
File without changes
|
/package/dist/application-spec/generate-application/code/templates/{common → skills}/agent-skill.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|