@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.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/dist/bin.js +53 -15
  3. package/package.json +3 -2
  4. package/templates/golden-path/.dev.vars.example +10 -13
  5. package/templates/golden-path/CLAUDE.md +22 -7
  6. package/templates/golden-path/README.md +13 -8
  7. package/templates/golden-path/package.json +1 -0
  8. package/templates/golden-path/shared/api.ts +36 -3
  9. package/templates/golden-path/src/auth.ts +101 -16
  10. package/templates/golden-path/src/dev-personas.ts +88 -0
  11. package/templates/golden-path/src/env.ts +4 -2
  12. package/templates/golden-path/src/index.ts +8 -7
  13. package/templates/golden-path/src/vite-env.d.ts +14 -0
  14. package/templates/golden-path/test/harness.ts +6 -2
  15. package/templates/golden-path/test/smoke.test.ts +98 -15
  16. package/templates/golden-path/web/App.tsx +1 -1
  17. package/templates/golden-path/web/main.tsx +2 -2
  18. package/templates/golden-path/web/pple.ts +6 -5
  19. package/dist/api.js +0 -108
  20. package/dist/cli.js +0 -151
  21. package/dist/commands/auth.js +0 -32
  22. package/dist/commands/deploy.js +0 -113
  23. package/dist/commands/env.js +0 -70
  24. package/dist/commands/info.js +0 -238
  25. package/dist/commands/init.js +0 -130
  26. package/dist/commands/upgrade.js +0 -29
  27. package/dist/credentials.js +0 -53
  28. package/dist/deps.js +0 -87
  29. package/dist/device-flow.js +0 -122
  30. package/dist/errors.js +0 -16
  31. package/dist/git.js +0 -127
  32. package/dist/link.js +0 -59
  33. package/dist/node-deps.js +0 -107
  34. package/dist/npm.js +0 -127
  35. package/dist/scaffold.js +0 -58
  36. package/dist/session.js +0 -29
  37. package/dist/skills.js +0 -86
  38. package/dist/ui.js +0 -12
  39. 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, compiles to dist/
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:os";
3
- import { run } from "./cli.js";
4
- import { nodeDeps } from "./node-deps.js";
5
- import { consoleOutput } from "./ui.js";
6
- const out = consoleOutput((text) => process.stdout.write(text), (text) => process.stderr.write(text));
7
- try {
8
- process.exitCode = await run(process.argv.slice(2), nodeDeps(out, os.homedir()));
9
- }
10
- catch (e) {
11
- // Not a failure the CLI knows how to explain — say so plainly instead of
12
- // dumping a stack trace on a Builder who can't act on it.
13
- process.stderr.write("เกิดข้อผิดพลาดภายใน pple CLI กรุณาส่งข้อความนี้ให้ทีมแพลตฟอร์ม:\n");
14
- process.stderr.write(`${e instanceof Error ? (e.stack ?? e.message) : String(e)}\n`);
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.1",
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 && tsc -p tsconfig.build.json",
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
- # Local development configuration. Copy this file to `.dev.vars` (which is
2
- # gitignored) and adjust. `wrangler dev` and `vite dev` load `.dev.vars`
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
- # Turns on the local auth bypass. When set, any request whose bearer token
6
- # equals this value is accepted as a fake signed-in user, so you can develop
7
- # in a plain browser without PPLE Today. The React app uses this token
8
- # automatically during `vite dev`.
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
- # Optional: exercise the notification helper locally. These are normally
15
- # injected by the platform at deploy time.
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
- - Inside PPLE Today, the mini-app SDK (`web/pple.ts`) captures the access
31
- token from the launch URL. The Worker validates it against PPLE ID
32
- (`src/auth.ts`).
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) and returns an access token — do not add a custom sign-in page
35
- or resurrect a NotInApp guard.
36
- - Locally, `DEV_AUTH` in `.dev.vars` bypasses PPLE Today. **Never** set
37
- `DEV_AUTH` in production; the platform never provisions it.
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 bypass |
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
- cp .dev.vars.example .dev.vars # local auth bypass
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
- In local dev you're signed in automatically as a fake user (the `DEV_AUTH`
36
- bypass), so you can build without PPLE Today. Opened inside PPLE Today, the
37
- mini-app SDK signs the real user in from the launch URL; opened in a plain
38
- browser after deploy, the same SDK runs the PPLE ID login.
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
- /** The signed-in user, as the Worker resolves it from the PPLE ID token. */
8
- export const MeSchema = z.object({
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 Me = z.infer<typeof MeSchema>;
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 interface Identity {
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
- /** Local-only bypass token; unset in production. See .dev.vars.example. */
21
- DEV_AUTH?: string;
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: accept a fake user when the request carries the
35
- // configured DEV_AUTH token. Never active in production, because the
36
- // platform never provisions DEV_AUTH.
37
- if (env.DEV_AUTH && token === env.DEV_AUTH) {
38
- return { ok: true, identity: { sub: "dev-user", name: "Local Dev" } };
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: { sub: body.sub, name: body.name ?? null } };
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
  }