@pplethai/cli 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bin.js +53 -15
- package/package.json +3 -2
- package/templates/golden-path/.dev.vars.example +10 -13
- package/templates/golden-path/CLAUDE.md +22 -7
- package/templates/golden-path/README.md +13 -8
- package/templates/golden-path/package.json +1 -0
- package/templates/golden-path/shared/api.ts +36 -3
- package/templates/golden-path/src/auth.ts +101 -16
- package/templates/golden-path/src/dev-personas.ts +88 -0
- package/templates/golden-path/src/env.ts +4 -2
- package/templates/golden-path/src/index.ts +8 -7
- package/templates/golden-path/src/vite-env.d.ts +14 -0
- package/templates/golden-path/test/harness.ts +6 -2
- package/templates/golden-path/test/smoke.test.ts +98 -15
- package/templates/golden-path/web/App.tsx +1 -1
- package/templates/golden-path/web/main.tsx +2 -2
- package/templates/golden-path/web/pple.ts +6 -5
- package/dist/api.js +0 -108
- package/dist/cli.js +0 -151
- package/dist/commands/auth.js +0 -32
- package/dist/commands/deploy.js +0 -113
- package/dist/commands/env.js +0 -70
- package/dist/commands/info.js +0 -238
- package/dist/commands/init.js +0 -130
- package/dist/commands/upgrade.js +0 -29
- package/dist/credentials.js +0 -53
- package/dist/deps.js +0 -87
- package/dist/device-flow.js +0 -122
- package/dist/errors.js +0 -16
- package/dist/git.js +0 -127
- package/dist/link.js +0 -59
- package/dist/node-deps.js +0 -107
- package/dist/npm.js +0 -127
- package/dist/scaffold.js +0 -58
- package/dist/session.js +0 -29
- package/dist/skills.js +0 -86
- package/dist/ui.js +0 -12
- package/dist/update.js +0 -142
package/README.md
CHANGED
|
@@ -109,7 +109,7 @@ echo '{ "updateCheck": false }' > ~/.config/pple/config.json # this machine
|
|
|
109
109
|
npm install
|
|
110
110
|
npm test # drives whole commands against a fake Provisioner and real git
|
|
111
111
|
npm run typecheck
|
|
112
|
-
npm run build # bundles the template and Skills,
|
|
112
|
+
npm run build # bundles the template and Skills, then esbuild → dist/bin.js
|
|
113
113
|
```
|
|
114
114
|
|
|
115
115
|
Tests run the real command path — real `git` in a temp directory, a fake
|
package/dist/bin.js
CHANGED
|
@@ -1,16 +1,54 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import os from "node:
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
process.exitCode = 1;
|
|
16
|
-
|
|
2
|
+
import Rr from"node:os";var s=class extends Error{constructor(r,n){super(r);this.hint=n;this.name="CliError"}hint},et=new s("\u0E04\u0E38\u0E13\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A","\u0E23\u0E31\u0E19 `pple auth login` \u0E01\u0E48\u0E2D\u0E19"),x=new s("\u0E01\u0E32\u0E23\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E2B\u0E21\u0E14\u0E2D\u0E32\u0E22\u0E38\u0E41\u0E25\u0E49\u0E27","\u0E23\u0E31\u0E19 `pple auth login` \u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07");var $=class{constructor(e,r){this.deps=e;this.token=r}deps;token;me(){return this.request("GET","/me")}app(e){return this.request("GET",`/apps/${encodeURIComponent(e)}`,{slug:e})}createApp(e){return this.request("POST","/apps",{body:{name:e}})}repoToken(e){return this.request("POST",`/apps/${encodeURIComponent(e)}/repo-token`,{slug:e})}deploys(e){return this.request("GET",`/apps/${encodeURIComponent(e)}/deploys`,{slug:e}).then(r=>r.deploys)}env(e){return this.request("GET",`/apps/${encodeURIComponent(e)}/env`,{slug:e}).then(r=>r.env)}metrics(e){return this.request("GET",`/apps/${encodeURIComponent(e)}/metrics`,{slug:e})}collaborators(e){return this.request("GET",`/apps/${encodeURIComponent(e)}/collaborators`,{slug:e}).then(r=>r.collaborators)}requests(e){return this.request("GET",`/apps/${encodeURIComponent(e)}/requests`,{slug:e}).then(r=>r.requests)}invites(e){return this.request("GET",`/apps/${encodeURIComponent(e)}/invites`,{slug:e}).then(r=>r.invites)}setEnv(e,r,n,i){return this.request("PUT",`/apps/${encodeURIComponent(e)}/env/${encodeURIComponent(r)}`,{slug:e,body:{value:n,secret:i}})}deleteEnv(e,r){return this.request("DELETE",`/apps/${encodeURIComponent(e)}/env/${encodeURIComponent(r)}`,{slug:e,envKey:r})}async request(e,r,n={}){let i=`${this.deps.config.apiBase}${r}`,o={authorization:`Bearer ${this.token}`},u;n.body!==void 0&&(o["content-type"]="application/json",u=JSON.stringify(n.body));let a=await this.deps.fetch(i,{method:e,headers:o,body:u}).catch(()=>null);if(!a)throw new s("\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D PPLE Platform \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49","\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E01\u0E32\u0E23\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D\u0E2D\u0E34\u0E19\u0E40\u0E17\u0E2D\u0E23\u0E4C\u0E40\u0E19\u0E47\u0E15\u0E41\u0E25\u0E49\u0E27\u0E25\u0E2D\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07");if(a.ok)return a.status===204?void 0:await a.json();let c=await a.json().catch(()=>({}));throw me(a.status,c.error,n)}};function me(t,e,r={}){let{slug:n,envKey:i}=r;return t===401?x:e==="not_org_member"?new s("PPLE ID \u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E2D\u0E22\u0E39\u0E48\u0E43\u0E19\u0E2D\u0E07\u0E04\u0E4C\u0E01\u0E23\u0E02\u0E2D\u0E07\u0E1E\u0E23\u0E23\u0E04 \u0E08\u0E36\u0E07\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E41\u0E2D\u0E1B\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49","\u0E01\u0E23\u0E38\u0E13\u0E32\u0E15\u0E34\u0E14\u0E15\u0E48\u0E2D\u0E2B\u0E31\u0E27\u0E2B\u0E19\u0E49\u0E32\u0E17\u0E35\u0E21\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E2A\u0E34\u0E17\u0E18\u0E34\u0E4C \u0E41\u0E25\u0E49\u0E27\u0E25\u0E2D\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07"):e==="agreement_required"?new s("\u0E04\u0E38\u0E13\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E22\u0E2D\u0E21\u0E23\u0E31\u0E1A\u0E02\u0E49\u0E2D\u0E15\u0E01\u0E25\u0E07\u0E1C\u0E39\u0E49\u0E1E\u0E31\u0E12\u0E19\u0E32","\u0E22\u0E2D\u0E21\u0E23\u0E31\u0E1A\u0E44\u0E14\u0E49\u0E17\u0E35\u0E48 https://console.ppleth.ai \u0E41\u0E25\u0E49\u0E27\u0E23\u0E31\u0E19\u0E04\u0E33\u0E2A\u0E31\u0E48\u0E07\u0E19\u0E35\u0E49\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07"):e==="app_has_no_repo"?new s(`${n?`"${n}"`:"\u0E41\u0E2D\u0E1B\u0E19\u0E35\u0E49"} \u0E22\u0E31\u0E07\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E44\u0E21\u0E48\u0E40\u0E2A\u0E23\u0E47\u0E08`,"\u0E23\u0E2D\u0E2A\u0E31\u0E01\u0E04\u0E23\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27\u0E25\u0E2D\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07 \u0E2B\u0E32\u0E01\u0E22\u0E31\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E41\u0E1A\u0E1A\u0E19\u0E35\u0E49 \u0E01\u0E23\u0E38\u0E13\u0E32\u0E15\u0E34\u0E14\u0E15\u0E48\u0E2D\u0E17\u0E35\u0E21\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21"):e==="invalid_key"?new s("\u0E04\u0E35\u0E22\u0E4C\u0E19\u0E35\u0E49\u0E43\u0E0A\u0E49\u0E40\u0E1B\u0E47\u0E19\u0E0A\u0E37\u0E48\u0E2D\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49","\u0E04\u0E35\u0E22\u0E4C\u0E15\u0E49\u0E2D\u0E07\u0E02\u0E36\u0E49\u0E19\u0E15\u0E49\u0E19\u0E14\u0E49\u0E27\u0E22\u0E15\u0E31\u0E27\u0E2D\u0E31\u0E01\u0E29\u0E23\u0E2B\u0E23\u0E37\u0E2D\u0E02\u0E35\u0E14\u0E25\u0E48\u0E32\u0E07 \u0E15\u0E32\u0E21\u0E14\u0E49\u0E27\u0E22\u0E15\u0E31\u0E27\u0E2D\u0E31\u0E01\u0E29\u0E23 \u0E15\u0E31\u0E27\u0E40\u0E25\u0E02 \u0E2B\u0E23\u0E37\u0E2D\u0E02\u0E35\u0E14\u0E25\u0E48\u0E32\u0E07"):e==="reserved_key"?new s("\u0E04\u0E35\u0E22\u0E4C\u0E19\u0E35\u0E49\u0E16\u0E39\u0E01\u0E2A\u0E07\u0E27\u0E19\u0E44\u0E27\u0E49\u0E42\u0E14\u0E22\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21","\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E0A\u0E37\u0E48\u0E2D\u0E2D\u0E37\u0E48\u0E19 \u2014 APP_SLUG, DB, FILES, NOTIFY_* \u0E41\u0E25\u0E30 PPLE_DEPLOY_ID \u0E16\u0E39\u0E01\u0E43\u0E0A\u0E49\u0E44\u0E1B\u0E41\u0E25\u0E49\u0E27"):e==="invalid_value"?new s("\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01\u0E04\u0E48\u0E32\u0E19\u0E35\u0E49\u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08","\u0E2A\u0E48\u0E07\u0E04\u0E48\u0E32\u0E21\u0E32\u0E40\u0E1B\u0E47\u0E19 argument \u0E1C\u0E48\u0E32\u0E19 `--file` \u0E2B\u0E23\u0E37\u0E2D\u0E17\u0E32\u0E07 stdin"):t===404?i?new s(`\u0E41\u0E2D\u0E1B\u0E19\u0E35\u0E49\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32 "${i}" \u0E44\u0E27\u0E49`,"\u0E23\u0E31\u0E19 `pple env list` \u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E14\u0E39\u0E04\u0E48\u0E32\u0E17\u0E35\u0E48\u0E15\u0E31\u0E49\u0E07\u0E44\u0E27\u0E49"):new s(n?`\u0E44\u0E21\u0E48\u0E21\u0E35\u0E41\u0E2D\u0E1B\u0E0A\u0E37\u0E48\u0E2D "${n}" \u0E17\u0E35\u0E48\u0E40\u0E1B\u0E47\u0E19\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13`:"\u0E44\u0E21\u0E48\u0E1E\u0E1A\u0E2A\u0E34\u0E48\u0E07\u0E19\u0E35\u0E49\u0E1A\u0E19\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21","\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E41\u0E2D\u0E1B\u0E44\u0E14\u0E49\u0E17\u0E35\u0E48 https://console.ppleth.ai"):t>=500||e==="sso_unavailable"?new s("PPLE Platform \u0E01\u0E33\u0E25\u0E31\u0E07\u0E21\u0E35\u0E1B\u0E31\u0E0D\u0E2B\u0E32\u0E43\u0E19\u0E02\u0E13\u0E30\u0E19\u0E35\u0E49","\u0E23\u0E2D\u0E2A\u0E31\u0E01\u0E04\u0E23\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27\u0E25\u0E2D\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07 \u0E2B\u0E32\u0E01\u0E22\u0E31\u0E07\u0E40\u0E01\u0E34\u0E14\u0E02\u0E36\u0E49\u0E19\u0E2D\u0E35\u0E01 \u0E01\u0E23\u0E38\u0E13\u0E32\u0E41\u0E08\u0E49\u0E07\u0E17\u0E35\u0E21\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21"):new s("PPLE Platform \u0E1B\u0E0F\u0E34\u0E40\u0E2A\u0E18\u0E04\u0E33\u0E02\u0E2D\u0E19\u0E35\u0E49",e?`\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E08\u0E32\u0E01\u0E23\u0E30\u0E1A\u0E1A: ${e}`:void 0)}import D from"node:fs/promises";import ge from"node:path";var de="credentials.json",rt=384,ye=448;function T(t){return ge.join(t.configDir,de)}async function nt(t){let e=await D.readFile(T(t),"utf8").catch(()=>null);if(e===null)return null;let r;try{r=JSON.parse(e)}catch{return null}return typeof r.accessToken!="string"||r.ssoBase!==t.config.ssoBase?null:{accessToken:r.accessToken,refreshToken:typeof r.refreshToken=="string"?r.refreshToken:null,expiresAt:typeof r.expiresAt=="number"?r.expiresAt:null,ssoBase:r.ssoBase}}async function S(t,e){await D.mkdir(t.configDir,{recursive:!0,mode:ye}),await D.writeFile(T(t),`${JSON.stringify(e,null,2)}
|
|
3
|
+
`,{mode:rt}),await D.chmod(T(t),rt)}async function it(t){try{return await D.unlink(T(t)),!0}catch{return!1}}var we="/oauth/v2/device_authorization",st="/oauth/v2/token",he="urn:ietf:params:oauth:grant-type:device_code",at="openid profile offline_access";function F(t){return{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams(t).toString()}}function q(t){return new s(`\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D PPLE ID (${t}) \u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49`,"\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E01\u0E32\u0E23\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D\u0E2D\u0E34\u0E19\u0E40\u0E17\u0E2D\u0E23\u0E4C\u0E40\u0E19\u0E47\u0E15\u0E41\u0E25\u0E49\u0E27\u0E25\u0E2D\u0E07 `pple auth login` \u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07")}async function ut(t){let{ssoBase:e,clientId:r}=t.config,n=await t.fetch(`${e}${we}`,F({client_id:r,scope:at})).catch(()=>null);if(!n||!n.ok)throw q(e);let i=await n.json().catch(()=>({}));if(!i.device_code||!i.user_code||!i.verification_uri)throw q(e);return{deviceCode:i.device_code,userCode:i.user_code,verificationUri:i.verification_uri,verificationUriComplete:i.verification_uri_complete??null,expiresInMs:(i.expires_in??600)*1e3,intervalMs:(i.interval??5)*1e3}}async function lt(t,e){let{ssoBase:r,clientId:n}=t.config,i=t.now()+e.expiresInMs,o=e.intervalMs;for(;t.now()<i;){await t.sleep(o);let u=await t.fetch(`${r}${st}`,F({client_id:n,grant_type:he,device_code:e.deviceCode})).catch(()=>null);if(!u)throw q(r);let a=await u.json().catch(()=>({}));if(u.ok&&a.access_token)return pt(t,a);switch(a.error){case"authorization_pending":break;case"slow_down":o+=5e3;break;case"access_denied":throw new s("\u0E01\u0E32\u0E23\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E16\u0E39\u0E01\u0E1B\u0E0F\u0E34\u0E40\u0E2A\u0E18\u0E43\u0E19\u0E40\u0E1A\u0E23\u0E32\u0E27\u0E4C\u0E40\u0E0B\u0E2D\u0E23\u0E4C","\u0E2B\u0E32\u0E01\u0E44\u0E21\u0E48\u0E43\u0E0A\u0E48\u0E04\u0E38\u0E13\u0E17\u0E35\u0E48\u0E1B\u0E0F\u0E34\u0E40\u0E2A\u0E18 \u0E43\u0E2B\u0E49\u0E23\u0E31\u0E19 `pple auth login` \u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07");case"expired_token":throw ot();default:throw new s("PPLE ID \u0E1B\u0E0F\u0E34\u0E40\u0E2A\u0E18\u0E01\u0E32\u0E23\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A",a.error_description??"\u0E25\u0E2D\u0E07 `pple auth login` \u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07")}}throw ot()}function ot(){return new s("\u0E23\u0E2B\u0E31\u0E2A\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E2B\u0E21\u0E14\u0E2D\u0E32\u0E22\u0E38\u0E01\u0E48\u0E2D\u0E19\u0E44\u0E14\u0E49\u0E23\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E2D\u0E19\u0E38\u0E21\u0E31\u0E15\u0E34","\u0E23\u0E31\u0E19 `pple auth login` \u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07 \u2014 \u0E02\u0E31\u0E49\u0E19\u0E15\u0E2D\u0E19\u0E43\u0E19\u0E40\u0E1A\u0E23\u0E32\u0E27\u0E4C\u0E40\u0E0B\u0E2D\u0E23\u0E4C\u0E15\u0E49\u0E2D\u0E07\u0E17\u0E33\u0E43\u0E2B\u0E49\u0E40\u0E2A\u0E23\u0E47\u0E08\u0E20\u0E32\u0E22\u0E43\u0E19\u0E44\u0E21\u0E48\u0E01\u0E35\u0E48\u0E19\u0E32\u0E17\u0E35")}async function ct(t,e){let{ssoBase:r,clientId:n}=t.config,i=await t.fetch(`${r}${st}`,F({client_id:n,grant_type:"refresh_token",refresh_token:e,scope:at})).catch(()=>null);if(!i||!i.ok)return null;let o=await i.json().catch(()=>({}));return o.access_token?{...pt(t,o),refreshToken:o.refresh_token??e}:null}function pt(t,e){return{accessToken:e.access_token,refreshToken:e.refresh_token??null,expiresAt:typeof e.expires_in=="number"?t.now()+e.expires_in*1e3:null}}var ve=6e4;async function Pe(t){let e=await nt(t);if(!e)throw et;if(!(e.expiresAt!==null&&e.expiresAt-t.now()<ve))return e.accessToken;if(e.refreshToken){let n=await ct(t,e.refreshToken);if(n)return await S(t,{...n,ssoBase:t.config.ssoBase}),n.accessToken}throw x}async function p(t){return new $(t,await Pe(t))}async function ft(t){let e=await ut(t);t.out.say("\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E42\u0E14\u0E22\u0E40\u0E1B\u0E34\u0E14\u0E2B\u0E19\u0E49\u0E32\u0E19\u0E35\u0E49\u0E41\u0E25\u0E49\u0E27\u0E01\u0E23\u0E2D\u0E01\u0E23\u0E2B\u0E31\u0E2A:"),t.out.say(),t.out.say(` ${e.verificationUri}`),t.out.say(` \u0E23\u0E2B\u0E31\u0E2A: ${e.userCode}`),t.out.say(),t.out.say("\u0E01\u0E33\u0E25\u0E31\u0E07\u0E23\u0E2D\u0E43\u0E2B\u0E49\u0E04\u0E38\u0E13\u0E2D\u0E19\u0E38\u0E21\u0E31\u0E15\u0E34\u0E01\u0E32\u0E23\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u2026"),await t.openBrowser(e.verificationUriComplete??e.verificationUri);let r=await lt(t,e);await S(t,{...r,ssoBase:t.config.ssoBase});let n=await new $(t,r.accessToken).me();t.out.say(`\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E43\u0E19\u0E0A\u0E37\u0E48\u0E2D ${n.name??n.sub} \u0E41\u0E25\u0E49\u0E27`),n.isBuilder||t.out.say("\u0E2D\u0E35\u0E01\u0E2B\u0E19\u0E36\u0E48\u0E07\u0E02\u0E31\u0E49\u0E19\u0E15\u0E2D\u0E19\u0E01\u0E48\u0E2D\u0E19\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E41\u0E2D\u0E1B\u0E44\u0E14\u0E49: \u0E22\u0E2D\u0E21\u0E23\u0E31\u0E1A\u0E02\u0E49\u0E2D\u0E15\u0E01\u0E25\u0E07\u0E1C\u0E39\u0E49\u0E1E\u0E31\u0E12\u0E19\u0E32\u0E17\u0E35\u0E48 https://console.ppleth.ai")}async function mt(t){let e=await it(t);t.out.say(e?"\u0E2D\u0E2D\u0E01\u0E08\u0E32\u0E01\u0E23\u0E30\u0E1A\u0E1A\u0E41\u0E25\u0E49\u0E27":"\u0E04\u0E38\u0E13\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A")}async function G(t){let e=await(await p(t)).me();t.out.say(`\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E43\u0E19\u0E0A\u0E37\u0E48\u0E2D ${e.name??e.sub} \u0E41\u0E25\u0E49\u0E27`),e.isBuilder||t.out.say("\u0E04\u0E38\u0E13\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E22\u0E2D\u0E21\u0E23\u0E31\u0E1A\u0E02\u0E49\u0E2D\u0E15\u0E01\u0E25\u0E07\u0E1C\u0E39\u0E49\u0E1E\u0E31\u0E12\u0E19\u0E32 \u2014 \u0E22\u0E2D\u0E21\u0E23\u0E31\u0E1A\u0E44\u0E14\u0E49\u0E17\u0E35\u0E48 https://console.ppleth.ai")}var R="main",Ee="x-access-token";async function d(t,e,r,n){return t.run("git",n?["-c","credential.helper=",...r]:r,{cwd:e,env:{GIT_TERMINAL_PROMPT:"0",...n?{GIT_ASKPASS:t.gitAskpass,PPLE_GIT_USER:Ee,PPLE_GIT_TOKEN:n.token}:{}}})}function gt(t){return["-c",`user.name=${t.author.name}`,"-c",`user.email=${t.author.email}`]}function dt(t){return/authentication|could not read|403|denied|not found/i.test(`${t.stdout}
|
|
4
|
+
${t.stderr}`)}function yt(t,e){return new s(`\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21\u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E43\u0E2B\u0E49\u0E40\u0E04\u0E23\u0E37\u0E48\u0E2D\u0E07\u0E19\u0E35\u0E49${t}`,`\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E27\u0E48\u0E32\u0E41\u0E2D\u0E1B\u0E22\u0E31\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E2D\u0E22\u0E39\u0E48\u0E17\u0E35\u0E48 https://console.ppleth.ai \u0E41\u0E25\u0E49\u0E27\u0E23\u0E31\u0E19 \`${e}\` \u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07`)}function wt(t){return new s("\u0E2D\u0E48\u0E32\u0E19\u0E42\u0E1F\u0E25\u0E40\u0E14\u0E2D\u0E23\u0E4C\u0E02\u0E2D\u0E07\u0E41\u0E2D\u0E1B\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49",t.stderr.trim())}async function k(t,e,r,n,i){let o=await d(t,e,r,i).catch(()=>{throw new s("\u0E40\u0E04\u0E23\u0E37\u0E48\u0E2D\u0E07\u0E19\u0E35\u0E49\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35\u0E40\u0E04\u0E23\u0E37\u0E48\u0E2D\u0E07\u0E21\u0E37\u0E2D\u0E17\u0E35\u0E48 PPLE CLI \u0E15\u0E49\u0E2D\u0E07\u0E43\u0E0A\u0E49","\u0E15\u0E34\u0E14\u0E15\u0E31\u0E49\u0E07 git (https://git-scm.com/downloads) \u0E41\u0E25\u0E49\u0E27\u0E23\u0E31\u0E19\u0E04\u0E33\u0E2A\u0E31\u0E48\u0E07\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07")});if(o.code!==0)throw n(o);return o}async function ht(t,e,r,n){await k(t,t.cwd,["clone",e,r],i=>dt(i)?yt("\u0E40\u0E02\u0E49\u0E32\u0E16\u0E36\u0E07\u0E42\u0E04\u0E49\u0E14\u0E02\u0E2D\u0E07\u0E41\u0E2D\u0E1B\u0E04\u0E38\u0E13","pple init"):new s("\u0E14\u0E36\u0E07\u0E42\u0E04\u0E49\u0E14\u0E02\u0E2D\u0E07\u0E41\u0E2D\u0E1B\u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08",i.stderr.trim()),n)}async function I(t,e){return(await k(t,e,["status","--porcelain"],wt)).stdout.trim()!==""}async function L(t,e,r,n){await k(t,e,["add","-A"],wt),await k(t,e,[...gt(n),"commit","-m",r],i=>new s("\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08",i.stderr.trim()))}async function vt(t,e){return(await k(t,e,["rev-parse","HEAD"],n=>new s("\u0E2D\u0E48\u0E32\u0E19\u0E1B\u0E23\u0E30\u0E27\u0E31\u0E15\u0E34\u0E02\u0E2D\u0E07\u0E41\u0E2D\u0E1B\u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08",n.stderr.trim()))).stdout.trim()}async function Pt(t,e,r){await d(t,e,["fetch","origin",R],r);let n=await d(t,e,["rev-parse","HEAD"]),i=await d(t,e,["rev-parse",`origin/${R}`]);return n.code!==0||i.code!==0?!1:n.stdout.trim()===i.stdout.trim()}async function $t(t,e,r){let n=["push","origin",`HEAD:${R}`],i=await d(t,e,n,r);if(i.code===0)return;let o=`${i.stdout}
|
|
5
|
+
${i.stderr}`;if(!/rejected|non-fast-forward|fetch first/i.test(o))throw dt(i)?yt("\u0E2A\u0E48\u0E07\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E44\u0E1B\u0E22\u0E31\u0E07\u0E41\u0E2D\u0E1B\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13","pple deploy"):new s("\u0E2A\u0E48\u0E07\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08",i.stderr.trim());if(t.out.say("\u0E21\u0E35\u0E04\u0E19\u0E2D\u0E37\u0E48\u0E19\u0E41\u0E01\u0E49\u0E44\u0E02\u0E41\u0E2D\u0E1B\u0E19\u0E35\u0E49 \u2014 \u0E01\u0E33\u0E25\u0E31\u0E07\u0E19\u0E33\u0E07\u0E32\u0E19\u0E02\u0E2D\u0E07\u0E40\u0E02\u0E32\u0E40\u0E02\u0E49\u0E32\u0E21\u0E32\u0E01\u0E48\u0E2D\u0E19\u2026"),(await d(t,e,[...gt(r),"pull","--rebase","origin",R],r)).code!==0)throw await d(t,e,["rebase","--abort"]),new s("\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E02\u0E31\u0E14\u0E41\u0E22\u0E49\u0E07\u0E01\u0E31\u0E1A\u0E17\u0E35\u0E48\u0E04\u0E19\u0E2D\u0E37\u0E48\u0E19\u0E14\u0E35\u0E1E\u0E25\u0E2D\u0E22\u0E44\u0E1B\u0E41\u0E25\u0E49\u0E27","\u0E43\u0E2B\u0E49 AI coding agent \u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E23\u0E27\u0E21\u0E2A\u0E2D\u0E07\u0E40\u0E27\u0E2D\u0E23\u0E4C\u0E0A\u0E31\u0E19\u0E40\u0E02\u0E49\u0E32\u0E14\u0E49\u0E27\u0E22\u0E01\u0E31\u0E19 \u0E41\u0E25\u0E49\u0E27\u0E23\u0E31\u0E19 `pple deploy` \u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07");let a=await d(t,e,n,r);if(a.code!==0)throw new s("\u0E2A\u0E48\u0E07\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08",a.stderr.trim())}import K from"node:fs/promises";import A from"node:path";var H=".pple",Et="app.json";async function Dt(t,e){await K.mkdir(A.join(t,H),{recursive:!0}),await K.writeFile(A.join(t,H,Et),`${JSON.stringify(e,null,2)}
|
|
6
|
+
`)}async function y(t){let e=await V(t);if(e)return e;throw new s("\u0E42\u0E1F\u0E25\u0E40\u0E14\u0E2D\u0E23\u0E4C\u0E19\u0E35\u0E49\u0E44\u0E21\u0E48\u0E43\u0E0A\u0E48\u0E41\u0E2D\u0E1B PPLE","\u0E40\u0E02\u0E49\u0E32\u0E44\u0E1B\u0E43\u0E19\u0E42\u0E1F\u0E25\u0E40\u0E14\u0E2D\u0E23\u0E4C\u0E02\u0E2D\u0E07\u0E41\u0E2D\u0E1B \u0E2B\u0E23\u0E37\u0E2D\u0E23\u0E31\u0E19 `pple init <app>` \u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E41\u0E2D\u0E1B\u0E43\u0E2B\u0E21\u0E48")}async function V(t){let e=A.resolve(t.cwd);for(;;){let r=A.join(e,H,Et),n=await K.readFile(r,"utf8").catch(()=>null);if(n!==null){let o=De(n);if(o)return{...o,dir:e};throw new s("\u0E01\u0E32\u0E23\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E42\u0E22\u0E07\u0E41\u0E2D\u0E1B\u0E19\u0E35\u0E49\u0E01\u0E31\u0E1A\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21\u0E40\u0E2A\u0E35\u0E22\u0E2B\u0E32\u0E22","\u0E23\u0E31\u0E19 `pple init <app>` \u0E43\u0E19\u0E42\u0E1F\u0E25\u0E40\u0E14\u0E2D\u0E23\u0E4C\u0E43\u0E2B\u0E21\u0E48\u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07")}let i=A.dirname(e);if(i===e)break;e=i}return null}function De(t){try{let e=JSON.parse(t);return typeof e.slug!="string"||e.slug===""?null:{slug:e.slug,apiBase:typeof e.apiBase=="string"?e.apiBase:"",url:typeof e.url=="string"?e.url:""}}catch{return null}}import{createHash as be}from"node:crypto";import g from"node:fs/promises";import w from"node:path";import{realpath as ke}from"node:fs/promises";import J from"node:path";var Y="@pplethai/cli",m=`npm install -g ${Y}`;async function N(t){let e=await t.fetch(`${t.config.registryBase}/${Y}/latest`,{headers:{accept:"application/json"}}).catch(()=>null);if(!e?.ok)return null;let r=await e.json().catch(()=>null);return typeof r?.version=="string"&&r.version!==""?r.version:null}async function O(t){let e=await t.run("npm",["root","-g"],{cwd:t.cwd}).catch(()=>null);if(!e||e.code!==0)return!1;let r=e.stdout.trim();return r===""?!1:Ae(r,t.packageDir)}function j(t,e){return t.run("npm",["install","-g",`${Y}@${e}`],{cwd:t.cwd}).catch(r=>({code:1,stdout:"",stderr:r instanceof Error?r.message:String(r)}))}async function Ae(t,e){let[r,n]=await Promise.all([kt(t),kt(e)]),i=J.relative(r,n);return i!==""&&!i.startsWith("..")&&!J.isAbsolute(i)}async function kt(t){return ke(t).catch(()=>J.resolve(t))}function B(t,e){let r=At(t),n=At(e);if(!r)return!1;if(!n)return!0;for(let i=0;i<3;i+=1)if(r.parts[i]!==n.parts[i])return r.parts[i]>n.parts[i];return _e(r.prerelease,n.prerelease)>0}function At(t){let e=/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/.exec(t.trim());return e?{parts:[Number(e[1]),Number(e[2]),Number(e[3])],prerelease:e[4]?e[4].split("."):[]}:null}function _e(t,e){if(t.length===0&&e.length===0)return 0;if(t.length===0)return 1;if(e.length===0)return-1;for(let r=0;r<Math.max(t.length,e.length);r+=1){let n=t[r],i=e[r];if(n===void 0)return-1;if(i===void 0)return 1;let o=/^\d+$/.test(n)&&/^\d+$/.test(i);if(n!==i)return o?Number(n)>Number(i)?1:-1:n>i?1:-1}return 0}function _t(t){return`${t.stderr}
|
|
7
|
+
${t.stdout}`.split(`
|
|
8
|
+
`).map(r=>r.replace(/^npm (ERR!|error|warn)\s*/i,"").trim()).filter(r=>r!=="").slice(0,3).join(`
|
|
9
|
+
`)||"\u0E2B\u0E22\u0E38\u0E14\u0E17\u0E33\u0E07\u0E32\u0E19\u0E42\u0E14\u0E22\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E23\u0E30\u0E1A\u0E38\u0E2A\u0E32\u0E40\u0E2B\u0E15\u0E38"}var xt=w.join(".claude","skills","pple-platform"),bt=`${xt.split(w.sep).join("/")}/`;async function U(t,e){let r=t.skillsDir;if(await g.readdir(r).catch(()=>null)===null)throw new s("\u0E44\u0E21\u0E48\u0E1E\u0E1A Skill \u0E02\u0E2D\u0E07 PPLE Platform \u0E43\u0E19\u0E01\u0E32\u0E23\u0E15\u0E34\u0E14\u0E15\u0E31\u0E49\u0E07 CLI \u0E0A\u0E38\u0E14\u0E19\u0E35\u0E49",`\u0E15\u0E34\u0E14\u0E15\u0E31\u0E49\u0E07 CLI \u0E43\u0E2B\u0E21\u0E48 (\`${m}\`) \u0E41\u0E25\u0E49\u0E27\u0E25\u0E2D\u0E07\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07`);let i=w.join(e,xt),o=await Ct(i);await Ce(r,i),await xe(e);let u=await Ct(i);o!==u&&t.out.say(o===null?"\u0E15\u0E34\u0E14\u0E15\u0E31\u0E49\u0E07 Skill \u0E02\u0E2D\u0E07\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21\u0E41\u0E25\u0E49\u0E27":"\u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15 Skill \u0E02\u0E2D\u0E07\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21\u0E41\u0E25\u0E49\u0E27")}async function Ce(t,e){await g.rm(e,{recursive:!0,force:!0}),await Tt(t,e)}async function Tt(t,e){await g.mkdir(e,{recursive:!0});for(let r of await g.readdir(t,{withFileTypes:!0})){if(r.name===".DS_Store")continue;let n=w.join(t,r.name),i=w.join(e,r.name);r.isDirectory()?await Tt(n,i):await g.copyFile(n,i)}}async function Ct(t){let e=await St(t).catch(()=>null);if(e===null)return null;let r=be("sha256");for(let n of e.sort())r.update(n),r.update("\0"),r.update(await g.readFile(w.join(t,n))),r.update("\0");return r.digest("hex")}async function St(t,e=""){let r=await g.readdir(t,{withFileTypes:!0}),n=[];for(let i of r){if(i.name===".DS_Store")continue;let o=e===""?i.name:`${e}/${i.name}`;i.isDirectory()?n.push(...await St(w.join(t,i.name),o)):n.push(o)}return n}async function xe(t){let e=w.join(t,".gitignore"),r=await g.readFile(e,"utf8").catch(()=>"");if(r.split(`
|
|
10
|
+
`).some(o=>o.trim()===bt))return;let i=r.endsWith(`
|
|
11
|
+
`)||r===""?r:`${r}
|
|
12
|
+
`;await g.writeFile(e,`${i}${bt}
|
|
13
|
+
`)}var Te=3e3,Se=3*6e4,Re=10*6e4,Ie=20;async function Rt(t,e){let r=await y(t);if(r.apiBase!==""&&r.apiBase!==t.config.apiBase)throw new s("\u0E41\u0E2D\u0E1B\u0E19\u0E35\u0E49\u0E2D\u0E22\u0E39\u0E48\u0E1A\u0E19 PPLE Platform \u0E04\u0E19\u0E25\u0E30\u0E15\u0E31\u0E27\u0E01\u0E31\u0E1A\u0E17\u0E35\u0E48\u0E04\u0E38\u0E13\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E2D\u0E22\u0E39\u0E48",`\u0E41\u0E2D\u0E1B\u0E19\u0E35\u0E49\u0E16\u0E39\u0E01\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E44\u0E27\u0E49\u0E01\u0E31\u0E1A ${r.apiBase}`);let n=await p(t),i=await n.app(r.slug);if(i.status==="retired")throw new s(`"${i.name}" \u0E16\u0E39\u0E01\u0E1B\u0E25\u0E14\u0E23\u0E30\u0E27\u0E32\u0E07\u0E41\u0E25\u0E49\u0E27`,"\u0E41\u0E2D\u0E1B\u0E17\u0E35\u0E48\u0E1B\u0E25\u0E14\u0E23\u0E30\u0E27\u0E32\u0E07\u0E41\u0E25\u0E49\u0E27\u0E14\u0E35\u0E1E\u0E25\u0E2D\u0E22\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49 \u0E2B\u0E32\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23\u0E2A\u0E32\u0E19\u0E07\u0E32\u0E19\u0E19\u0E35\u0E49\u0E15\u0E48\u0E2D \u0E43\u0E2B\u0E49\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E41\u0E2D\u0E1B\u0E43\u0E2B\u0E21\u0E48\u0E43\u0E19\u0E04\u0E2D\u0E19\u0E42\u0E0B\u0E25");if(i.status!=="ready")throw new s(`"${i.name}" \u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E1E\u0E23\u0E49\u0E2D\u0E21\u0E23\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07`,i.error?`\u0E01\u0E32\u0E23\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E1E\u0E1A\u0E1B\u0E31\u0E0D\u0E2B\u0E32: ${i.error}`:"\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E44\u0E14\u0E49\u0E17\u0E35\u0E48 https://console.ppleth.ai \u0E41\u0E25\u0E49\u0E27\u0E25\u0E2D\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E43\u0E19\u0E2D\u0E35\u0E01\u0E2A\u0E31\u0E01\u0E04\u0E23\u0E39\u0E48");let o=await n.repoToken(r.slug);if(await U(t,r.dir),await I(t,r.dir))t.out.say("\u0E01\u0E33\u0E25\u0E31\u0E07\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u2026"),await L(t,r.dir,e.message??`\u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15 ${i.name}`,o);else if(await Pt(t,r.dir,o)){t.out.say(`\u0E44\u0E21\u0E48\u0E21\u0E35\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E43\u0E2B\u0E21\u0E48 \u2014 ${i.name} \u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19\u0E2D\u0E22\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27\u0E17\u0E35\u0E48 ${i.url}`);return}t.out.say("\u0E01\u0E33\u0E25\u0E31\u0E07\u0E2A\u0E48\u0E07\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u2026"),await $t(t,r.dir,o);let u=await vt(t,r.dir);t.out.say("\u0E01\u0E33\u0E25\u0E31\u0E07\u0E1A\u0E34\u0E25\u0E14\u0E4C\u0E41\u0E2D\u0E1B\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u2026 (\u0E1B\u0E01\u0E15\u0E34\u0E43\u0E0A\u0E49\u0E40\u0E27\u0E25\u0E32\u0E23\u0E32\u0E27\u0E2B\u0E19\u0E36\u0E48\u0E07\u0E19\u0E32\u0E17\u0E35)");let a=await Le(t,n,r.slug,u);Oe(t,i,a)}async function Le(t,e,r,n){let i=t.now(),o;for(;;){let a=(await e.deploys(r)).find(fe=>fe.commit===n);if(a&&(o=a,a.status!=="building"))return a;if(t.now()-i>=(o?Re:Se))throw new s(o?"\u0E2A\u0E48\u0E07\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E41\u0E25\u0E49\u0E27 \u0E41\u0E15\u0E48\u0E01\u0E32\u0E23\u0E1A\u0E34\u0E25\u0E14\u0E4C\u0E43\u0E0A\u0E49\u0E40\u0E27\u0E25\u0E32\u0E19\u0E32\u0E19\u0E01\u0E27\u0E48\u0E32\u0E17\u0E35\u0E48\u0E04\u0E32\u0E14\u0E44\u0E27\u0E49":"\u0E2A\u0E48\u0E07\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E41\u0E25\u0E49\u0E27 \u0E41\u0E15\u0E48\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E40\u0E23\u0E34\u0E48\u0E21\u0E1A\u0E34\u0E25\u0E14\u0E4C",`\u0E15\u0E34\u0E14\u0E15\u0E32\u0E21\u0E08\u0E19\u0E40\u0E2A\u0E23\u0E47\u0E08\u0E44\u0E14\u0E49\u0E17\u0E35\u0E48 https://console.ppleth.ai/apps/${r}`);await t.sleep(Te)}}var Ne="superseded by a newer deploy";function Oe(t,e,r){if(r.status==="failed"){if(r.error===Ne)throw new s("\u0E21\u0E35\u0E01\u0E32\u0E23\u0E14\u0E35\u0E1E\u0E25\u0E2D\u0E22\u0E04\u0E23\u0E31\u0E49\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E21\u0E32\u0E41\u0E17\u0E19\u0E17\u0E35\u0E48\u0E04\u0E23\u0E31\u0E49\u0E07\u0E17\u0E35\u0E48\u0E04\u0E38\u0E13\u0E01\u0E33\u0E25\u0E31\u0E07\u0E23\u0E2D\u0E2D\u0E22\u0E39\u0E48",`\u0E15\u0E34\u0E14\u0E15\u0E32\u0E21\u0E01\u0E32\u0E23\u0E14\u0E35\u0E1E\u0E25\u0E2D\u0E22\u0E04\u0E23\u0E31\u0E49\u0E07\u0E19\u0E31\u0E49\u0E19\u0E44\u0E14\u0E49\u0E17\u0E35\u0E48 https://console.ppleth.ai/apps/${e.slug}`);let i=r.log?je(r.log,Ie):r.error;throw i&&(t.out.say(),t.out.say(i),t.out.say()),new s(`\u0E1A\u0E34\u0E25\u0E14\u0E4C ${e.name} \u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08 \u0E2A\u0E34\u0E48\u0E07\u0E17\u0E35\u0E48\u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19\u0E2D\u0E22\u0E39\u0E48\u0E08\u0E36\u0E07\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07`,i?"\u0E2A\u0E48\u0E07\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E14\u0E49\u0E32\u0E19\u0E1A\u0E19\u0E43\u0E2B\u0E49 AI coding agent \u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13 \u2014 \u0E43\u0E19\u0E19\u0E31\u0E49\u0E19\u0E1A\u0E2D\u0E01\u0E27\u0E48\u0E32\u0E15\u0E49\u0E2D\u0E07\u0E41\u0E01\u0E49\u0E2D\u0E30\u0E44\u0E23":`\u0E14\u0E39\u0E23\u0E32\u0E22\u0E25\u0E30\u0E40\u0E2D\u0E35\u0E22\u0E14\u0E44\u0E14\u0E49\u0E17\u0E35\u0E48 https://console.ppleth.ai/apps/${e.slug}`)}let n=r.migrations.applied??[];if(n.length>0&&t.out.say(`\u0E43\u0E0A\u0E49 migration ${n.length} \u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E01\u0E31\u0E1A\u0E10\u0E32\u0E19\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E41\u0E25\u0E49\u0E27`),r.status==="unverified"){t.out.say(`\u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15 ${e.name} \u0E41\u0E25\u0E49\u0E27 \u0E41\u0E15\u0E48\u0E41\u0E2D\u0E1B\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E15\u0E2D\u0E1A\u0E2A\u0E19\u0E2D\u0E07`),t.out.say(`\u0E23\u0E2D\u0E2A\u0E31\u0E01\u0E04\u0E23\u0E39\u0E48 \u0E41\u0E25\u0E49\u0E27\u0E40\u0E1B\u0E34\u0E14 ${e.url}`);return}t.out.say(`${e.name} \u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19\u0E44\u0E14\u0E49\u0E41\u0E25\u0E49\u0E27\u0E17\u0E35\u0E48 ${e.url}`)}function je(t,e){return t.split(`
|
|
14
|
+
`).slice(-e).join(`
|
|
15
|
+
`).trim()}import Be from"node:fs/promises";import Ue from"node:path";async function It(t){let e=await y(t),n=await(await p(t)).env(e.slug);if(n.length===0){t.out.say("\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E43\u0E14 \u0E46"),t.out.say("\u0E15\u0E31\u0E27\u0E41\u0E1B\u0E23\u0E17\u0E35\u0E48\u0E04\u0E38\u0E13\u0E15\u0E31\u0E49\u0E07\u0E08\u0E30\u0E21\u0E35\u0E1C\u0E25\u0E43\u0E19\u0E01\u0E32\u0E23\u0E14\u0E35\u0E1E\u0E25\u0E2D\u0E22\u0E04\u0E23\u0E31\u0E49\u0E07\u0E16\u0E31\u0E14\u0E44\u0E1B");return}for(let i of n)i.secret?t.out.say(`${i.key}=(secret)`):t.out.say(`${i.key}=${i.value??""}`);t.out.say(""),t.out.say("\u0E08\u0E30\u0E21\u0E35\u0E1C\u0E25\u0E43\u0E19\u0E01\u0E32\u0E23\u0E14\u0E35\u0E1E\u0E25\u0E2D\u0E22\u0E04\u0E23\u0E31\u0E49\u0E07\u0E16\u0E31\u0E14\u0E44\u0E1B")}async function Lt(t,e){let r=await y(t),n=await Me(t,e),o=await(await p(t)).setEnv(r.slug,e.key,n,e.secret);t.out.say(`\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01 ${o.key}${o.secret?" (secret)":""} \u0E41\u0E25\u0E49\u0E27`),t.out.say("\u0E08\u0E30\u0E21\u0E35\u0E1C\u0E25\u0E43\u0E19\u0E01\u0E32\u0E23\u0E14\u0E35\u0E1E\u0E25\u0E2D\u0E22\u0E04\u0E23\u0E31\u0E49\u0E07\u0E16\u0E31\u0E14\u0E44\u0E1B")}async function Nt(t,e){let r=await y(t);await(await p(t)).deleteEnv(r.slug,e),t.out.say(`\u0E25\u0E1A ${e} \u0E41\u0E25\u0E49\u0E27`),t.out.say("\u0E08\u0E30\u0E21\u0E35\u0E1C\u0E25\u0E43\u0E19\u0E01\u0E32\u0E23\u0E14\u0E35\u0E1E\u0E25\u0E2D\u0E22\u0E04\u0E23\u0E31\u0E49\u0E07\u0E16\u0E31\u0E14\u0E44\u0E1B")}async function Me(t,e){if(e.file!==void 0&&e.value!==void 0)throw new s("\u0E2A\u0E48\u0E07\u0E04\u0E48\u0E32\u0E21\u0E32\u0E40\u0E1B\u0E47\u0E19 argument \u0E2B\u0E23\u0E37\u0E2D\u0E1C\u0E48\u0E32\u0E19 `--file` \u0E2D\u0E22\u0E48\u0E32\u0E07\u0E43\u0E14\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E2B\u0E19\u0E36\u0E48\u0E07 \u0E44\u0E21\u0E48\u0E43\u0E0A\u0E48\u0E17\u0E31\u0E49\u0E07\u0E2A\u0E2D\u0E07\u0E2D\u0E22\u0E48\u0E32\u0E07");if(e.file!==void 0){let r=Ue.resolve(t.cwd,e.file),n=await Be.readFile(r,"utf8").catch(()=>null);if(n===null)throw new s(`\u0E2D\u0E48\u0E32\u0E19\u0E44\u0E1F\u0E25\u0E4C ${e.file} \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49`,"\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E1E\u0E32\u0E18\u0E41\u0E25\u0E49\u0E27\u0E25\u0E2D\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07");return n}if(e.value!==void 0)return e.value;if(t.interactive)throw new s("`pple env set` \u0E15\u0E49\u0E2D\u0E07\u0E23\u0E30\u0E1A\u0E38\u0E04\u0E48\u0E32","\u0E2A\u0E48\u0E07\u0E04\u0E48\u0E32\u0E21\u0E32\u0E40\u0E1B\u0E47\u0E19 argument \u0E1C\u0E48\u0E32\u0E19 `--file` \u0E2B\u0E23\u0E37\u0E2D pipe \u0E17\u0E32\u0E07 stdin");return t.readStdin()}var Fe=20,Ge=/[\u0E31\u0E34-\u0E3A\u0E47-\u0E4E]/g;function l(t,e){let r=t.replace(Ge,"").length;return t+" ".repeat(Math.max(0,e-r))}var Ke={ready:"\u0E1E\u0E23\u0E49\u0E2D\u0E21\u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19",provisioning:"\u0E01\u0E33\u0E25\u0E31\u0E07\u0E08\u0E31\u0E14\u0E40\u0E15\u0E23\u0E35\u0E22\u0E21",failed:"\u0E25\u0E49\u0E21\u0E40\u0E2B\u0E25\u0E27",retired:"\u0E1B\u0E25\u0E14\u0E23\u0E30\u0E27\u0E32\u0E07\u0E41\u0E25\u0E49\u0E27"},Ot={draft:"\u0E09\u0E1A\u0E31\u0E1A\u0E23\u0E48\u0E32\u0E07",beta:"\u0E17\u0E14\u0E25\u0E2D\u0E07\u0E43\u0E0A\u0E49",live:"\u0E40\u0E1C\u0E22\u0E41\u0E1E\u0E23\u0E48\u0E08\u0E23\u0E34\u0E07"},He={owner:"\u0E40\u0E08\u0E49\u0E32\u0E02\u0E2D\u0E07",collaborator:"\u0E1C\u0E39\u0E49\u0E23\u0E48\u0E27\u0E21\u0E1E\u0E31\u0E12\u0E19\u0E32"},jt={live:"\u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19\u0E2D\u0E22\u0E39\u0E48",building:"\u0E01\u0E33\u0E25\u0E31\u0E07\u0E1A\u0E34\u0E25\u0E14\u0E4C",unverified:"\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19",failed:"\u0E25\u0E49\u0E21\u0E40\u0E2B\u0E25\u0E27"},Ve={pending:"\u0E23\u0E2D\u0E14\u0E33\u0E40\u0E19\u0E34\u0E19\u0E01\u0E32\u0E23",approved:"\u0E2D\u0E19\u0E38\u0E21\u0E31\u0E15\u0E34\u0E41\u0E25\u0E49\u0E27",denied:"\u0E1B\u0E0F\u0E34\u0E40\u0E2A\u0E18\u0E41\u0E25\u0E49\u0E27"};function v(t,e){return t[e]??e}async function Bt(t,e){let r=await Je(t,e),n=await p(t),i=await n.app(r),o=i.role!=="collaborator",[u,a,c,P]=await Promise.all([n.metrics(r),n.deploys(r),n.env(r),o?Ye(n,r):Promise.resolve(null)]);We(t,i),Xe(t,u),ze(t,a),Ze(t,c),P&&(Qe(t,i,P.requests,P.invites),tr(t,P.collaborators),er(t,P.requests)),t.out.say(""),t.out.say("\u0E2B\u0E32\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E42\u0E04\u0E27\u0E15\u0E32 \u0E04\u0E48\u0E32 env \u0E1C\u0E39\u0E49\u0E23\u0E48\u0E27\u0E21\u0E1E\u0E31\u0E12\u0E19\u0E32 \u0E2B\u0E23\u0E37\u0E2D\u0E01\u0E32\u0E23\u0E40\u0E1C\u0E22\u0E41\u0E1E\u0E23\u0E48 \u0E43\u0E0A\u0E49 https://console.ppleth.ai")}async function Je(t,e){if(e)return e;try{return(await y(t)).slug}catch(r){throw r instanceof s&&r.message==="\u0E42\u0E1F\u0E25\u0E40\u0E14\u0E2D\u0E23\u0E4C\u0E19\u0E35\u0E49\u0E44\u0E21\u0E48\u0E43\u0E0A\u0E48\u0E41\u0E2D\u0E1B PPLE"?new s("\u0E41\u0E2D\u0E1B\u0E44\u0E2B\u0E19? `pple info` \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35 App Link \u0E2B\u0E23\u0E37\u0E2D slug","\u0E40\u0E02\u0E49\u0E32\u0E44\u0E1B\u0E43\u0E19\u0E42\u0E1F\u0E25\u0E40\u0E14\u0E2D\u0E23\u0E4C\u0E02\u0E2D\u0E07\u0E41\u0E2D\u0E1B \u0E43\u0E2A\u0E48 slug (`pple info <slug>`) \u0E2B\u0E23\u0E37\u0E2D\u0E40\u0E1B\u0E34\u0E14 https://console.ppleth.ai"):r}}async function Ye(t,e){let[r,n,i]=await Promise.all([t.collaborators(e),t.requests(e),t.invites(e)]);return{collaborators:r,requests:n,invites:i}}function We(t,e){t.out.say(e.name),t.out.say(` ${l("slug",18)}${e.slug}`),t.out.say(` ${l("URL",18)}${e.url}`),e.customAddress&&t.out.say(` ${l("\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48\u0E17\u0E35\u0E48\u0E01\u0E33\u0E2B\u0E19\u0E14\u0E40\u0E2D\u0E07",18)}${e.customAddress}`),t.out.say(` ${l("\u0E2A\u0E16\u0E32\u0E19\u0E30",18)}${v(Ke,e.status)}`),t.out.say(` ${l("\u0E01\u0E32\u0E23\u0E40\u0E1C\u0E22\u0E41\u0E1E\u0E23\u0E48",18)}${v(Ot,e.tier??"draft")}`),e.role&&t.out.say(` ${l("\u0E1A\u0E17\u0E1A\u0E32\u0E17\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13",18)}${v(He,e.role)}`),e.deploy&&t.out.say(` ${l("\u0E01\u0E32\u0E23\u0E14\u0E35\u0E1E\u0E25\u0E2D\u0E22\u0E1B\u0E31\u0E08\u0E08\u0E38\u0E1A\u0E31\u0E19",18)}${v(jt,e.deploy.status)}`+(e.deploy.message?` \u2014 ${e.deploy.message}`:"")),e.error&&t.out.say(` ${l("\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14",18)}${e.error}`)}function Xe(t,e){t.out.say(""),t.out.say("\u0E01\u0E32\u0E23\u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19\u0E41\u0E25\u0E30\u0E42\u0E04\u0E27\u0E15\u0E32\u0E17\u0E23\u0E31\u0E1E\u0E22\u0E32\u0E01\u0E23"),t.out.say(` ${l("CPU \u0E15\u0E48\u0E2D request",20)}${e.limits.cpuMs} ms`),t.out.say(` ${l("\u0E01\u0E32\u0E23\u0E41\u0E08\u0E49\u0E07\u0E40\u0E15\u0E37\u0E2D\u0E19",20)}${_(e.usage.notificationsSent)}`+(e.usage.notificationsSent===null?" (\u0E14\u0E39\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E43\u0E19\u0E02\u0E13\u0E30\u0E19\u0E35\u0E49)":` \u0E08\u0E32\u0E01\u0E42\u0E04\u0E27\u0E15\u0E32 ${_(e.limits.notificationsPerDay)} \u0E04\u0E23\u0E31\u0E49\u0E07\u0E27\u0E31\u0E19\u0E19\u0E35\u0E49`)),t.out.say(` ${l("\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14 (24 \u0E0A\u0E21.)",20)}${_(e.usage.errors)}`+(e.usage.errors===null?" (\u0E14\u0E39\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E43\u0E19\u0E02\u0E13\u0E30\u0E19\u0E35\u0E49)":e.usage.errors===0?" (\u0E44\u0E21\u0E48\u0E21\u0E35\u0E43\u0E19 24 \u0E0A\u0E31\u0E48\u0E27\u0E42\u0E21\u0E07\u0E17\u0E35\u0E48\u0E1C\u0E48\u0E32\u0E19\u0E21\u0E32)":e.usage.requests===null?" (\u0E04\u0E33\u0E02\u0E2D\u0E17\u0E35\u0E48\u0E25\u0E49\u0E21\u0E40\u0E2B\u0E25\u0E27\u0E43\u0E19 24 \u0E0A\u0E31\u0E48\u0E27\u0E42\u0E21\u0E07\u0E17\u0E35\u0E48\u0E1C\u0E48\u0E32\u0E19\u0E21\u0E32)":` \u0E08\u0E32\u0E01\u0E17\u0E31\u0E49\u0E07\u0E2B\u0E21\u0E14 ${_(e.usage.requests)} \u0E04\u0E33\u0E02\u0E2D`)),t.out.say(` ${l("\u0E1C\u0E39\u0E49\u0E43\u0E0A\u0E49\u0E41\u0E2D\u0E1B",20)}${_(e.usage.appUsers)}`+(e.usage.appUsers===null?" (\u0E14\u0E39\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E43\u0E19\u0E02\u0E13\u0E30\u0E19\u0E35\u0E49)":""))}function _(t){return t===null?"\u2014":String(t)}function ze(t,e){if(t.out.say(""),t.out.say("\u0E01\u0E32\u0E23\u0E14\u0E35\u0E1E\u0E25\u0E2D\u0E22\u0E25\u0E48\u0E32\u0E2A\u0E38\u0E14"),e.length===0){t.out.say(" \u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35");return}for(let r of e.slice(0,10)){let n=r.commit.slice(0,7),i=r.message?` \u2014 ${r.message}`:"",o=v(jt,r.status);t.out.say(` ${l(o,13)} ${n}${i}`)}}function Ze(t,e){if(t.out.say(""),t.out.say("\u0E04\u0E48\u0E32 env"),e.length===0){t.out.say(" \u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E43\u0E14 \u0E46");return}for(let r of e)r.secret?t.out.say(` ${r.key}=(secret)`):t.out.say(` ${r.key}=${r.value??""}`)}function Qe(t,e,r,n){t.out.say(""),t.out.say("\u0E01\u0E32\u0E23\u0E40\u0E1C\u0E22\u0E41\u0E1E\u0E23\u0E48"),t.out.say(` ${l("\u0E23\u0E30\u0E14\u0E31\u0E1A",18)}${v(Ot,e.tier??"draft")}`),e.customAddress&&t.out.say(` ${l("\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48\u0E17\u0E35\u0E48\u0E01\u0E33\u0E2B\u0E19\u0E14\u0E40\u0E2D\u0E07",18)}${e.customAddress}`);let i=r.find(o=>o.type==="publish"&&o.status==="pending");if(i&&t.out.say(` ${l("\u0E04\u0E33\u0E02\u0E2D\u0E17\u0E35\u0E48\u0E23\u0E2D\u0E2D\u0E22\u0E39\u0E48",18)}${Ut(i)}`),e.tier==="beta"){let o=n.filter(u=>u.status!=="DECLINED").length;t.out.say(` ${l("\u0E04\u0E33\u0E40\u0E0A\u0E34\u0E0D\u0E17\u0E14\u0E25\u0E2D\u0E07\u0E43\u0E0A\u0E49",18)}\u0E43\u0E0A\u0E49\u0E44\u0E1B ${o} \u0E08\u0E32\u0E01 ${Fe} \u0E17\u0E35\u0E48\u0E19\u0E31\u0E48\u0E07`)}}function tr(t,e){if(t.out.say(""),t.out.say("\u0E1C\u0E39\u0E49\u0E23\u0E48\u0E27\u0E21\u0E1E\u0E31\u0E12\u0E19\u0E32"),e.length===0){t.out.say(" \u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35");return}for(let r of e){let n=r.maskedName??"\u0E1C\u0E39\u0E49\u0E23\u0E48\u0E27\u0E21\u0E1E\u0E31\u0E12\u0E19\u0E32",i=r.phoneNumber?` (${r.phoneNumber})`:"";t.out.say(` ${n}${i}`)}}function er(t,e){if(t.out.say(""),t.out.say("\u0E1B\u0E23\u0E30\u0E27\u0E31\u0E15\u0E34\u0E04\u0E33\u0E02\u0E2D"),e.length===0){t.out.say(" \u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35");return}for(let r of e.slice(0,10)){let n=r.reason?` \u2014 ${r.reason}`:"",i=v(Ve,r.status);t.out.say(` ${l(i,13)} ${Ut(r)}${n}`)}}function Ut(t){if(t.type==="publish"){let r=Array.isArray(t.payload.roles)?t.payload.roles:[],n=typeof t.payload.customAddress=="string"?` \xB7 \u0E17\u0E35\u0E48 ${t.payload.customAddress}`:"";return`\u0E04\u0E33\u0E02\u0E2D\u0E40\u0E1C\u0E22\u0E41\u0E1E\u0E23\u0E48 \xB7 \u0E02\u0E36\u0E49\u0E19\u0E40\u0E1C\u0E22\u0E41\u0E1E\u0E23\u0E48\u0E08\u0E23\u0E34\u0E07 \xB7 ${r.length===0?"\u0E17\u0E38\u0E01\u0E04\u0E19":r.join(", ")}${n}`}if(t.type==="retire")return"\u0E04\u0E33\u0E02\u0E2D\u0E1B\u0E25\u0E14\u0E23\u0E30\u0E27\u0E32\u0E07 \xB7 \u0E1B\u0E25\u0E14\u0E23\u0E30\u0E27\u0E32\u0E07\u0E41\u0E2D\u0E1B";let e=[];return typeof t.payload.cpuMs=="number"&&e.push(`CPU ${t.payload.cpuMs} ms/request`),typeof t.payload.notificationsPerDay=="number"&&e.push(`\u0E01\u0E32\u0E23\u0E41\u0E08\u0E49\u0E07\u0E40\u0E15\u0E37\u0E2D\u0E19 ${t.payload.notificationsPerDay} \u0E04\u0E23\u0E31\u0E49\u0E07/\u0E27\u0E31\u0E19`),`\u0E04\u0E33\u0E02\u0E2D\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E42\u0E04\u0E27\u0E15\u0E32 \xB7 \u0E02\u0E2D\u0E40\u0E1E\u0E34\u0E48\u0E21 ${e.length>0?e.join(" \u0E41\u0E25\u0E30 "):"\u0E42\u0E04\u0E27\u0E15\u0E32"}`}import Kt from"node:fs/promises";import b from"node:path";import E from"node:fs/promises";import Mt from"node:path";var rr=new Set([".git","node_modules","dist",".wrangler",".dev.vars",".env"]),nr=new Map([["gitignore",".gitignore"]]),ir="pple-app",or=new Set(["package.json","package-lock.json","wrangler.jsonc"]);async function qt(t,e,r){if(await E.readdir(t).catch(()=>null)===null)throw new s("\u0E44\u0E21\u0E48\u0E1E\u0E1A\u0E40\u0E17\u0E21\u0E40\u0E1E\u0E25\u0E15\u0E41\u0E2D\u0E1B PPLE \u0E43\u0E19\u0E01\u0E32\u0E23\u0E15\u0E34\u0E14\u0E15\u0E31\u0E49\u0E07 CLI \u0E0A\u0E38\u0E14\u0E19\u0E35\u0E49",`\u0E15\u0E34\u0E14\u0E15\u0E31\u0E49\u0E07 CLI \u0E43\u0E2B\u0E21\u0E48 (\`${m}\`) \u0E41\u0E25\u0E49\u0E27\u0E25\u0E2D\u0E07\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07`);let i=[];return await Ft({from:t,to:e,prefix:"",slug:r,written:i}),i.sort()}async function Ft(t){for(let e of await E.readdir(t.from,{withFileTypes:!0})){if(rr.has(e.name))continue;let r=nr.get(e.name)??e.name,n=Mt.join(t.from,e.name),i=Mt.join(t.to,r),o=t.prefix===""?r:`${t.prefix}/${r}`;if(e.isDirectory()){await E.mkdir(i,{recursive:!0}),await Ft({...t,from:n,to:i,prefix:o});continue}if(or.has(r)){let u=await E.readFile(n,"utf8");await E.writeFile(i,sr(u,ir,t.slug))}else await E.copyFile(n,i);t.written.push(o)}}function sr(t,e,r){return t.split(e).join(r)}var ar=3e3,ur=5*6e4;async function Ht(t,e){let r=await p(t),n=e.slug?await r.app(e.slug):await pr(t,r,await cr(t,e.name));if(!n.repo)throw new s(`"${n.name}" \u0E22\u0E31\u0E07\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E44\u0E21\u0E48\u0E40\u0E2A\u0E23\u0E47\u0E08`,`\u0E23\u0E2D\u0E2A\u0E31\u0E01\u0E04\u0E23\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27\u0E23\u0E31\u0E19 \`pple init ${n.slug}\` \u0E2B\u0E32\u0E01\u0E22\u0E31\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E41\u0E1A\u0E1A\u0E19\u0E35\u0E49 \u0E01\u0E23\u0E38\u0E13\u0E32\u0E15\u0E34\u0E14\u0E15\u0E48\u0E2D\u0E17\u0E35\u0E21\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21`);n.status==="provisioning"&&t.out.say("\u0E41\u0E2D\u0E1B\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E22\u0E31\u0E07\u0E2D\u0E22\u0E39\u0E48\u0E23\u0E30\u0E2B\u0E27\u0E48\u0E32\u0E07\u0E01\u0E32\u0E23\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E1A\u0E19\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21\u2026");let i=b.resolve(t.cwd,e.dir??n.slug);await mr(i);let o=await r.repoToken(n.slug);if(t.out.say(`\u0E01\u0E33\u0E25\u0E31\u0E07\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32 "${n.name}" \u0E43\u0E19 ${b.basename(i)}/\u2026`),await ht(t,fr(t,n.repo),i,o),await gr(i))throw new s(`"${n.name}" \u0E21\u0E35\u0E42\u0E04\u0E49\u0E14\u0E2D\u0E22\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27 \u0E08\u0E36\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35\u0E2D\u0E30\u0E44\u0E23\u0E15\u0E49\u0E2D\u0E07\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32`,"\u0E17\u0E33\u0E07\u0E32\u0E19\u0E43\u0E19\u0E42\u0E1F\u0E25\u0E40\u0E14\u0E2D\u0E23\u0E4C\u0E19\u0E31\u0E49\u0E19\u0E41\u0E25\u0E49\u0E27\u0E23\u0E31\u0E19 `pple deploy` \u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E19\u0E33\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E02\u0E36\u0E49\u0E19\u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19\u0E08\u0E23\u0E34\u0E07");await qt(t.templateDir,i,n.slug),await Dt(i,{slug:n.slug,apiBase:t.config.apiBase,url:n.url}),await U(t,i),await I(t,i)&&await L(t,i,"\u0E40\u0E23\u0E34\u0E48\u0E21\u0E08\u0E32\u0E01\u0E40\u0E17\u0E21\u0E40\u0E1E\u0E25\u0E15\u0E21\u0E32\u0E15\u0E23\u0E10\u0E32\u0E19\u0E02\u0E2D\u0E07 PPLE",o);let u=await lr(t,i);dr(t,n,i,u)}async function lr(t,e){t.out.say("\u0E01\u0E33\u0E25\u0E31\u0E07\u0E15\u0E34\u0E14\u0E15\u0E31\u0E49\u0E07\u0E41\u0E1E\u0E47\u0E01\u0E40\u0E01\u0E08\u0E41\u0E25\u0E30\u0E40\u0E15\u0E23\u0E35\u0E22\u0E21\u0E10\u0E32\u0E19\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E1A\u0E19\u0E40\u0E04\u0E23\u0E37\u0E48\u0E2D\u0E07\u2026");let r=[["npm",["install"]],["npm",["run","db:migrate:local"]]];for(let[n,i]of r){let o=await t.run(n,i,{cwd:e}).catch(()=>null);if(!o||o.code!==0)return!1}return!0}async function cr(t,e){if(await V(t))throw new s("\u0E42\u0E1F\u0E25\u0E40\u0E14\u0E2D\u0E23\u0E4C\u0E19\u0E35\u0E49\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E01\u0E31\u0E1A\u0E41\u0E2D\u0E1B PPLE \u0E2D\u0E22\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27","\u0E23\u0E31\u0E19 `pple info` \u0E2B\u0E23\u0E37\u0E2D `pple deploy` \u0E17\u0E35\u0E48\u0E19\u0E35\u0E48 \u0E2B\u0E23\u0E37\u0E2D\u0E22\u0E49\u0E32\u0E22\u0E44\u0E1B\u0E42\u0E1F\u0E25\u0E40\u0E14\u0E2D\u0E23\u0E4C\u0E2D\u0E37\u0E48\u0E19\u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E41\u0E2D\u0E1B\u0E43\u0E2B\u0E21\u0E48");if(e!==void 0){let n=e.trim();if(!n)throw new s("`--name` \u0E15\u0E49\u0E2D\u0E07\u0E23\u0E30\u0E1A\u0E38\u0E0A\u0E37\u0E48\u0E2D\u0E41\u0E2D\u0E1B",'\u0E15\u0E31\u0E27\u0E2D\u0E22\u0E48\u0E32\u0E07: `pple init --name "\u0E25\u0E07\u0E17\u0E30\u0E40\u0E1A\u0E35\u0E22\u0E19\u0E2D\u0E32\u0E2A\u0E32\u0E2A\u0E21\u0E31\u0E04\u0E23"`');return n}if(!t.interactive)throw new s("`pple init` \u0E15\u0E49\u0E2D\u0E07\u0E23\u0E30\u0E1A\u0E38\u0E0A\u0E37\u0E48\u0E2D\u0E41\u0E2D\u0E1B",'\u0E43\u0E2A\u0E48 `--name "\u0E0A\u0E37\u0E48\u0E2D\u0E41\u0E2D\u0E1B\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13"` \u0E2B\u0E23\u0E37\u0E2D\u0E23\u0E31\u0E19\u0E43\u0E19\u0E40\u0E17\u0E2D\u0E23\u0E4C\u0E21\u0E34\u0E19\u0E31\u0E25\u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E43\u0E2B\u0E49\u0E23\u0E30\u0E1A\u0E1A\u0E16\u0E32\u0E21');let r=(await t.ask("\u0E0A\u0E37\u0E48\u0E2D\u0E41\u0E2D\u0E1B:")).trim();if(!r)throw new s("\u0E15\u0E49\u0E2D\u0E07\u0E23\u0E30\u0E1A\u0E38\u0E0A\u0E37\u0E48\u0E2D\u0E41\u0E2D\u0E1B\u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E41\u0E2D\u0E1B",'\u0E25\u0E2D\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07 \u0E2B\u0E23\u0E37\u0E2D\u0E43\u0E2A\u0E48 `--name "\u0E0A\u0E37\u0E48\u0E2D\u0E41\u0E2D\u0E1B\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13"`');return r}async function pr(t,e,r){t.out.say(`\u0E01\u0E33\u0E25\u0E31\u0E07\u0E2A\u0E23\u0E49\u0E32\u0E07 "${r}" \u0E1A\u0E19\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21\u2026`);let n=await e.createApp(r);if(Gt(n))return n;t.out.say("\u0E01\u0E33\u0E25\u0E31\u0E07\u0E23\u0E2D\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E43\u0E2B\u0E49\u0E40\u0E2A\u0E23\u0E47\u0E08\u2026");let i=t.now();for(;;){if(n.status==="failed")throw new s(`\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32 "${n.name}" \u0E1A\u0E19\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21\u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08`,n.error?`${n.error} slug \u0E02\u0E2D\u0E07\u0E41\u0E2D\u0E1B\u0E04\u0E37\u0E2D ${n.slug} \u2014 \u0E01\u0E23\u0E38\u0E13\u0E32\u0E15\u0E34\u0E14\u0E15\u0E48\u0E2D\u0E17\u0E35\u0E21\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21 \u0E2B\u0E23\u0E37\u0E2D\u0E25\u0E2D\u0E07 \`pple init ${n.slug}\` \u0E20\u0E32\u0E22\u0E2B\u0E25\u0E31\u0E07`:`slug \u0E02\u0E2D\u0E07\u0E41\u0E2D\u0E1B\u0E04\u0E37\u0E2D ${n.slug} \u2014 \u0E01\u0E23\u0E38\u0E13\u0E32\u0E15\u0E34\u0E14\u0E15\u0E48\u0E2D\u0E17\u0E35\u0E21\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21 \u0E2B\u0E23\u0E37\u0E2D\u0E25\u0E2D\u0E07 \`pple init ${n.slug}\` \u0E20\u0E32\u0E22\u0E2B\u0E25\u0E31\u0E07`);if(t.now()-i>=ur)throw new s(`"${n.name}" \u0E22\u0E31\u0E07\u0E2D\u0E22\u0E39\u0E48\u0E23\u0E30\u0E2B\u0E27\u0E48\u0E32\u0E07\u0E01\u0E32\u0E23\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E1A\u0E19\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21`,`\u0E25\u0E2D\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E14\u0E49\u0E27\u0E22 \`pple init ${n.slug}\` \u0E43\u0E19\u0E2D\u0E35\u0E01\u0E2A\u0E31\u0E01\u0E04\u0E23\u0E39\u0E48`);if(await t.sleep(ar),n=await e.app(n.slug),Gt(n))return n}}function Gt(t){return t.status==="ready"&&t.repo!==null}function fr(t,e){return`${t.config.repoBase}/${e}.git`}async function mr(t){let e=await Kt.readdir(t).catch(()=>null);if(e!==null&&e.length>0)throw new s(`\u0E42\u0E1F\u0E25\u0E40\u0E14\u0E2D\u0E23\u0E4C ${b.basename(t)}/ \u0E21\u0E35\u0E44\u0E1F\u0E25\u0E4C\u0E2D\u0E22\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27`,"\u0E23\u0E31\u0E19 `pple init` \u0E17\u0E35\u0E48\u0E2D\u0E37\u0E48\u0E19 \u0E2B\u0E23\u0E37\u0E2D\u0E43\u0E2A\u0E48 `--dir <folder>` \u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E42\u0E1F\u0E25\u0E40\u0E14\u0E2D\u0E23\u0E4C\u0E2D\u0E37\u0E48\u0E19")}async function gr(t){return Kt.access(b.join(t,"package.json")).then(()=>!0).catch(()=>!1)}function dr(t,e,r,n){let i=b.basename(r);t.out.say(),t.out.say(`"${e.name}" \u0E1E\u0E23\u0E49\u0E2D\u0E21\u0E43\u0E2B\u0E49\u0E17\u0E33\u0E07\u0E32\u0E19\u0E41\u0E25\u0E49\u0E27\u0E43\u0E19 ${i}/`),t.out.say(`\u0E41\u0E2D\u0E1B\u0E08\u0E30\u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19\u0E44\u0E14\u0E49\u0E17\u0E35\u0E48 ${e.url}`),t.out.say(),t.out.say("\u0E02\u0E31\u0E49\u0E19\u0E15\u0E48\u0E2D\u0E44\u0E1B:"),t.out.say(` cd ${i}`),n||(t.out.say(" npm install"),t.out.say(" npm run db:migrate:local")),t.out.say(" npm run dev # \u0E14\u0E39\u0E1C\u0E25\u0E1A\u0E19\u0E40\u0E04\u0E23\u0E37\u0E48\u0E2D\u0E07\u0E19\u0E35\u0E49"),t.out.say(" pple deploy # \u0E19\u0E33\u0E02\u0E36\u0E49\u0E19\u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19\u0E08\u0E23\u0E34\u0E07")}import W from"node:fs/promises";import X from"node:path";var yr=1440*60*1e3,Vt="update-check.json",wr="config.json",hr=new Set(["upgrade","help","--help","-h"]);function Jt(t){return t.length>0&&!hr.has(t[0])}function z(t,e){t.out.say(`\u0E21\u0E35 pple \u0E40\u0E27\u0E2D\u0E23\u0E4C\u0E0A\u0E31\u0E19\u0E43\u0E2B\u0E21\u0E48 (${e}) \u0E04\u0E38\u0E13\u0E43\u0E0A\u0E49\u0E40\u0E27\u0E2D\u0E23\u0E4C\u0E0A\u0E31\u0E19 ${t.version}`)}function Z(t){t.out.say("pple \u0E0A\u0E38\u0E14\u0E19\u0E35\u0E49\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E15\u0E34\u0E14\u0E15\u0E31\u0E49\u0E07\u0E1C\u0E48\u0E32\u0E19 npm \u0E01\u0E32\u0E23\u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15\u0E17\u0E35\u0E48\u0E19\u0E35\u0E48\u0E2D\u0E32\u0E08\u0E17\u0E33\u0E43\u0E2B\u0E49\u0E04\u0E38\u0E13"),t.out.say("\u0E21\u0E35 pple \u0E2A\u0E2D\u0E07\u0E40\u0E27\u0E2D\u0E23\u0E4C\u0E0A\u0E31\u0E19 \u0E01\u0E23\u0E38\u0E13\u0E32\u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15\u0E14\u0E49\u0E27\u0E22\u0E27\u0E34\u0E18\u0E35\u0E40\u0E14\u0E34\u0E21\u0E17\u0E35\u0E48\u0E04\u0E38\u0E13\u0E15\u0E34\u0E14\u0E15\u0E31\u0E49\u0E07\u0E44\u0E27\u0E49"),t.out.say(`\u0E2B\u0E23\u0E37\u0E2D\u0E15\u0E34\u0E14\u0E15\u0E31\u0E49\u0E07\u0E14\u0E49\u0E27\u0E22 npm:
|
|
16
|
+
|
|
17
|
+
${m}`)}function Q(t){return`${_t(t)}
|
|
18
|
+
|
|
19
|
+
\u0E25\u0E2D\u0E07\u0E23\u0E31\u0E19\u0E04\u0E33\u0E2A\u0E31\u0E48\u0E07\u0E19\u0E35\u0E49\u0E14\u0E49\u0E27\u0E22\u0E15\u0E31\u0E27\u0E40\u0E2D\u0E07:
|
|
20
|
+
|
|
21
|
+
${m}`}async function Yt(t,e){if(!await Pr(t))return null;await $r(t);let r=await N(t);if(r===null||!B(r,t.version))return null;if(z(t,r),!await O(t))return Z(t),t.out.say(),null;if(!t.interactive)return t.out.say("\u0E23\u0E31\u0E19 `pple upgrade` \u0E40\u0E21\u0E37\u0E48\u0E2D\u0E04\u0E38\u0E13\u0E1E\u0E23\u0E49\u0E2D\u0E21"),t.out.say(),null;if(!await t.confirm("\u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15 pple \u0E15\u0E2D\u0E19\u0E19\u0E35\u0E49\u0E40\u0E25\u0E22\u0E44\u0E2B\u0E21?"))return t.out.say(),null;let n=await j(t,r);return n.code!==0?await vr(t,r,n):(t.out.say(`pple \u0E40\u0E1B\u0E47\u0E19\u0E40\u0E27\u0E2D\u0E23\u0E4C\u0E0A\u0E31\u0E19 ${r} \u0E41\u0E25\u0E49\u0E27 \u0E01\u0E33\u0E25\u0E31\u0E07\u0E17\u0E33\u0E07\u0E32\u0E19\u0E15\u0E48\u0E2D\u0E08\u0E32\u0E01\u0E17\u0E35\u0E48\u0E04\u0E49\u0E32\u0E07\u0E44\u0E27\u0E49\u2026`),t.out.say(),t.reexec(e))}async function vr(t,e,r){return t.out.say(`\u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15 pple \u0E40\u0E1B\u0E47\u0E19 ${e} \u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08`),t.out.say(Q(r)),t.out.say(),await t.confirm(`\u0E43\u0E0A\u0E49 pple ${t.version} \u0E17\u0E33\u0E07\u0E32\u0E19\u0E15\u0E48\u0E2D\u0E44\u0E1B\u0E01\u0E48\u0E2D\u0E19\u0E44\u0E2B\u0E21?`)?(t.out.say(),null):(t.out.say("\u0E2B\u0E22\u0E38\u0E14\u0E41\u0E25\u0E49\u0E27 \u0E44\u0E21\u0E48\u0E21\u0E35\u0E2D\u0E30\u0E44\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07"),1)}async function Pr(t){if(!t.updateChecks||!await Er(t))return!1;let e=await Wt(X.join(t.configDir,Vt));return typeof e?.lastCheckedAt!="number"?!0:t.now()-e.lastCheckedAt>=yr}async function $r(t){let e={lastCheckedAt:t.now()};await W.mkdir(t.configDir,{recursive:!0}).then(()=>W.writeFile(X.join(t.configDir,Vt),`${JSON.stringify(e,null,2)}
|
|
22
|
+
`)).catch(()=>{})}async function Er(t){return(await Wt(X.join(t.configDir,wr)))?.updateCheck!==!1}async function Wt(t){let e=await W.readFile(t,"utf8").catch(()=>null);if(e===null)return null;try{return JSON.parse(e)}catch{return null}}async function Xt(t){let e=await N(t);if(e===null)throw new s("\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D npm \u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E15\u0E23\u0E27\u0E08\u0E2B\u0E32\u0E40\u0E27\u0E2D\u0E23\u0E4C\u0E0A\u0E31\u0E19\u0E43\u0E2B\u0E21\u0E48\u0E02\u0E2D\u0E07 pple \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49",`\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E01\u0E32\u0E23\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D\u0E2D\u0E34\u0E19\u0E40\u0E17\u0E2D\u0E23\u0E4C\u0E40\u0E19\u0E47\u0E15 \u0E2B\u0E23\u0E37\u0E2D\u0E2D\u0E31\u0E1B\u0E40\u0E01\u0E23\u0E14\u0E42\u0E14\u0E22\u0E15\u0E23\u0E07:
|
|
23
|
+
|
|
24
|
+
${m}`);if(!B(e,t.version)){t.out.say(`\u0E04\u0E38\u0E13\u0E43\u0E0A\u0E49 pple \u0E40\u0E27\u0E2D\u0E23\u0E4C\u0E0A\u0E31\u0E19\u0E25\u0E48\u0E32\u0E2A\u0E38\u0E14\u0E2D\u0E22\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27 (${t.version})`);return}if(!await O(t)){z(t,e),t.out.say(),Z(t);return}t.out.say(`\u0E01\u0E33\u0E25\u0E31\u0E07\u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15 pple ${t.version} \u2192 ${e}\u2026`);let r=await j(t,e);if(r.code!==0)throw new s(`\u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15 pple \u0E40\u0E1B\u0E47\u0E19 ${e} \u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08`,Q(r));t.out.say(`pple \u0E40\u0E1B\u0E47\u0E19\u0E40\u0E27\u0E2D\u0E23\u0E4C\u0E0A\u0E31\u0E19 ${e} \u0E41\u0E25\u0E49\u0E27`)}var zt=`pple \u2014 \u0E2A\u0E23\u0E49\u0E32\u0E07\u0E41\u0E25\u0E30\u0E2A\u0E48\u0E07\u0E41\u0E2D\u0E1B\u0E02\u0E36\u0E49\u0E19 PPLE Platform
|
|
25
|
+
|
|
26
|
+
pple auth login \u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E14\u0E49\u0E27\u0E22 PPLE ID \u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13
|
|
27
|
+
pple auth logout \u0E25\u0E1A\u0E01\u0E32\u0E23\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E2D\u0E2D\u0E01\u0E08\u0E32\u0E01\u0E40\u0E04\u0E23\u0E37\u0E48\u0E2D\u0E07\u0E19\u0E35\u0E49
|
|
28
|
+
pple whoami \u0E14\u0E39\u0E27\u0E48\u0E32\u0E01\u0E33\u0E25\u0E31\u0E07\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E14\u0E49\u0E27\u0E22\u0E1A\u0E31\u0E0D\u0E0A\u0E35\u0E43\u0E14
|
|
29
|
+
|
|
30
|
+
pple init \u0E2A\u0E23\u0E49\u0E32\u0E07\u0E41\u0E2D\u0E1B\u0E41\u0E25\u0E30\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E42\u0E04\u0E49\u0E14\u0E1A\u0E19\u0E40\u0E04\u0E23\u0E37\u0E48\u0E2D\u0E07\u0E19\u0E35\u0E49
|
|
31
|
+
pple init --name "App" \u0E2A\u0E23\u0E49\u0E32\u0E07\u0E41\u0E2D\u0E1B\u0E42\u0E14\u0E22\u0E44\u0E21\u0E48\u0E15\u0E49\u0E2D\u0E07\u0E16\u0E32\u0E21 (\u0E2A\u0E33\u0E2B\u0E23\u0E31\u0E1A agent/\u0E2A\u0E04\u0E23\u0E34\u0E1B\u0E15\u0E4C)
|
|
32
|
+
pple init <app> \u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E41\u0E2D\u0E1B\u0E17\u0E35\u0E48\u0E21\u0E35\u0E2D\u0E22\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27\u0E1A\u0E19\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21
|
|
33
|
+
pple deploy [-m "note"] \u0E2A\u0E48\u0E07\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E02\u0E36\u0E49\u0E19\u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19\u0E08\u0E23\u0E34\u0E07
|
|
34
|
+
pple info [<slug>] \u0E14\u0E39\u0E2A\u0E16\u0E32\u0E19\u0E30 \u0E01\u0E32\u0E23\u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19 \u0E01\u0E32\u0E23\u0E14\u0E35\u0E1E\u0E25\u0E2D\u0E22 \u0E41\u0E25\u0E30\u0E04\u0E35\u0E22\u0E4C env \u0E02\u0E2D\u0E07\u0E41\u0E2D\u0E1B\u0E19\u0E35\u0E49
|
|
35
|
+
|
|
36
|
+
pple env list \u0E14\u0E39\u0E15\u0E31\u0E27\u0E41\u0E1B\u0E23\u0E41\u0E25\u0E30 secret \u0E02\u0E2D\u0E07\u0E41\u0E2D\u0E1B\u0E19\u0E35\u0E49
|
|
37
|
+
pple env set <KEY> [VAL] \u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32\u0E15\u0E31\u0E27\u0E41\u0E1B\u0E23 (\u0E2B\u0E23\u0E37\u0E2D --secret) \u0E23\u0E31\u0E1A\u0E04\u0E48\u0E32\u0E08\u0E32\u0E01 arg, --file \u0E2B\u0E23\u0E37\u0E2D stdin
|
|
38
|
+
pple env delete <KEY> \u0E25\u0E1A\u0E15\u0E31\u0E27\u0E41\u0E1B\u0E23\u0E2B\u0E23\u0E37\u0E2D secret
|
|
39
|
+
|
|
40
|
+
pple upgrade \u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15 pple \u0E40\u0E1B\u0E47\u0E19\u0E40\u0E27\u0E2D\u0E23\u0E4C\u0E0A\u0E31\u0E19\u0E25\u0E48\u0E32\u0E2A\u0E38\u0E14
|
|
41
|
+
|
|
42
|
+
\u0E15\u0E31\u0E27\u0E40\u0E25\u0E37\u0E2D\u0E01
|
|
43
|
+
-m, --message <note> \u0E2A\u0E34\u0E48\u0E07\u0E17\u0E35\u0E48\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07 \u0E41\u0E2A\u0E14\u0E07\u0E43\u0E19\u0E1B\u0E23\u0E30\u0E27\u0E31\u0E15\u0E34\u0E02\u0E2D\u0E07\u0E41\u0E2D\u0E1B
|
|
44
|
+
--name <App Name> \u0E2A\u0E23\u0E49\u0E32\u0E07\u0E41\u0E2D\u0E1B\u0E43\u0E2B\u0E21\u0E48\u0E14\u0E49\u0E27\u0E22\u0E0A\u0E37\u0E48\u0E2D\u0E19\u0E35\u0E49 (pple init)
|
|
45
|
+
--dir <folder> \u0E15\u0E33\u0E41\u0E2B\u0E19\u0E48\u0E07\u0E17\u0E35\u0E48\u0E08\u0E30\u0E27\u0E32\u0E07\u0E42\u0E04\u0E49\u0E14\u0E02\u0E2D\u0E07\u0E41\u0E2D\u0E1B (pple init)
|
|
46
|
+
--file <path> \u0E2D\u0E48\u0E32\u0E19\u0E04\u0E48\u0E32 env \u0E08\u0E32\u0E01\u0E44\u0E1F\u0E25\u0E4C (pple env set)
|
|
47
|
+
--secret \u0E40\u0E01\u0E47\u0E1A\u0E04\u0E48\u0E32\u0E40\u0E1B\u0E47\u0E19 secret \u0E41\u0E1A\u0E1A\u0E40\u0E02\u0E35\u0E22\u0E19\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E40\u0E14\u0E35\u0E22\u0E27 (pple env set)
|
|
48
|
+
-h, --help \u0E41\u0E2A\u0E14\u0E07\u0E27\u0E34\u0E18\u0E35\u0E43\u0E0A\u0E49\u0E19\u0E35\u0E49
|
|
49
|
+
`;async function Zt(t,e){try{if(Jt(t)){let r=await Yt(e,t);if(r!==null)return r}return await Dr(t,e),0}catch(r){if(r instanceof s)return e.out.fail(r),1;throw r}}async function Dr(t,e){let r=[...t];if(r.length===0||r[0]==="--help"||r[0]==="-h"){e.out.say(zt);return}let n=r.shift();switch(n){case"auth":{let i=r.shift();if(i==="login")return ft(e);if(i==="logout")return mt(e);if(i==="whoami")return G(e);throw tt(`auth ${i??""}`.trim())}case"whoami":return G(e);case"init":{let i=M(r,"--dir"),o=M(r,"--name"),u=r.shift();if(o!==void 0&&u)throw new s("`pple init` \u0E23\u0E31\u0E1A\u0E44\u0E14\u0E49\u0E40\u0E09\u0E1E\u0E32\u0E30\u0E0A\u0E37\u0E48\u0E2D\u0E41\u0E2D\u0E1B\u0E43\u0E2B\u0E21\u0E48 \u0E2B\u0E23\u0E37\u0E2D\u0E41\u0E2D\u0E1B\u0E17\u0E35\u0E48\u0E21\u0E35\u0E2D\u0E22\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27 \u0E2D\u0E22\u0E48\u0E32\u0E07\u0E43\u0E14\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E2B\u0E19\u0E36\u0E48\u0E07\u0E40\u0E17\u0E48\u0E32\u0E19\u0E31\u0E49\u0E19",'\u0E43\u0E0A\u0E49 `pple init --name "\u0E0A\u0E37\u0E48\u0E2D\u0E41\u0E2D\u0E1B\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13"` \u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E43\u0E2B\u0E21\u0E48 \u0E2B\u0E23\u0E37\u0E2D `pple init <app>` \u0E2A\u0E33\u0E2B\u0E23\u0E31\u0E1A\u0E41\u0E2D\u0E1B\u0E17\u0E35\u0E48\u0E21\u0E35\u0E2D\u0E22\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27');return Ht(e,{slug:u,name:o,dir:i})}case"deploy":{let i=M(r,"--message","-m");return Rt(e,{message:i})}case"info":{let i=r.shift();return Bt(e,i)}case"env":{let i=r.shift();if(i==="list")return It(e);if(i==="set"){let o=kr(r,"--secret"),u=M(r,"--file"),a=r.shift(),c=r.shift();if(!a)throw new s("`pple env set` \u0E15\u0E49\u0E2D\u0E07\u0E23\u0E30\u0E1A\u0E38 KEY","\u0E15\u0E31\u0E27\u0E2D\u0E22\u0E48\u0E32\u0E07: `pple env set API_URL https://example.com`");return Lt(e,{key:a,value:c,secret:o,file:u})}if(i==="delete"){let o=r.shift();if(!o)throw new s("`pple env delete` \u0E15\u0E49\u0E2D\u0E07\u0E23\u0E30\u0E1A\u0E38 KEY","\u0E15\u0E31\u0E27\u0E2D\u0E22\u0E48\u0E32\u0E07: `pple env delete API_URL`");return Nt(e,o)}throw tt(`env ${i??""}`.trim())}case"upgrade":return Xt(e);case"help":e.out.say(zt);return;default:throw tt(n??"")}}function tt(t){return new s(`\u0E44\u0E21\u0E48\u0E21\u0E35\u0E04\u0E33\u0E2A\u0E31\u0E48\u0E07 \`pple ${t}\``,"\u0E23\u0E31\u0E19 `pple --help` \u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E14\u0E39\u0E04\u0E33\u0E2A\u0E31\u0E48\u0E07\u0E17\u0E31\u0E49\u0E07\u0E2B\u0E21\u0E14")}function M(t,e,r){let n=t.findIndex(o=>o===e||r&&o===r);if(n===-1)return;let[,i]=t.splice(n,2);if(i===void 0||i.startsWith("-"))throw new s(`\`${e}\` \u0E15\u0E49\u0E2D\u0E07\u0E23\u0E30\u0E1A\u0E38\u0E04\u0E48\u0E32\u0E15\u0E32\u0E21\u0E2B\u0E25\u0E31\u0E07`);return i}function kr(t,e){let r=t.indexOf(e);return r===-1?!1:(t.splice(r,1),!0)}import{spawn as ae}from"node:child_process";import ue from"node:readline/promises";import{existsSync as Qt,readFileSync as Ar}from"node:fs";import f from"node:path";import{fileURLToPath as _r}from"node:url";var C={apiBase:"https://api.ppleth.ai",ssoBase:"https://id.peoplesparty.or.th",clientId:"382216793067947795",repoBase:"https://github.com",registryBase:"https://registry.npmjs.org"};function te(t){return{apiBase:t.PPLE_API_BASE??C.apiBase,ssoBase:t.PPLE_SSO_BASE??C.ssoBase,clientId:t.PPLE_CLIENT_ID??C.clientId,repoBase:t.PPLE_REPO_BASE??C.repoBase,registryBase:t.PPLE_REGISTRY_BASE??C.registryBase}}function ee(t,e){let r=t.XDG_CONFIG_HOME?.trim();return f.join(r&&r!==""?r:f.join(e,".config"),"pple")}function re(t){let e=t.PPLE_NO_UPDATE_CHECK?.trim().toLowerCase();return!e||e==="0"||e==="false"}function h(){return f.dirname(f.dirname(_r(import.meta.url)))}function ne(){try{let t=Ar(f.join(h(),"package.json"),"utf8");return String(JSON.parse(t).version??"0.0.0")}catch{return"0.0.0"}}function ie(t){let e=t.PPLE_TEMPLATE_DIR?.trim();if(e)return e;let r=f.join(h(),"templates","golden-path");return Qt(r)?r:f.join(f.dirname(h()),"template")}function oe(t){let e=t.PPLE_SKILLS_DIR?.trim();if(e)return e;let r=f.join(h(),"skills","pple-platform");return Qt(r)?r:f.join(f.dirname(h()),"skills","pple-platform")}function se(){return f.join(h(),"askpass","pple-askpass.mjs")}function le(t,e,r){return new Promise((n,i)=>{let o=ae(t,e,{cwd:r.cwd,env:{...process.env,...r.env},stdio:["ignore","pipe","pipe"]}),u="",a="";o.stdout.on("data",c=>u+=String(c)),o.stderr.on("data",c=>a+=String(c)),o.on("error",i),o.on("close",c=>n({code:c??0,stdout:u,stderr:a}))})}async function br(t){let e=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";await le(e,[t],{cwd:process.cwd()}).catch(()=>{})}async function Cr(t){let e=ue.createInterface({input:process.stdin,output:process.stdout});try{let r=await e.question(`${t} [y/N] `);return/^y(es)?$/i.test(r.trim())}finally{e.close()}}async function xr(t){let e=ue.createInterface({input:process.stdin,output:process.stdout});try{return await e.question(`${t} `)}finally{e.close()}}async function Tr(){let t=[];for await(let e of process.stdin)t.push(typeof e=="string"?Buffer.from(e):e);return Buffer.concat(t).toString("utf8")}function Sr(t){return new Promise((e,r)=>{let n=ae(process.execPath,[process.argv[1],...t],{stdio:"inherit"});n.on("error",r),n.on("close",i=>e(i??0))})}function ce(t,e){return{fetch:globalThis.fetch.bind(globalThis),now:()=>Date.now(),sleep:r=>new Promise(n=>setTimeout(n,r)),cwd:process.cwd(),configDir:ee(process.env,e),out:t,openBrowser:br,run:le,templateDir:ie(process.env),skillsDir:oe(process.env),packageDir:h(),version:ne(),interactive:process.stdin.isTTY===!0&&process.stdout.isTTY===!0,confirm:Cr,ask:xr,readStdin:Tr,reexec:Sr,updateChecks:re(process.env),gitAskpass:se(),config:te(process.env)}}function pe(t,e){return{say(r=""){t(`${r}
|
|
50
|
+
`)},fail(r){e(`${r.message}
|
|
51
|
+
`),r.hint&&e(`${r.hint}
|
|
52
|
+
`)}}}var Ir=pe(t=>process.stdout.write(t),t=>process.stderr.write(t));try{process.exitCode=await Zt(process.argv.slice(2),ce(Ir,Rr.homedir()))}catch(t){process.stderr.write(`\u0E40\u0E01\u0E34\u0E14\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E20\u0E32\u0E22\u0E43\u0E19 pple CLI \u0E01\u0E23\u0E38\u0E13\u0E32\u0E2A\u0E48\u0E07\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E19\u0E35\u0E49\u0E43\u0E2B\u0E49\u0E17\u0E35\u0E21\u0E41\u0E1E\u0E25\u0E15\u0E1F\u0E2D\u0E23\u0E4C\u0E21:
|
|
53
|
+
`),process.stderr.write(`${t instanceof Error?t.stack??t.message:String(t)}
|
|
54
|
+
`),process.exitCode=1}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pplethai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"templates"
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "npm run build:template && npm run build:skills &&
|
|
20
|
+
"build": "npm run build:template && npm run build:skills && node scripts/bundle.mjs",
|
|
21
21
|
"build:template": "node scripts/bundle-template.mjs",
|
|
22
22
|
"build:skills": "node scripts/bundle-skills.mjs",
|
|
23
23
|
"typecheck": "tsc --noEmit",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^22.10.0",
|
|
29
|
+
"esbuild": "^0.28.1",
|
|
29
30
|
"typescript": "^5.8.0",
|
|
30
31
|
"vitest": "^4.1.10"
|
|
31
32
|
},
|
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
# automatically.
|
|
1
|
+
# Optional local-development overrides. `npm run dev` works with NO `.dev.vars`
|
|
2
|
+
# at all — copy this to `.dev.vars` (gitignored) only if you want one of the
|
|
3
|
+
# settings below. `vite dev` and `wrangler dev` load `.dev.vars` automatically.
|
|
4
4
|
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# NEVER set DEV_AUTH in production — the platform never provisions it, and the
|
|
11
|
-
# Worker treats its absence as "real auth only".
|
|
12
|
-
DEV_AUTH="dev-token"
|
|
5
|
+
# Which mock identity to sign in as locally. Defaults to "hq-staff".
|
|
6
|
+
# Built-in personas: hq-staff, province-coordinator, platform-admin, delegate
|
|
7
|
+
# (add your own in src/dev-personas.ts). Set to "none" to turn the bypass off
|
|
8
|
+
# and exercise the real PPLE ID sign-in path locally.
|
|
9
|
+
# DEV_PERSONA="province-coordinator"
|
|
13
10
|
|
|
14
|
-
#
|
|
15
|
-
#
|
|
11
|
+
# Exercise the notification helper locally. These are normally injected by the
|
|
12
|
+
# platform at deploy time.
|
|
16
13
|
# NOTIFY_API_BASE="https://today.peoplesparty.or.th"
|
|
17
14
|
# NOTIFY_API_KEY="your-app-notification-key"
|
|
@@ -27,14 +27,29 @@ which attach the PPLE ID bearer token. Same origin, so paths are relative
|
|
|
27
27
|
|
|
28
28
|
## How auth works
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
Every `/api/*` request carries a PPLE ID bearer token; the Worker resolves it
|
|
31
|
+
to an `Identity` (`src/auth.ts`, shape in `shared/api.ts`) with two faces:
|
|
32
|
+
|
|
33
|
+
- **`actor`** — the real human clicking (`sub`, `name`, `mobile`). For audit
|
|
34
|
+
and display only.
|
|
35
|
+
- **`effective`** — what they may do: `activeRole`, `eligibleRoles`,
|
|
36
|
+
`provinces` (scope), `extraRoles` (capabilities like `platform:admin`).
|
|
37
|
+
**Gate every authorization decision on `effective`, never on `actor`.** Under
|
|
38
|
+
delegation these are the *supervisor's* values and `effective.isDelegated`
|
|
39
|
+
is true.
|
|
40
|
+
|
|
41
|
+
Where the token comes from:
|
|
42
|
+
|
|
43
|
+
- Inside PPLE Today, the mini-app SDK (`web/pple.ts`) captures the access token
|
|
44
|
+
from the launch URL; the Worker validates it against PPLE ID.
|
|
33
45
|
- In a plain browser, the same SDK runs the PPLE ID OIDC login (redirect /
|
|
34
|
-
callback)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
46
|
+
callback) — do not add a custom sign-in page or resurrect a NotInApp guard.
|
|
47
|
+
- Locally (`npm run dev`) there is no login: the Worker signs you in as a mock
|
|
48
|
+
**persona** (`DEV_PERSONA`, default `hq-staff` — see `src/dev-personas.ts`).
|
|
49
|
+
To test a province-scoped feature use `DEV_PERSONA=province-coordinator`;
|
|
50
|
+
for delegation use `delegate`; for admin-only paths use `platform-admin`.
|
|
51
|
+
This bypass is gated on `import.meta.env.DEV`, so it is compiled out of the
|
|
52
|
+
deployed Worker — there is nothing to set or unset for production.
|
|
38
53
|
|
|
39
54
|
## Conventions
|
|
40
55
|
|
|
@@ -14,7 +14,7 @@ what you want to your AI coding agent and edit the demo cards. See
|
|
|
14
14
|
| Capability | Where | Demo |
|
|
15
15
|
| ---------- | ----- | ---- |
|
|
16
16
|
| **API** | Hono Worker, `src/index.ts` | routes under `/api/*` |
|
|
17
|
-
| **Identity** | `src/auth.ts` + `web/pple.ts` | validates PPLE ID tokens; browser PPLE ID login; dev
|
|
17
|
+
| **Identity** | `src/auth.ts` + `web/pple.ts` | validates PPLE ID tokens; browser PPLE ID login; local mock personas (`src/dev-personas.ts`) |
|
|
18
18
|
| **Database** | D1, `src/db.ts` + `migrations/` | the Notes card |
|
|
19
19
|
| **Files** | R2, `src/files.ts` | the Files card |
|
|
20
20
|
| **Notifications** | `src/notify.ts` | the Notify card (audience-bound; optional `linkPath`) |
|
|
@@ -27,15 +27,20 @@ everything else — same origin, no CORS.
|
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
npm install
|
|
30
|
-
|
|
31
|
-
npm run db:migrate:local # set up the local database
|
|
32
|
-
npm run dev # http://localhost:5173
|
|
30
|
+
npm run dev # http://localhost:5173
|
|
33
31
|
```
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
`npm run dev` applies your local database migrations, then starts the
|
|
34
|
+
full-stack dev server. No config files, no PPLE Today, no OAuth: you're signed
|
|
35
|
+
in automatically as a mock **persona** (`hq-staff` by default). To develop as
|
|
36
|
+
someone else, set `DEV_PERSONA` in `.dev.vars` (see `.dev.vars.example`) to
|
|
37
|
+
`hq-staff`, `province-coordinator`, `platform-admin`, or `delegate` — or add
|
|
38
|
+
your own in `src/dev-personas.ts`.
|
|
39
|
+
|
|
40
|
+
Opened inside PPLE Today, the mini-app SDK signs the real user in from the
|
|
41
|
+
launch URL; opened in a plain browser after deploy, the same SDK runs the
|
|
42
|
+
PPLE ID login. (`pple init` runs `npm install` and the first migration for
|
|
43
|
+
you, so a freshly created app is ready to `npm run dev` straight away.)
|
|
39
44
|
|
|
40
45
|
## Everyday commands
|
|
41
46
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"type": "module",
|
|
5
5
|
"//": "Golden-path template for a PPLE Platform Builder App. Rename this to your app slug. Everything runs on Cloudflare: a Hono Worker (API), D1 (database), R2 (files); the UI is a React SPA built with the People's Party design system.",
|
|
6
6
|
"scripts": {
|
|
7
|
+
"predev": "wrangler d1 migrations apply DB --local",
|
|
7
8
|
"dev": "vite dev",
|
|
8
9
|
"build": "vite build",
|
|
9
10
|
"preview": "vite preview",
|
|
@@ -4,12 +4,45 @@
|
|
|
4
4
|
// the inferred TypeScript types.
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* The signed-in caller, as the Worker resolves it from the PPLE ID token
|
|
9
|
+
* (src/auth.ts). Two faces:
|
|
10
|
+
*
|
|
11
|
+
* - `actor` — the real human clicking. Use for audit and display only.
|
|
12
|
+
* - `effective` — what they may do. Gate every authorization decision on this,
|
|
13
|
+
* never on `actor`. Under Delegation these are the supervisor's values and
|
|
14
|
+
* `isDelegated` is true. See docs/adr/0012 and CONTEXT.md.
|
|
15
|
+
*/
|
|
16
|
+
export const ActorSchema = z.object({
|
|
9
17
|
sub: z.string(),
|
|
10
18
|
name: z.string().nullable(),
|
|
19
|
+
/** Thai mobile number, the join key across PPLE systems. May be null. */
|
|
20
|
+
mobile: z.string().nullable(),
|
|
21
|
+
});
|
|
22
|
+
export type Actor = z.infer<typeof ActorSchema>;
|
|
23
|
+
|
|
24
|
+
export const EffectiveSchema = z.object({
|
|
25
|
+
/** True ⇒ the values below are borrowed from a supervisor (see Actor). */
|
|
26
|
+
isDelegated: z.boolean(),
|
|
27
|
+
/** The Role in play now (one of `eligibleRoles`), e.g. "hq", "province". */
|
|
28
|
+
activeRole: z.string(),
|
|
29
|
+
eligibleRoles: z.array(z.string()),
|
|
30
|
+
/** Geographic scope, or ["all"]. */
|
|
31
|
+
provinces: z.array(z.string()),
|
|
32
|
+
/** Capabilities, e.g. "platform:admin", "exco", "province_co". */
|
|
33
|
+
extraRoles: z.array(z.string()),
|
|
34
|
+
});
|
|
35
|
+
export type Effective = z.infer<typeof EffectiveSchema>;
|
|
36
|
+
|
|
37
|
+
export const IdentitySchema = z.object({
|
|
38
|
+
actor: ActorSchema,
|
|
39
|
+
effective: EffectiveSchema,
|
|
11
40
|
});
|
|
12
|
-
export type
|
|
41
|
+
export type Identity = z.infer<typeof IdentitySchema>;
|
|
42
|
+
|
|
43
|
+
/** What `GET /api/me` returns: the caller's Identity. */
|
|
44
|
+
export const MeSchema = IdentitySchema;
|
|
45
|
+
export type Me = Identity;
|
|
13
46
|
|
|
14
47
|
/** A row in the example `notes` table (the D1 read/write demo). */
|
|
15
48
|
export const NoteSchema = z.object({
|
|
@@ -5,11 +5,16 @@
|
|
|
5
5
|
// The Worker validates that token server-side against the PPLE ID userinfo
|
|
6
6
|
// endpoint — the same seam the platform's own services use. There is no local
|
|
7
7
|
// session or cookie: each request carries the token.
|
|
8
|
+
//
|
|
9
|
+
// The token resolves to an Identity with two faces (see shared/api.ts):
|
|
10
|
+
// • actor — the real human clicking (audit/display only)
|
|
11
|
+
// • effective — what they may do (gate authorization on this)
|
|
12
|
+
// Under Delegation, effective.* are the supervisor's and effective.isDelegated
|
|
13
|
+
// is true, while actor stays the delegate. See docs/adr/0012.
|
|
14
|
+
import type { Identity } from "../shared/api";
|
|
15
|
+
import { resolveDevPersona } from "./dev-personas";
|
|
8
16
|
|
|
9
|
-
export
|
|
10
|
-
sub: string;
|
|
11
|
-
name: string | null;
|
|
12
|
-
}
|
|
17
|
+
export type { Identity };
|
|
13
18
|
|
|
14
19
|
export type AuthResult =
|
|
15
20
|
| { ok: true; identity: Identity }
|
|
@@ -17,8 +22,12 @@ export type AuthResult =
|
|
|
17
22
|
|
|
18
23
|
interface AuthEnv {
|
|
19
24
|
SSO_BASE_URL: string;
|
|
20
|
-
/**
|
|
21
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Local development only: which mock persona to sign in as (see
|
|
27
|
+
* src/dev-personas.ts). Unset means the default persona; "none" turns the
|
|
28
|
+
* bypass off so you can exercise the real PPLE ID path locally.
|
|
29
|
+
*/
|
|
30
|
+
DEV_PERSONA?: string;
|
|
22
31
|
}
|
|
23
32
|
|
|
24
33
|
/**
|
|
@@ -31,23 +40,99 @@ export async function authenticate(
|
|
|
31
40
|
token: string,
|
|
32
41
|
fetchImpl: typeof fetch = globalThis.fetch.bind(globalThis),
|
|
33
42
|
): Promise<AuthResult> {
|
|
34
|
-
// Local development bypass
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
// Local development bypass. `import.meta.env.DEV` is true under `vite dev`
|
|
44
|
+
// (and tests) and statically `false` in `vite build`, so this whole block is
|
|
45
|
+
// dead-code-eliminated from the deployed Worker — the bypass cannot exist in
|
|
46
|
+
// production (docs/adr/0011). No token, no `.dev.vars`, no PPLE Today needed;
|
|
47
|
+
// set DEV_PERSONA="none" to fall through to the real path instead.
|
|
48
|
+
if (import.meta.env.DEV && env.DEV_PERSONA !== "none") {
|
|
49
|
+
return { ok: true, identity: resolveDevPersona(env.DEV_PERSONA) };
|
|
39
50
|
}
|
|
40
51
|
|
|
52
|
+
if (!token) return { ok: false, status: 401 };
|
|
53
|
+
|
|
41
54
|
const res = await fetchImpl(`${env.SSO_BASE_URL}/oidc/v1/userinfo`, {
|
|
42
55
|
headers: { authorization: `Bearer ${token}` },
|
|
43
56
|
});
|
|
44
57
|
if (res.status === 401 || res.status === 403) return { ok: false, status: 401 };
|
|
45
58
|
if (!res.ok) return { ok: false, status: 502 };
|
|
46
59
|
|
|
47
|
-
const body = (await res.json().catch(() => ({}))) as
|
|
48
|
-
sub?: string;
|
|
49
|
-
name?: string;
|
|
50
|
-
};
|
|
60
|
+
const body = (await res.json().catch(() => ({}))) as RawUserInfo;
|
|
51
61
|
if (!body.sub) return { ok: false, status: 502 };
|
|
52
|
-
return { ok: true, identity:
|
|
62
|
+
return { ok: true, identity: toIdentity(body) };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// --- Parsing the PPLE ID userinfo response -------------------------------
|
|
66
|
+
//
|
|
67
|
+
// Organization members carry an `ad` block. Its `user` is the person whose
|
|
68
|
+
// authority is in effect (a delegate is already resolved to their supervisor
|
|
69
|
+
// here); `actualPpleUser` is the real human who logged in. Every level is
|
|
70
|
+
// optional, so a missing or oddly-shaped payload yields empty values rather
|
|
71
|
+
// than throwing. See pple-sso's lib/ad/legacy-context.ts for the full shape.
|
|
72
|
+
|
|
73
|
+
interface RawPerson {
|
|
74
|
+
id?: number;
|
|
75
|
+
role?: string;
|
|
76
|
+
mobile?: string;
|
|
77
|
+
metadata?: { ad?: { extra_roles?: unknown; is_province_coordinator?: unknown } };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface RawAd {
|
|
81
|
+
user?: RawPerson;
|
|
82
|
+
actualPpleUser?: RawPerson;
|
|
83
|
+
activeRole?: string;
|
|
84
|
+
eligibleRoles?: unknown;
|
|
85
|
+
eligibleProvinces?: unknown;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface RawUserInfo {
|
|
89
|
+
sub?: string;
|
|
90
|
+
name?: string;
|
|
91
|
+
ad?: RawAd;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function stringArray(value: unknown): string[] {
|
|
95
|
+
return Array.isArray(value)
|
|
96
|
+
? value.filter((v): v is string => typeof v === "string")
|
|
97
|
+
: [];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Extra-roles nested under a person's AD metadata, plus the synthetic
|
|
101
|
+
* `province_co` a province coordinator carries. */
|
|
102
|
+
function extraRolesOf(person: RawPerson | undefined): string[] {
|
|
103
|
+
const ad = person?.metadata?.ad;
|
|
104
|
+
const roles = stringArray(ad?.extra_roles);
|
|
105
|
+
if (person?.role === "province" && ad?.is_province_coordinator === true) {
|
|
106
|
+
roles.push("province_co");
|
|
107
|
+
}
|
|
108
|
+
return roles;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function toIdentity(body: RawUserInfo): Identity {
|
|
112
|
+
const ad = body.ad;
|
|
113
|
+
const effectivePerson = ad?.user;
|
|
114
|
+
// When nobody is delegating, `actualPpleUser` mirrors `user`.
|
|
115
|
+
const actualPerson = ad?.actualPpleUser ?? effectivePerson;
|
|
116
|
+
const activeRole = ad?.activeRole ?? effectivePerson?.role ?? "";
|
|
117
|
+
const eligibleRoles = stringArray(ad?.eligibleRoles);
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
actor: {
|
|
121
|
+
// Top-level `sub` is the OIDC subject of the human who logged in.
|
|
122
|
+
sub: body.sub as string,
|
|
123
|
+
name: body.name ?? null,
|
|
124
|
+
mobile: actualPerson?.mobile ?? null,
|
|
125
|
+
},
|
|
126
|
+
effective: {
|
|
127
|
+
isDelegated:
|
|
128
|
+
effectivePerson?.id !== undefined &&
|
|
129
|
+
actualPerson?.id !== undefined &&
|
|
130
|
+
effectivePerson.id !== actualPerson.id,
|
|
131
|
+
activeRole,
|
|
132
|
+
eligibleRoles:
|
|
133
|
+
eligibleRoles.length > 0 ? eligibleRoles : activeRole ? [activeRole] : [],
|
|
134
|
+
provinces: stringArray(ad?.eligibleProvinces),
|
|
135
|
+
extraRoles: extraRolesOf(effectivePerson),
|
|
136
|
+
},
|
|
137
|
+
};
|
|
53
138
|
}
|