@jerryc05/hi-tools 0.1.18 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,42 +5,38 @@ pnpm add -g @jerryc05/hi-tools
5
5
 
6
6
  # Help
7
7
  ```
8
- hi/0.1.10
9
-
10
- Usage:
11
- $ hi
8
+ hi [command]
12
9
 
13
10
  Commands:
14
- upgrade Upgrade to latest version (default using pnpm)
15
- mm [M]erge [M]aster: Update local master to remote's, then merge into current branch
16
- mmm [M]erge [M]aster (don't [M]odify local master): Merge remote's master into current branch, without updating local master
17
- tschk My ts-check rules
18
- wup [W]ait for pkg publish, [U]pdate target repo, and [P]ush
19
- ips Show current machine's IP addrs
20
- mdns Show mdns hostname.local
21
- bm <target> [B]ranch [M]erge: merge current HEAD into target branch without switching
22
- tt-npm-pub <repoID> [PUB]lish current hash of current repo to Luban
23
- tt-bam Update BAM code-gen
24
- tt-gecko Show gecko info by bits URL
25
- tt-i18n I18n scan and sort
26
- Print help message
11
+ hi mm [M]erge [M]aster: Update local master to remote's, then merge into
12
+ current branch
13
+ hi mmm [M]erge [M]aster (don't [M]odify local master): Merge remote's
14
+ master into current branch, without updating local master
15
+ hi tschk My ts-check rules
16
+ hi wup [W]ait for pkg publish, [U]pdate target repo, and [P]ush
17
+ hi ips Show current machine's IP addrs
18
+ hi mdns Show mdns [hostname].local
19
+ hi tt TT/BD internal toolset
20
+
21
+ Options:
22
+ --version Show version number [boolean]
23
+ --verbose Run with verbose logging [boolean]
24
+ --help Show help [boolean]
25
+ ```
27
26
 
28
- For more info, run any command with the `--help` flag:
29
- $ hi upgrade --help
30
- $ hi mm --help
31
- $ hi mmm --help
32
- $ hi tschk --help
33
- $ hi wup --help
34
- $ hi ips --help
35
- $ hi mdns --help
36
- $ hi bm --help
37
- $ hi tt-npm-pub --help
38
- $ hi tt-bam --help
39
- $ hi tt-gecko --help
40
- $ hi tt-i18n --help
41
- $ hi --help
27
+ ```
28
+ hi tt
29
+
30
+ TT/BD internal toolset
31
+
32
+ Commands:
33
+ hi tt bam Update BAM code-gen
34
+ hi tt tt-gecko Show gecko info by bits URL
35
+ hi tt i18n I18n scan and sort
36
+ hi tt luban <repoId> Publish current repo pkg to Luban
42
37
 
43
38
  Options:
44
- -v, --version Display version number
45
- -h, --help Display this message
39
+ --version Show version number [boolean]
40
+ --verbose Run with verbose logging [boolean]
41
+ --help Show help [boolean]
46
42
  ```
package/bin/cli.mjs CHANGED
File without changes
package/dist/index.js CHANGED
@@ -1,22 +1,20 @@
1
1
  #!/usr/bin/env node
2
- typeof globalThis.CustomEvent>"u"&&(globalThis.CustomEvent=class extends Event{constructor(n,t={}){super(n,t),this.detail=t.detail}});import{readFile as he}from"node:fs/promises";import{join as be}from"node:path";import{log as ye}from"@clack/prompts";var S=[{cmd:{name:"bm <target>",desc:"[B]ranch [M]erge: merge current HEAD into target branch without switching"},action:async e=>{throw console.log(`\u{1F680} Starting silent merge: HEAD -> ${e}`),new Error("Not implemeted!")}}];import{networkInterfaces as Y}from"node:os";var x=[{cmd:{name:"ips",desc:"Show current machine's IP addrs"},options:[{name:"-4, --onlyIpv4",desc:"IPv4 only"},{name:"-6, --onlyIpv6",desc:"IPv6 only"}],action:({onlyIpv4:e,onlyIpv6:n})=>{let t=Y(),i={};for(let[o,r]of Object.entries(t))r=r?.filter(s=>e?s.family==="IPv4":n?s.family==="IPv6":!0),r?.length&&(i[o]=r.map(s=>s.address));console.log(i)}}];async function ee({repoID:e,hash:n,branch:t}){let i="SCM_USERNAME",o="SCM_PASSWORD",r=process.env[i],s=process.env[o];(!r||!s)&&(console.log(`Missing ${r?o:i} in env var.
3
- Go to https://luban.bytedance.net/npm/publish and get your personal SCM username + password.`),process.exit(1));let{execa:m}=await import("execa");try{let c=m`git log -1 --pretty=%s`,a,p;t?t===!0?p=(await m`git branch --show-current`).stdout.trim():p=t:n&&(n===!0?a=(await m`git rev-parse HEAD`).stdout.trim():a=n);let g={repos:e,create_user:r,pub_base:a?"commit_base":"branch_base",base_commit_hash:a??"",branch_name:p??"",desc:`[${l?.version}] ${(await c).stdout.trim()}`,has_version_stage:!1};console.log(`\u2139\uFE0F ${g.create_user} is publishing ${l?.name}@${l?.version} to repoID=${g.repos}
4
- ${a?`hash=${a}`:`brch=${p}`}
5
- desc=${g.desc}`);let f=await fetch("https://scm.byted.org/api/v2/npm_versions/",{method:"POST",headers:{Authorization:`Basic ${Buffer.from(`${r}:${s}`).toString("base64")}`,Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(g)});if(!f.ok){let R=await f.text();console.log(`\u274C HTTP ${f.status} Error: ${R}`),process.exit(1)}let I=await f.json();console.log("\u{1F389} Successfully published:",I)}catch(c){console.error("\u274C Execution Failed:",c),process.exit(1)}}var C=[{cmd:{name:"tt-npm-pub <repoID>",desc:"[PUB]lish current hash of current repo to Luban"},options:[{name:"--hash [hash]",desc:"Publish pkg by hash (default)"},{name:"-b, --branch [branch]",desc:"Publish pkg by branch"}],action:ee}];import{hostname as te}from"node:os";var v=[{cmd:{name:"mdns",desc:"Show mdns hostname.local"},action:()=>{let e=te();console.log(e.toLowerCase().endsWith(".local")?e:`${e}.local`)}}];import{spinner as ne}from"@clack/prompts";async function _(){let{execa:e}=await import("execa");try{let{stdout:n}=await e`git rev-parse --abbrev-ref --symbolic-full-name @{u}`;return n.split("/")[0]||"origin"}catch{return"origin"}}async function k(e){let n=ne();n.start(`${e?"Updating":"Fetching"} master...`);let{execa:t}=await import("execa");await t({stdio:"inherit"})`git fetch ${await _()} master${e?":master":""}`,n.message("Merging ..."),await t({stdio:"inherit"})`git merge ${await _()}/master --no-verify --no-edit`,n.stop("Done")}var P=[{cmd:{name:"mm",desc:"[M]erge [M]aster: Update local master to remote's, then merge into current branch"},action:()=>k(!0)},{cmd:{name:"mmm",desc:"[M]erge [M]aster (don't [M]odify local master): Merge remote's master into current branch, without updating local master"},action:()=>k(!1)}];import{log as D,spinner as oe}from"@clack/prompts";var A=[{cmd:{name:"tschk",desc:"My ts-check rules"},action:async()=>{let e=oe();e.start("Running custom tsc type-check...");let n=["2322","2339","2551","6133","6192","18048"],{execa:t}=await import("execa");try{let{stdout:i}=await t({reject:!1,stderr:"ignore"})`npx tsc --noEmit --emitDeclarationOnly false`,o=i.split(`
6
- `).filter(r=>{if(r.includes("/node_modules/"))return!1;let s=r.match(/error TS(\d+):/);return!(!s?.[1]||n.includes(s[1]))});o.length>0?(e.stop("Type-check failed"),o.map(r=>console.log(r)),D.error("Type-check failed"),process.exit(1)):e.stop("Type-check passed")}catch(i){e.stop("Type-check failed"),console.error(i),D.error("Type-check failed"),process.exit(1)}}}];var T=[{cmd:{name:"tt-bam",desc:"Update BAM code-gen"},action:async()=>{let{execa:e}=await import("execa");await e({stdio:"inherit"})`pnpm dlx @byted-arch-fe/bam-code-generator update`}}];import{cancel as H,isCancel as j,log as h,note as L,select as G}from"@clack/prompts";import d from"picocolors";var E="https://bits.bytedance.net";async function $(e,n,t,i){let o={...e,pageNum:e.pageNum??1},r=`${E}/api/v1/pipelines/runs?${new URLSearchParams(o).toString()}`,s=await fetch(r,{method:"GET",headers:{"Content-Type":"application/json","X-jwt-token":n,Username:t.username},signal:i??null});return{response:s,getJson:async()=>await s.json()}}async function N(e,n,t){let i=`${E}/api/v1/pipelines/runs/${e}`,o=await fetch(i,{method:"GET",headers:{"Content-Type":"application/json","X-jwt-token":n,Username:t.username}});return{response:o,getJson:async()=>await o.json()}}var b={RUNNING:2,CANCELLED:7,SUCCESS:8,FAIL:9};import{cac as re}from"cac";var u=re("hi");function y(e){let n=new Date(e),t=new Intl.DateTimeFormat("en-US",{timeZoneName:"longOffset"}).formatToParts(n).find(i=>i.type==="timeZoneName")?.value.replace("GMT","");return`${n.toLocaleDateString("zh-CN")} ${n.toTimeString().split(" ")[0]} ${t??""}`}import{log as ie,spinner as se}from"@clack/prompts";import J from"picocolors";var w;async function U(){let e=se();if(e.start("Logging in..."),!w){let{AIPaaSAuth:i}=await import("@byted/aipaas-auth");w=new i("cn")}let n=await w.getJwt(),t=await w.getUserInfo();return e.stop(`Hi ${J.magenta(t.username)} from ${J.blue(`${t.scope} ${t.work_country}`)}`),ie.info(`Login will expire on ${y(t.exp*1e3)}`),{jwtStr:n,jwtObj:t}}async function ae({pipelineId:e,url:n,region:t}){let{jwtStr:i,jwtObj:o}=await U(),r=(()=>{if(e==null&&!n)throw new Error("pipelineId or url is required");return e??B(n??"")})(),s=await O(r,i,o,t);if(s.length<=0){h.error(`No Gecko info found${t?` matching region [${t}]`:""} in latest run`);return}let{default:m}=await import("qrcode");for(let c=0;c<s.length;c++){let a=s[c];try{let p=await m.toString(a?.qrCodeScheme??"",{type:"terminal",small:!0,errorCorrectionLevel:"L"});console.log(`
2
+ typeof globalThis.CustomEvent>"u"&&(globalThis.CustomEvent=class extends Event{constructor(n,t={}){super(n,t),this.detail=t.detail}});import{readFile as ve}from"node:fs/promises";import{join as Ce}from"node:path";import{intro as ke}from"@clack/prompts";import xe from"yargs";import{hideBin as Se}from"yargs/helpers";import{networkInterfaces as te}from"node:os";var ne={"only-ipv4":{alias:"4",desc:"IPv4 only",boolean:!0},"only-ipv6":{alias:"6",desc:"IPv6 only",boolean:!0}},k=[{command:"ips",describe:"Show current machine's IP addrs",builder:ne,handler(e){let n=te(),t={};for(let[o,r]of Object.entries(n))r=r?.filter(s=>e["only-ipv4"]?s.family==="IPv4":e["only-ipv6"]?s.family==="IPv6":!0),r?.length&&(t[o]=r.map(s=>s.address));console.log(t)}}];import{hostname as re}from"node:os";var x=[{command:"mdns",describe:"Show mdns [hostname].local",handler(){let e=re();console.log(e.toLowerCase().endsWith(".local")?e:`${e}.local`)}}];import{spinner as ie}from"@clack/prompts";async function S(){let{execa:e}=await import("execa");try{let{stdout:n}=await e`git rev-parse --abbrev-ref --symbolic-full-name @{u}`;return n.split("/")[0]||"origin"}catch{return"origin"}}async function _({updBranch:e,branch:n,verbose:t}){let o=ie();o.start(`${e?"Updating":"Fetching"} ${n}...`);let{execa:r}=await import("execa");await r({stdio:"inherit",env:t?{GIT_TRACE:"1"}:{}})`git fetch ${await S()} ${n}${e?`:${n}`:""}`,o.message("Merging ..."),await r({stdio:"inherit",env:t?{GIT_TRACE:"1"}:{}})`git merge ${await S()}/${n} --no-verify --no-edit ${t?"":"-q"}`,o.stop("Done")}var w={branch:{alias:"b",default:"master",desc:'Default=master, or "main" if you wish'}},P=[{command:"mm",describe:"[M]erge [M]aster: Update local master to remote's, then merge into current branch",builder:w,handler(e){let{branch:n=w.branch.default,verbose:t}=e;_({updBranch:!0,branch:n,verbose:t})}},{command:"mmm",describe:"[M]erge [M]aster (don't [M]odify local master): Merge remote's master into current branch, without updating local master",builder:w,handler(e){let{branch:n=w.branch.default,verbose:t}=e;_({updBranch:!1,branch:n,verbose:t})}}];import{log as D,spinner as oe}from"@clack/prompts";var T=[{command:"tschk",describe:"My ts-check rules",handler:async()=>{let e=oe();e.start("Running custom tsc type-check...");let n=["2322","2339","2551","6133","6192","18048"],{execa:t}=await import("execa");try{let{stdout:o}=await t({reject:!1,stderr:"ignore"})`npx tsc --noEmit --emitDeclarationOnly false`,r=o.split(`
3
+ `).filter(s=>{if(s.includes("/node_modules/"))return!1;let i=s.match(/error TS(\d+):/);return!(!i?.[1]||n.includes(i[1]))});r.length>0?(e.stop("Type-check failed"),r.map(s=>console.log(s)),D.error("Type-check failed"),process.exit(1)):e.stop("Type-check passed")}catch(o){e.stop("Type-check failed"),console.error(o),D.error("Type-check failed"),process.exit(1)}}}];var A=[{command:"bam",describe:"Update BAM code-gen",handler:async()=>{let{execa:e}=await import("execa");await e({stdio:"inherit"})`pnpm dlx @byted-arch-fe/bam-code-generator update`}}];import{cancel as L,isCancel as j,log as g,note as O,select as G}from"@clack/prompts";import m from"picocolors";var E="https://bits.bytedance.net";async function C(e,n,t,o){let r={...e,pageNum:e.pageNum??1},s=`${E}/api/v1/pipelines/runs?${new URLSearchParams(r).toString()}`,i=await fetch(s,{method:"GET",headers:{"Content-Type":"application/json","X-jwt-token":n,Username:t.username},signal:o??null});return{response:i,getJson:async()=>await i.json()}}async function N(e,n,t){let o=`${E}/api/v1/pipelines/runs/${e}`,r=await fetch(o,{method:"GET",headers:{"Content-Type":"application/json","X-jwt-token":n,Username:t.username}});return{response:r,getJson:async()=>await r.json()}}var b={RUNNING:2,CANCELLED:7,SUCCESS:8,FAIL:9};function y(e){let n=new Date(e),t=new Intl.DateTimeFormat("en-US",{timeZoneName:"longOffset"}).formatToParts(n).find(o=>o.type==="timeZoneName")?.value.replace("GMT","");return`${n.toLocaleDateString("zh-CN")} ${n.toTimeString().split(" ")[0]} ${t??""}`}import{log as se,spinner as ae}from"@clack/prompts";import U from"picocolors";var I;async function J(){let e=ae();if(e.start("Logging in..."),!I){let{AIPaaSAuth:o}=await import("@byted/aipaas-auth");I=new o("cn")}let n=await I.getJwt(),t=await I.getUserInfo();return e.stop(`Hi ${U.magenta(t.username)} from ${U.blue(`${t.scope} ${t.work_country}`)}`),se.info(`Login will expire on ${y(t.exp*1e3)}`),{jwtStr:n,jwtObj:t}}async function ce({pipelineId:e,url:n,region:t,verbose:o}){let{jwtStr:r,jwtObj:s}=await J(),i=(()=>{if(e==null&&!n)throw new Error("pipelineId or url is required");return e??q(n??"")})(),c=await B(i,r,s,t);if(c.length<=0){g.error(`No Gecko info found${t?` matching region [${t}]`:""} in latest run`);return}let{default:p}=await import("qrcode");for(let a=0;a<c.length;a++){let l=c[a];try{let u=await p.toString(l?.qrCodeScheme??"",{type:"terminal",small:!0,errorCorrectionLevel:"L"});console.log(`
7
4
 
8
- ${p}`),console.dir(a),c<s.length-1&&console.log(`
5
+ ${u}`),console.dir(l),a<c.length-1&&console.log(`
9
6
 
10
7
  -----------------
11
8
 
12
- `)}catch(p){console.error("Failed to generate QR:",p)}}}async function O(e,n,t,i){let{response:o,getJson:r}=await $({pipelineId:e,pageSize:1,withoutJob:!1},n,t);o.ok||(h.error(`[getRunInfoByPipelineID] failed: ${o.status} ${o.statusText}
13
- ${await o.text()}`),process.exit(1));let s=await r();s.pipelineRuns[0]?.runStatus!==b.SUCCESS&&h.warn(`Latest run (runId=${s.pipelineRuns[0]?.runId}) status=${q(s.pipelineRuns[0]?.runStatus)}. Gecko info may be unavailable.`);let m=M(s.pipelineRuns,i);if(m.length)return m;let c=await ce(e,s.pipelineRuns);if(c)return O(c,n,t,i);let a=await me(e,n,t);return await pe(a,n,t)}function M(e,n){return e.flatMap(t=>t.jobs.map(i=>{try{let o=i.jobAtom.output;if(!o)return null;let r=o.GECKO_packageInfo;if(!r)return null;let s=o.GECKO_region;if(n&&!s?.includes(n))return null;let m=JSON.parse(r),{qrCodeScheme:c,candidatePackage:a,channel:p,updatedAt:g,creator:f,distributeRule:I}=m.package,{scmVersion:R}=a,Q=y(Number.parseInt(g,10)*1e3),X=I.envLaneList.flatMap(Z=>Z.values);return{qrCodeScheme:c,region:s,scmVersion:R,channel:p,updatedDate:Q,creator:f,envs:X,runId:t.runId,runSeq:t.runSeq}}catch(o){return console.error(o),null}}).filter(i=>i!=null)).filter(t=>!!t)}async function ce(e,n){let t=n.flatMap(r=>r.jobs.map(s=>s.jobAtom.inputs?.trigger_params).filter(s=>!!s).filter(s=>s.detail_url.length));if(!t.length)return;L(`Found ${t.length} possible alternative pipeline(s) you may want to try instead.`,"Mistyped the pipeline ID?");let i=[{value:"",label:`(Keep current pipeline id=${e})`}].concat(t.map(r=>({value:B(r.detail_url),label:`${d.underline(r.development_task_name)} by ${r.developer.join(",")}`,hint:r.detail_url}))),o=await G({message:"Select a pipeline to change, or cancel [ESC] to use the current pipeline.",options:i});if(j(o)||!o){H("Keep using current pipeline");return}return h.success(`Using new pipeline id=${o}`),o}async function me(e,n,t){let{response:o,getJson:r}=await $({pipelineId:e,pageSize:10,withoutJob:!0},n,t);o.ok||(h.error(`[getRunInfoByPipelineID] failed: ${o.status} ${o.statusText}
14
- ${await o.text()}`),process.exit(1));let s=await r();s.pipelineRuns.length<=0&&(h.error(`No pipeline runs found in the most recent 10 runs
15
- ${JSON.stringify(s,null,1)}`),process.exit(1)),L("The latest pipeline run may be ongoing/failed. Try a previous run to inspect.","Select a previous run");let m=s.pipelineRuns.map(a=>{let p=q(a.runStatus),g=le(a),f=a.triggerInfo?.triggeredBy||a.createdBy||"?";return{value:a.runId,label:`#${a.runSeq} runId=${a.runId} ${p}`,hint:`${g} by ${f}`}}),c=await G({message:"Select the run ID to inspect",options:m});return j(c)&&(H("Run selection cancelled"),process.exit(0)),c}async function pe(e,n,t){let{response:i,getJson:o}=await N(e,n,t);i.ok||(h.error(`[getRunDetailByRunID] failed: ${i.status} ${i.statusText}
16
- ${await i.text()}`),process.exit(1));let r=await o();return M([r.pipelineRun])}function B(e){let n=/\bpipelineId=(\d+)\b/,t=e.match(n);if(t?.[1])return t[1];throw new Error(`Invalid URL. Expecting a url containing ${d.bold(d.yellow("pipelineId"))} query param. E.g. `+d.underline(d.gray(`https://b??.net/devops/??/develop/detail/??/flow?devops_space_type=server_fe&${d.bold(d.magenta("pipelineId=1139212901634"))}&stage=dev_gatekeeper_stage`)))}function q(e){switch(e){case b.RUNNING:return d.blue("RUNNING");case b.CANCELLED:return d.gray("CANCELLED");case b.SUCCESS:return d.green("SUCCESS");case b.FAIL:return d.red("FAIL")}return`status=${e}`}function le(e){return e.startedAt?`started @ ${y(e.startedAt)}`:e.createdAt?`created @ ${y(e.createdAt)}`:"time=?"}var F=[{cmd:{name:"tt-gecko",desc:"Show gecko info by bits URL"},options:[{name:"-p,--pipelineId <pipelineId>",desc:"Pipeline ID (Overrides URL)"},{name:"-u,--url <url>",desc:"Bits URL"},{name:"-r,--region <region>",desc:"Region filter (match-based)"}],examples:[`${u.name} tt-gecko -r us -u 'https://b??.net/devops/??/develop/detail/??/flow?devops_space_type=server_fe&pipelineId=1139212901634&stage=dev_gatekeeper_stage'`],action:ae}];import{access as ue,constants as de}from"node:fs/promises";var K=[{cmd:{name:"tt-i18n",desc:"I18n scan and sort"},action:async()=>{let e="starling.config.js",n="combine-lang.js";for(let o of[e,n])try{await ue(o,de.R_OK)}catch(r){console.error(`tt i18n: Failed to read ${o}
17
- `,r),process.exit(1)}let{execa:t,execaNode:i}=await import("execa");await t({stdio:"inherit"})`pnpm dlx @ies/starling-cli scan -c ${e} --fallback --disable-browser`,await i({stdio:"inherit"})`${e}`,await t({stdio:"inherit"})`pnpm --package=json-sort-cli dlx sortjson ./src/lang`.catch(o=>console.error("tt i18n sortjson error:",o))}}];var W=[...T,...F,...K];async function ge({npm:e,global:n}){let{execa:t}=await import("execa");await t({stdio:"inherit"})`${e?"npm":"pnpm"} add ${n?"-g":""} https://github.com/jerryc05/hi-tools.git`}var z=[{cmd:{name:"upgrade",desc:"Upgrade to latest version (default using pnpm)"},options:[{name:"--npm",desc:"Use npm instead of default"},{name:"-g,--global",desc:"Pass -g flag to pkg mgr"}],action:ge}];var fe=e=>new Promise(n=>setTimeout(n,e)),V=[{cmd:{name:"wup",desc:"[W]ait for pkg publish, [U]pdate target repo, and [P]ush"},options:[{name:"-t, --target <path>",desc:"Target repository path"},{name:"-c, --cmdPrefix <prefix>",desc:"Pkg install command prefix",config:{default:"pnpm add"}},{name:"--timeout <limit>",desc:"Timeout limit in seconds",config:{default:300}}],examples:[`${u.name} wup -t "/tmp/otherRepoPath" -c "emo add"`,`${u.name} wup -t "/tmp/otherRepoPath" -c "rush add --make-consistent -p"`],action:async({target:e,cmdPrefix:n,timeout:t})=>{l||(console.log("\u274C Unable to parse package.json!"),process.exit(1)),e||(console.log("\u274C Missing target repo path"),process.exit(1));let i=l.version,o=`${l.name}@${i}`,r=1e4,s=[...n.split(" "),o];console.log(`\u{1F680} Monitoring ${o}...`),console.log(`\u{1F4C2} Target: ${e}`),console.log(`\u{1F6E0} Install cmd: ${s.join(" ")}`);let{execa:m}=await import("execa");try{console.log("\u{1F4E5} Pulling latest changes in target repo..."),await m({cwd:e,stdio:"inherit",env:{GIT_TRACE:"1"}})`git pull`;let c=Date.now();for(;;){let{exitCode:a}=await m({reject:!1,stdio:"inherit"})`npm view ${o} version`;if(a===0){console.log(`
18
- \u2705 v${i} is live! Installing...`);try{await m({cwd:e,stdio:"inherit"})`${s}`,console.log(`
19
- \u{1F389} [SUCCESS] ${o} installed!`);break}catch{console.log(`
20
- \u26A0\uFE0F Registry updated but installation failed, retrying...`)}}else process.stdout.write(".");(Date.now()-c)/1e3>=t&&(console.error(`
21
- \u274C [ERROR] Timed out after ${t}s.`),process.exit(1)),await fe(r)}console.log("\u{1F4DD} Committing changes..."),await m({stdio:"inherit"})`git commit -am 'chore: upd ${o}`,console.log("\u{1F4E4} Pushing to remote..."),await m({stdio:"inherit"})`git push`,console.log("\u{1F389} DONE!")}catch(c){console.error(`
22
- \u274C Task failed:`,c),process.exit(1)}}}];var l=JSON.parse(await he(be(import.meta.dirname,"../package.json"),"utf8"));l&&ye.info(`${l.name} v${l.version}`);var we=[...z,...P,...A,...V,...x,...v,...S,...C,...W];for(let{cmd:e,options:n,examples:t,action:i}of we){let o=u.command(e.name,e.desc);for(let r of n??[])o=o.option(r.name,r.desc,r.config);for(let r of t??[])o=o.example(r);o.action(i)}u.version(l.version).help();u.command("","Print help message").action(u.outputHelp);u.parse();export{l as PKG_JSON_OBJ};
9
+ `)}catch(u){console.error("Failed to generate QR:",u)}}}var pe={url:{alias:"u",desc:"Bits URL",string:!0,conflicts:["pipeline-id"]},"pipeline-id":{alias:"p",desc:"Pipeline ID (Overrides URL)",string:!0,conflicts:["url"]},region:{alias:"r",desc:"String-match based region filter",string:!0}},H=[{command:"gecko",describe:"Show gecko info by bits URL",builder:e=>e.options(pe).example("$0 tt-gecko -r us -u 'https://b??.net/devops/??/develop/detail/??/flow?devops_space_type=server_fe&pipelineId=1139212901634&stage=dev_gatekeeper_stage'","Example of URL mode, filtering us region"),handler(e){let{url:n,pipelineId:t,region:o,verbose:r}=e;ce({url:n,pipelineId:t,region:o,verbose:r})}}];async function B(e,n,t,o){let{response:r,getJson:s}=await C({pipelineId:e,pageSize:1,withoutJob:!1},n,t);r.ok||(g.error(`[getRunInfoByPipelineID] failed: ${r.status} ${r.statusText}
10
+ ${await r.text()}`),process.exit(1));let i=await s();i.pipelineRuns[0]?.runStatus!==b.SUCCESS&&g.warn(`Latest run (runId=${i.pipelineRuns[0]?.runId}) status=${F(i.pipelineRuns[0]?.runStatus)}. Gecko info may be unavailable.`);let c=M(i.pipelineRuns,o);if(c.length)return c;let p=await le(e,i.pipelineRuns);if(p)return B(p,n,t,o);let a=await ue(e,n,t);return await me(a,n,t)}function M(e,n){return e.flatMap(t=>t.jobs.map(o=>{try{let r=o.jobAtom.output;if(!r)return null;let s=r.GECKO_packageInfo;if(!s)return null;let i=r.GECKO_region;if(n&&!i?.includes(n))return null;let c=JSON.parse(s),{qrCodeScheme:p,candidatePackage:a,channel:l,updatedAt:u,creator:f,distributeRule:R}=c.package,{scmVersion:v}=a,Z=y(Number.parseInt(u,10)*1e3),Y=R.envLaneList.flatMap(ee=>ee.values);return{qrCodeScheme:p,region:i,scmVersion:v,channel:l,updatedDate:Z,creator:f,envs:Y,runId:t.runId,runSeq:t.runSeq}}catch(r){return console.error(r),null}}).filter(o=>o!=null)).filter(t=>!!t)}async function le(e,n){let t=n.flatMap(s=>s.jobs.map(i=>i.jobAtom.inputs?.trigger_params).filter(i=>!!i).filter(i=>i.detail_url.length));if(!t.length)return;O(`Found ${t.length} possible alternative pipeline(s) you may want to try instead.`,"Mistyped the pipeline ID?");let o=[{value:"",label:`(Keep current pipeline id=${e})`}].concat(t.map(s=>({value:q(s.detail_url),label:`${m.underline(s.development_task_name)} by ${s.developer.join(",")}`,hint:s.detail_url}))),r=await G({message:"Select a pipeline to change, or cancel [ESC] to use the current pipeline.",options:o});if(j(r)||!r){L("Keep using current pipeline");return}return g.success(`Using new pipeline id=${r}`),r}async function ue(e,n,t){let{response:r,getJson:s}=await C({pipelineId:e,pageSize:10,withoutJob:!0},n,t);r.ok||(g.error(`[getRunInfoByPipelineID] failed: ${r.status} ${r.statusText}
11
+ ${await r.text()}`),process.exit(1));let i=await s();i.pipelineRuns.length<=0&&(g.error(`No pipeline runs found in the most recent 10 runs
12
+ ${JSON.stringify(i,null,1)}`),process.exit(1)),O("The latest pipeline run may be ongoing/failed. Try a previous run to inspect.","Select a previous run");let c=i.pipelineRuns.map(a=>{let l=F(a.runStatus),u=de(a),f=a.triggerInfo?.triggeredBy||a.createdBy||"?";return{value:a.runId,label:`#${a.runSeq} runId=${a.runId} ${l}`,hint:`${u} by ${f}`}}),p=await G({message:"Select the run ID to inspect",options:c});return j(p)&&(L("Run selection cancelled"),process.exit(0)),p}async function me(e,n,t){let{response:o,getJson:r}=await N(e,n,t);o.ok||(g.error(`[getRunDetailByRunID] failed: ${o.status} ${o.statusText}
13
+ ${await o.text()}`),process.exit(1));let s=await r();return M([s.pipelineRun])}function q(e){let n=/\bpipelineId=(\d+)\b/,o=e.match(n)?.[1]?.trim();if(o){if(!/^\d+$/.test(o))throw new Error("Invalid pipelineId query from URL. Expecting a pipelineId query value with all numbers");return o}throw new Error(`Invalid URL. Expecting a url containing ${m.bold(m.yellow("pipelineId"))} query param. E.g. `+m.underline(m.gray(`https://b??.net/devops/??/develop/detail/??/flow?devops_space_type=server_fe&${m.bold(m.magenta("pipelineId=1139212901634"))}&stage=dev_gatekeeper_stage`)))}function F(e){switch(e){case b.RUNNING:return m.blue("RUNNING");case b.CANCELLED:return m.gray("CANCELLED");case b.SUCCESS:return m.green("SUCCESS");case b.FAIL:return m.red("FAIL")}return`status=${e}`}function de(e){return e.startedAt?`started @ ${y(e.startedAt)}`:e.createdAt?`created @ ${y(e.createdAt)}`:"time=?"}import{access as fe,constants as ge}from"node:fs/promises";var K=[{command:"i18n",describe:"I18n scan and sort",handler:async()=>{let e="starling.config.js",n="combine-lang.js";for(let r of[e,n])try{await fe(r,ge.R_OK)}catch(s){console.error(`tt i18n: Failed to read ${r}
14
+ `,s),process.exit(1)}let{execa:t,execaNode:o}=await import("execa");await t({stdio:"inherit"})`pnpm dlx @ies/starling-cli scan -c ${e} --fallback --disable-browser`,await o({stdio:"inherit"})`${e}`,await t({stdio:"inherit"})`pnpm --package=json-sort-cli dlx sortjson ./src/lang`.catch(r=>console.error("tt i18n sortjson error:",r))}}];import{log as $,note as be}from"@clack/prompts";async function ye({repoId:e,hash:n,branch:t}){let o="SCM_USERNAME",r="SCM_PASSWORD",s=process.env[o],i=process.env[r];(!s||!i)&&($.error(`Missing ${s?r:o} in env var.
15
+ Go to https://luban.bytedance.net/npm/publish and get your personal SCM username+password.`),process.exit(1));let{execa:c}=await import("execa");try{let p=c`git log -1 --pretty=%s`,a,l;n||!n&&!t?n?a=n:a=(await c`git rev-parse HEAD`).stdout.trim():t?l=t:l=(await c`git branch --show-current`).stdout.trim();let u={repos:e,create_user:s,pub_base:a?"commit_base":"branch_base",base_commit_hash:a??"",branch_name:l??"",desc:`[${d?.version}] ${(await p).stdout.trim()}`,has_version_stage:!1};be(`\u2139\uFE0F ${u.create_user} is publishing ${d?.name}@${d?.version} to repoId=${u.repos}
16
+ ${a?`hash=${a}`:`brch=${l}`}
17
+ desc=${u.desc}`);let f=await fetch("https://scm.byted.org/api/v2/npm_versions/",{method:"POST",headers:{Authorization:`Basic ${Buffer.from(`${s}:${i}`).toString("base64")}`,Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(u)});if(!f.ok){let v=await f.text();$.error(`HTTP ${f.status} Error: ${v}`),process.exit(1)}let R=await f.json();$.success("\u{1F389} Successfully published:",R)}catch(p){$.error("Execution Failed:"),console.error(p),process.exit(1)}}var he={"by-hash":{alias:"h",desc:"Publish pkg by hash (default)",string:!0,conflicts:["by-branch"]},"by-branch":{alias:"b",desc:"Publish pkg by branch",string:!0,conflicts:["by-hash"]}},W=[{command:"luban <repoId>",describe:"Publish current repo pkg to Luban",builder:he,handler(e){let{byHash:n,byBranch:t}=e,o=Number(e.repoId);ye({repoId:o,hash:n,branch:t})}}];var z=[{command:"tt",describe:"TT/BD internal toolset",builder:e=>e.command([...A,...H,...K,...W]).demandCommand(1),handler(){}}];import{lstatSync as we}from"node:fs";import{log as V,note as Ie,spinner as h}from"@clack/prompts";var $e=e=>new Promise(n=>setTimeout(n,e));async function Re(e){let n=d.version,t=`${d.name}@${n}`,o=1e4,r=[...e.installCmdPrefix.split(" "),t];Ie(`\u{1F680} Monitoring ${t}...
18
+ \u{1F4C2} Target: ${e.target}
19
+ \u{1F6E0} Install cmd: ${r.join(" ")}`);let{execa:s}=await import("execa");try{let i=h();i.start("Pulling latest changes in target repo..."),await s({cwd:e.target,stdio:"inherit",env:{GIT_TRACE:"1"}})`git pull`,i.stop("Latest commit pulled"),i=h();let c=Date.now();for(let p=1;;p++){i.start(`Waiting for ${t}, attempt ${p}`);let{exitCode:a}=await s({reject:!1,stdio:"inherit"})`npm view ${t} version`;if(a===0){i.stop(`${t} is live! Found it \u2705`);try{i=h(),i.start(`Installing ${t} via ${r}`),await s({cwd:e.target,stdio:"inherit"})`${r}`,i.stop(`${t} installed! \u2705`);break}catch{i.stop(`${t} not installed`),V.error("Registry updated but failed to install")}}(Date.now()-c)/1e3>=e.timeout&&(i.stop(`Didn't find ${t} in ${e.timeout} sec(s)`),process.exit(1)),await $e(o)}i=h(),i.start("Committing changes..."),await s({stdio:"inherit"})`git commit -am 'chore: upd ${t}`,i.stop("Committed \u2705"),i=h(),i.start("Pushing to remote..."),await s({stdio:"inherit"})`git push`,i.stop("Pushed \u2705"),V.success("\u{1F389} DONE!")}catch(i){console.error(`
20
+ \u274C Task failed:`,i),process.exit(1)}}var Q={target:{alias:"t",desc:"Target repository path",demandOption:!0,normalize:!0},"install-cmd-prefix":{alias:"cmd",desc:"Pkg install command prefix",default:"pnpm add"},timeout:{desc:"Timeout checking new pkg version in sec",default:300}},X=[{command:"wup",describe:"[W]ait for pkg publish, [U]pdate target repo, and [P]ush",builder:e=>e.options(Q).example('$0 wup -t "/tmp/..." -c "emo add"',"Install w/ eden-mono").example('$0 wup -t "/tmp/..." -c "rush add --make-consistent -p"',"Install w/ @microsoft/rush"),handler(e){let{target:n,installCmdPrefix:t=Q["install-cmd-prefix"].default,verbose:o}=e,r=Number(e.timeout),s=`Path ${n} is not a directory.`;try{if(!n||!we(n).isDirectory())throw new Error(s);Re({target:n,installCmdPrefix:t,timeout:r,verbose:o})}catch(i){throw new Error(s,{cause:i})}}}];var d=JSON.parse(await ve(Ce(import.meta.dirname,"../package.json"),"utf8"));ke(`\u{1F44B} ${d.name} v${d.version}`);var _e=[...P,...T,...X,...k,...x,...z];xe().scriptName("hi").version(d.version).option("verbose",{type:"boolean",description:"Run with verbose logging",global:!0}).command(_e).help().parse(Se(process.argv));export{d as PKG};
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "@jerryc05/hi-tools",
3
- "version": "0.1.18",
3
+ "version": "0.2.0",
4
4
  "description": "A collection of my everyday SDE tools.",
5
5
  "scripts": {
6
6
  "pub": "npm run build && npm version patch && export NPM_CONFIG_REGISTRY=https://registry.npmjs.org &&{ npm whoami || npm login; } && npm publish --access public && git push",
7
- "build": "node build.js",
8
- "prepare": "husky"
7
+ "build": "node build.js"
9
8
  },
10
9
  "repository": {
11
10
  "type": "git",
@@ -21,8 +20,8 @@
21
20
  "type": "module",
22
21
  "license": "MIT",
23
22
  "dependencies": {
24
- "cac": "^7.0.0",
25
- "picocolors": "^1.1.1"
23
+ "picocolors": "^1.1.1",
24
+ "yargs": "^18.0.0"
26
25
  },
27
26
  "optionalDependencies": {
28
27
  "@byted/aipaas-auth": "^0.1.0",
@@ -34,24 +33,26 @@
34
33
  "@types/cli-progress": "^3.11.6",
35
34
  "@types/node": "^25.6.0",
36
35
  "@types/qrcode": "^1.5.6",
36
+ "@types/yargs": "^17.0.35",
37
37
  "cli-progress": "^3.12.0",
38
38
  "esbuild": "^0.28.0",
39
39
  "fast-glob": "^3.3.3",
40
- "husky": "^9.1.7",
41
40
  "p-map": "^7.0.4",
42
41
  "trash": "^10.1.1",
43
42
  "xxhash-wasm": "^1.1.0"
44
43
  },
45
44
  "overrides": {
46
- "@clack/prompts": "^1.3.0",
47
- "execa": "^9.6.1",
48
- "jsonwebtoken": "^9"
45
+ "@clack/prompts": "$@clack/prompts",
46
+ "execa": "$execa",
47
+ "jsonwebtoken": "^9",
48
+ "yargs": "$yargs"
49
49
  },
50
50
  "pnpm": {
51
51
  "overrides": {
52
- "@clack/prompts": "^1.3.0",
53
- "execa": "^9.6.1",
54
- "jsonwebtoken": "^9"
52
+ "@clack/prompts": "$@clack/prompts",
53
+ "execa": "$execa",
54
+ "jsonwebtoken": "^9",
55
+ "yargs": "$yargs"
55
56
  }
56
57
  }
57
58
  }