runhuman 1.2.0 → 1.3.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 (2) hide show
  1. package/dist/index.js +116 -110
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,60 +1,60 @@
1
1
  #!/usr/bin/env node
2
- var Ye=Object.defineProperty;var E=(s,t)=>()=>(s&&(t=s(s=0)),t);var Xe=(s,t)=>{for(var e in t)Ye(s,e,{get:t[e],enumerable:!0})};function et(s){return s instanceof T}function d(s){return et(s)?{message:s.message,exitCode:s.exitCode,details:s.details}:s instanceof Error?{message:s.message,exitCode:1}:{message:String(s),exitCode:1}}var T,B,Z,z,Q,Y,C=E(()=>{"use strict";T=class extends Error{constructor(e,n=1,o){super(e);this.exitCode=n;this.details=o;this.name="CliError"}},B=class extends T{constructor(t="Authentication failed",e){super(t,2,e),this.name="AuthenticationError"}},Z=class extends T{constructor(t="Resource not found",e){super(t,3,e),this.name="NotFoundError"}},z=class extends T{constructor(t="Validation failed",e){super(t,4,e),this.name="ValidationError"}},Q=class extends T{constructor(t="Operation timed out",e){super(t,5,e),this.name="TimeoutError"}},Y=class extends T{constructor(t="Insufficient balance",e){super(t,6,e),this.name="InsufficientBalanceError"}}});function a(s){return{pattern:s,build:e=>{if(!e)return s;let n=s;for(let[o,r]of Object.entries(e))r!==void 0&&(n=n.replace(`:${o}?`,r),n=n.replace(`:${o}`,r));return n=n.replace(/\/:[^/]+\?/g,""),n=n.replace(/\/+/g,"/"),n.length>1&&n.endsWith("/")&&(n=n.slice(0,-1)),n}}}var X=E(()=>{"use strict"});var D,ue=E(()=>{"use strict";X();D={dashboard:a("/dashboard"),onboarding:a("/dashboard/onboarding"),projects:a("/dashboard/projects"),usage:a("/dashboard/usage"),managePlan:a("/dashboard/manage-plan"),jobSimple:a("/dashboard/jobs/:jobId"),admin:a("/dashboard/admin"),organizations:a("/dashboard/organizations"),organization:a("/dashboard/organizations/:organizationId"),organizationMembers:a("/dashboard/organizations/:organizationId/members"),organizationSettings:a("/dashboard/organizations/:organizationId/settings"),organizationUsage:a("/dashboard/organizations/:organizationId/usage"),organizationProjects:a("/dashboard/organizations/:organizationId/projects"),organizationApiKeys:a("/dashboard/organizations/:organizationId/api-keys"),organizationIntegrations:a("/dashboard/organizations/:organizationId/integrations"),organizationGitHub:a("/dashboard/organizations/:organizationId/github"),organizationImportGitHub:a("/dashboard/organizations/:organizationId/import"),settings:a("/dashboard/settings"),settingsAccount:a("/dashboard/settings/account"),settingsGitHub:a("/dashboard/settings/github"),settingsApiKeys:a("/dashboard/settings/api-keys"),tester:a("/tester"),testerJobs:a("/tester/jobs"),testerSettings:a("/tester/settings"),project:a("/dashboard/:projectId"),playground:a("/dashboard/:projectId/playground"),jobs:a("/dashboard/:projectId/jobs"),job:a("/dashboard/:projectId/jobs/:jobId"),templates:a("/dashboard/:projectId/templates"),template:a("/dashboard/:projectId/templates/:templateId"),issues:a("/dashboard/:projectId/issues"),issue:a("/dashboard/:projectId/issues/:issueNumber"),issueSessions:a("/dashboard/:projectId/issue-sessions"),issueSession:a("/dashboard/:projectId/issue-sessions/:sessionId"),projectSettings:a("/dashboard/:projectId/settings"),flowCharts:a("/dashboard/:projectId/flowcharts"),flowChart:a("/dashboard/:projectId/flowcharts/:flowchartId"),flowChartView:a("/view/flowchart/:projectId/:flowchartId"),invite:a("/invite/:token"),quickStart:a("/start"),publicJob:a("/j/:jobId/:token"),statuspage:a("/statuspage"),docs:a("/docs/quick-start"),pricing:a("/pricing"),home:a("/")}});var y,pe=E(()=>{"use strict";X();y={jobs:a("/jobs"),job:a("/jobs/:jobId"),jobStatus:a("/jobs/:jobId/status"),jobFeedback:a("/jobs/:jobId/feedback"),jobShare:a("/jobs/:jobId/share"),jobClaim:a("/jobs/:jobId/claim"),run:a("/run"),execute:a("/execute"),publicJob:a("/public/jobs/:jobId/:token"),testerJob:a("/tester/jobs/:jobId"),testerJobUploadUrls:a("/tester/jobs/:jobId/upload-urls"),testerJobProcessResults:a("/tester/jobs/:jobId/process-results"),testerJobProcessingStatus:a("/tester/jobs/:jobId/processing/:processingJobId"),testerJobExtractFrames:a("/tester/jobs/:jobId/extract-frames"),testerJobAbort:a("/tester/jobs/:jobId/abort"),testerJobInvalid:a("/tester/jobs/:jobId/invalid"),testerJobPhase:a("/tester/jobs/:jobId/phase"),keys:a("/keys"),key:a("/keys/:keyId"),keyRevoke:a("/keys/:keyId/revoke"),keyInfo:a("/key-info"),pats:a("/pats"),pat:a("/pats/:patId"),patRevoke:a("/pats/:patId/revoke"),patInfo:a("/pat-info"),projects:a("/projects"),project:a("/projects/:projectId"),projectJobs:a("/projects/:projectId/jobs"),projectApiKeys:a("/projects/:projectId/api-keys"),projectTransfer:a("/projects/:projectId/transfer"),projectTemplates:a("/projects/:projectId/templates"),projectTemplate:a("/projects/:projectId/templates/:templateId"),projectFlowCharts:a("/projects/:projectId/flowcharts"),projectFlowChartsUpload:a("/projects/:projectId/flowcharts/upload"),projectFlowChart:a("/projects/:projectId/flowcharts/:flowchartId"),projectFlowChartData:a("/projects/:projectId/flowcharts/:flowchartId/data"),projectFlowChartChat:a("/projects/:projectId/flowcharts/:flowchartId/chat"),projectFlowChartShare:a("/projects/:projectId/flowcharts/:flowchartId/share"),bulkCreateProjects:a("/projects/bulk"),githubOAuthAuthorize:a("/github/oauth/authorize"),githubCallback:a("/github/oauth/callback"),githubLink:a("/github/link"),githubIssuesByRepo:a("/github/issues/:owner/:repo"),githubIssues:a("/github/issues"),githubIssue:a("/github/issues/:issueNumber"),githubIssueComments:a("/github/issues/:issueNumber/comments"),githubIssueLabels:a("/github/issues/labels"),githubIssueAssignees:a("/github/issues/assignees"),githubIssueTest:a("/github/issues/test"),githubIssuesBulkTest:a("/github/issues/bulk-test"),githubTestSessions:a("/github/issues/test-sessions"),githubTestSession:a("/github/issues/test-sessions/:sessionId"),githubTestSessionSeen:a("/github/issues/test-sessions/:sessionId/seen"),githubTestSessionsCounts:a("/github/issues/test-sessions/counts"),githubBulkTest:a("/github/bulk-test"),githubWebhooks:a("/github/webhooks"),authSync:a("/auth/sync"),authMe:a("/auth/me"),authStartup:a("/auth/startup"),authDeleteAccount:a("/auth/account"),billingBalance:a("/billing/balance"),billingHasCredits:a("/billing/has-credits"),billingPortal:a("/billing/portal"),billingCheckout:a("/billing/checkout"),health:a("/health"),status:a("/status"),templates:a("/templates"),issueAnalyzer:a("/issue-analyzer"),prAnalyzer:a("/pr-analyzer"),logs:a("/logs"),relevantIssuesDiscover:a("/relevant-issues/discover"),relevantIssuesLatest:a("/relevant-issues/latest"),onboarding:a("/onboarding"),onboardingComplete:a("/onboarding/complete"),onboardingCheck:a("/onboarding/check"),search:a("/search"),testerApply:a("/tester/apply"),testerProfile:a("/tester/profile"),testerPublicProfile:a("/testers/:testerId/profile"),testerDownloadApp:a("/tester/download-app"),testerAvatarUploadUrl:a("/tester/profile/avatar-upload-url"),testerAppVersion:a("/tester/app-version"),repoTemplates:a("/repos/:owner/:repo/templates"),repoTemplate:a("/repos/:owner/:repo/templates/:templateName"),organizations:a("/organizations"),organization:a("/organizations/:organizationId"),organizationMembers:a("/organizations/:organizationId/members"),organizationInvite:a("/organizations/:organizationId/invite"),organizationMember:a("/organizations/:organizationId/members/:userId"),organizationProjects:a("/organizations/:organizationId/projects"),organizationJobs:a("/organizations/:organizationId/jobs"),organizationTransferOwnership:a("/organizations/:organizationId/transfer-ownership"),organizationApiKeys:a("/organizations/:organizationId/api-keys"),organizationGitHubInstallations:a("/organizations/:organizationId/github/installations"),organizationGitHubInstallation:a("/organizations/:organizationId/github/installations/:installationId"),organizationGitHubRepos:a("/organizations/:organizationId/github/repos"),organizationGitHubInstallationRefresh:a("/organizations/:organizationId/github/installations/:installationId/refresh"),organizationGitHubRepoCheckAccess:a("/organizations/:organizationId/github/repos/check-access"),organizationGitHubRepoFindUrl:a("/organizations/:organizationId/github/repos/find-url"),organizationBilling:a("/organizations/:organizationId/billing"),transfersPending:a("/transfers/pending"),transfersOutgoing:a("/transfers/outgoing"),transferAccept:a("/transfers/:transferId/accept"),transferReject:a("/transfers/:transferId/reject"),transferCancel:a("/transfers/:transferId/cancel"),invite:a("/invites/:token"),inviteRedeem:a("/invites/:token/redeem"),agreements:a("/agreements"),agreementCheck:a("/agreements/check"),changelog:a("/changelog"),changelogUnreadCount:a("/changelog/unread-count"),changelogMarkRead:a("/changelog/mark-read")}});var re=E(()=>{"use strict";X();ue();pe()});import nt from"axios";var f,k=E(()=>{"use strict";C();re();f=class{client;config;constructor(t){if(this.config=t,!t.apiUrl)throw new Error("apiUrl is required in CLI config");this.client=nt.create({baseURL:t.apiUrl+"/api",timeout:3e4,headers:{"Content-Type":"application/json"}}),this.client.interceptors.request.use(e=>(this.config.apiKey&&(e.headers.Authorization=`Bearer ${this.config.apiKey}`),e.method==="delete"&&!e.data&&delete e.headers["Content-Type"],e)),this.client.interceptors.response.use(e=>e,e=>{throw this.handleError(e)})}handleError(t){if(t.response){let e=t.response.status,n=t.response.data,o=n?.error||n?.message||t.message;switch(e){case 401:case 403:return new B(o,n);case 402:return new Y(o,n);case 404:return new Z(o,n);case 400:case 422:return new z(o,n);default:return new T(o,1,n)}}return t.code==="ECONNABORTED"?new T("Request timeout",5):t.code==="ENOTFOUND"||t.code==="ECONNREFUSED"?new T("Cannot connect to Runhuman API",1):new T(t.message,1)}async createJob(t){return(await this.client.post(y.jobs.build(),t)).data}async getJob(t){return(await this.client.get(y.job.build({jobId:t}))).data}async listJobs(t){return(await this.client.get(y.jobs.build(),{params:t})).data}async cancelJob(t){await this.client.post(y.jobCancel.build({jobId:t}))}async deleteJob(t){await this.client.delete(y.job.build({jobId:t}))}async listProjects(t){return(await this.client.get(y.projects.build(),{params:t})).data}async getProject(t){return(await this.client.get(y.project.build({projectId:t}))).data}async createProject(t){return(await this.client.post(y.projects.build(),t)).data}async updateProject(t,e){return(await this.client.patch(y.project.build({projectId:t}),e)).data}async deleteProject(t){await this.client.delete(y.project.build({projectId:t}))}async listApiKeys(t){return(await this.client.get(y.organizationApiKeys.build({organizationId:t}))).data}async createApiKey(t,e){return(await this.client.post(y.organizationApiKeys.build({organizationId:t}),{name:e})).data}async getApiKey(t){return(await this.client.get(y.key.build({keyId:t}))).data}async deleteApiKey(t){await this.client.delete(y.key.build({keyId:t}))}async listOrganizations(t){return(await this.client.get(y.organizations.build(),{params:t})).data}async getOrganization(t){return(await this.client.get(y.organization.build({organizationId:t}))).data}async getOrganizationBilling(t){return(await this.client.get(y.organizationBilling.build({organizationId:t}))).data}async listOrganizationProjects(t,e){return(await this.client.get(y.organizationProjects.build({organizationId:t}),{params:e})).data}async listTemplates(t){return(await this.client.get(y.projectTemplates.build({projectId:t}))).data}async getTemplate(t,e){return(await this.client.get(y.projectTemplate.build({projectId:t,templateId:e}))).data}async createTemplate(t,e){return(await this.client.post(y.projectTemplates.build({projectId:t}),e)).data}async updateTemplate(t,e,n){return(await this.client.patch(y.projectTemplate.build({projectId:t,templateId:e}),n)).data}async deleteTemplate(t,e){await this.client.delete(y.projectTemplate.build({projectId:t,templateId:e}))}async getCurrentUser(){return(await this.client.get(y.authMe.build())).data}async listGithubRepos(t,e){return(await this.client.get(y.organizationGitHubRepos.build({organizationId:t}),{params:e})).data}async listGithubIssues(t,e,n){return(await this.client.get(y.githubIssuesByRepo.build({owner:t,repo:e}),{params:n})).data}async getGithubIssue(t,e,n){return(await this.client.get(y.githubIssueByRepo.build({owner:t,repo:e,issueNumber:String(n)}))).data}}});import{cosmiconfig as rt}from"cosmiconfig";import{homedir as st}from"os";import{join as $}from"path";import{readFileSync as K,writeFileSync as N,existsSync as O,mkdirSync as se,chmodSync as it}from"fs";function lt(s){return ct.includes(s)}var at,v,L,G,ct,g,A=E(()=>{"use strict";at="runhuman",v=$(st(),".config","runhuman"),L=$(v,"config.json"),G=$(v,"credentials.json"),ct=["pretty","json","compact"];g=class{constructor(t=process.cwd()){this.cwd=t}projectConfig=null;globalConfig=null;envConfig=null;async loadConfig(t={}){this.envConfig=this.loadEnvConfig(),this.projectConfig=await this.loadProjectConfig(),this.globalConfig=this.loadGlobalConfig();let e=this.loadCredentials(),n=e?.accessToken?{apiKey:e.accessToken}:{},o=Object.fromEntries(Object.entries(t).filter(([,u])=>u!==void 0));return{...this.getDefaults(),...this.globalConfig,...this.projectConfig,...n,...this.envConfig,...o}}getDefaults(){return{apiUrl:"https://runhuman.com",outputFormat:"pretty",color:!0,autoOpenBrowser:!0,defaultDuration:5,defaultScreenSize:"desktop"}}loadEnvConfig(){let t={};return process.env.RUNHUMAN_API_KEY&&(t.apiKey=process.env.RUNHUMAN_API_KEY),process.env.RUNHUMAN_API_URL&&(t.apiUrl=process.env.RUNHUMAN_API_URL),process.env.RUNHUMAN_PROJECT&&(t.project=process.env.RUNHUMAN_PROJECT),process.env.RUNHUMAN_DEFAULT_URL&&(t.defaultUrl=process.env.RUNHUMAN_DEFAULT_URL),process.env.RUNHUMAN_DEFAULT_DURATION&&(t.defaultDuration=parseInt(process.env.RUNHUMAN_DEFAULT_DURATION,10)),process.env.RUNHUMAN_DEFAULT_SCREEN_SIZE&&(t.defaultScreenSize=process.env.RUNHUMAN_DEFAULT_SCREEN_SIZE),process.env.RUNHUMAN_OUTPUT_FORMAT&&lt(process.env.RUNHUMAN_OUTPUT_FORMAT)&&(t.outputFormat=process.env.RUNHUMAN_OUTPUT_FORMAT),process.env.RUNHUMAN_NO_COLOR==="1"&&(t.color=!1),t}async loadProjectConfig(){try{return(await rt(at).search(this.cwd))?.config||null}catch{return null}}loadGlobalConfig(){try{if(!O(L))return null;let t=K(L,"utf-8");return JSON.parse(t)}catch{return null}}async get(t){return(await this.loadConfig())[t]}async set(t,e,n=!1){n?await this.setGlobalConfig(t,e):await this.setProjectConfig(t,e)}async setGlobalConfig(t,e){O(v)||se(v,{recursive:!0});let n={};if(O(L)){let o=K(L,"utf-8");n=JSON.parse(o)}n[t]=e,N(L,JSON.stringify(n,null,2))}async setProjectConfig(t,e){let n=$(this.cwd,".runhumanrc"),o={};if(O(n)){let r=K(n,"utf-8");o=JSON.parse(r)}o[t]=e,N(n,JSON.stringify(o,null,2))}async saveProjectConfig(t){let e=$(this.cwd,".runhumanrc"),n={};if(O(e)){let r=K(e,"utf-8");n=JSON.parse(r)}let o={...n,...t};N(e,JSON.stringify(o,null,2))}async list(){let t=await this.loadConfig();return{global:this.globalConfig,project:this.projectConfig,env:this.envConfig,effective:t}}async reset(t){if((t==="global"||t==="all")&&O(L)&&N(L,"{}"),t==="project"||t==="all"){let e=$(this.cwd,".runhumanrc");O(e)&&N(e,"{}")}}saveCredentials(t){O(v)||se(v,{recursive:!0}),N(G,JSON.stringify(t,null,2));try{process.platform!=="win32"&&it(G,384)}catch{}}loadCredentials(){try{if(!O(G))return null;let t=K(G,"utf-8");return JSON.parse(t)}catch{return null}}clearCredentials(){O(G)&&N(G,"{}")}saveUserInfo(t){let e=$(v,"user.json");O(v)||se(v,{recursive:!0}),N(e,JSON.stringify(t,null,2))}loadUserInfo(){try{let t=$(v,"user.json");if(!O(t))return null;let e=K(t,"utf-8");return JSON.parse(e)}catch{return null}}clearUserInfo(){let t=$(v,"user.json");O(t)&&N(t,"{}")}}});import J from"chalk";import ut from"cli-table3";var l,I=E(()=>{"use strict";l=class{constructor(t={}){this.options=t}output(t){this.options.json?console.log(JSON.stringify(t,null,2)):t.success?t.data&&!this.options.quiet&&this.outputPretty(t.data):this.outputError(t.error?.message||"An error occurred")}outputPretty(t){typeof t=="string"?console.log(t):(Array.isArray(t),console.log(JSON.stringify(t,null,2)))}outputError(t,e){if(this.options.json){let n={success:!1,error:{message:t,details:e},timestamp:new Date().toISOString()};console.error(JSON.stringify(n,null,2))}else console.error(this.color("red",`
2
+ var rt=Object.defineProperty;var R=(i,t)=>()=>(i&&(t=i(i=0)),t);var st=(i,t)=>{for(var e in t)rt(i,e,{get:t[e],enumerable:!0})};function it(i){return i instanceof x}function d(i){return it(i)?{message:i.message,exitCode:i.exitCode,details:i.details}:i instanceof Error?{message:i.message,exitCode:1}:{message:String(i),exitCode:1}}var x,B,Y,O,Z,Q,C=R(()=>{"use strict";x=class extends Error{constructor(e,n=1,o){super(e);this.exitCode=n;this.details=o;this.name="CliError"}},B=class extends x{constructor(t="Authentication failed",e){super(t,2,e),this.name="AuthenticationError"}},Y=class extends x{constructor(t="Resource not found",e){super(t,3,e),this.name="NotFoundError"}},O=class extends x{constructor(t="Validation failed",e){super(t,4,e),this.name="ValidationError"}},Z=class extends x{constructor(t="Operation timed out",e){super(t,5,e),this.name="TimeoutError"}},Q=class extends x{constructor(t="Insufficient balance",e){super(t,6,e),this.name="InsufficientBalanceError"}}});function a(i){return{pattern:i,build:e=>{if(!e)return i;let n=i;for(let[o,r]of Object.entries(e))r!==void 0&&(n=n.replace(`:${o}?`,r),n=n.replace(`:${o}`,r));return n=n.replace(/\/:[^/]+\?/g,""),n=n.replace(/\/+/g,"/"),n.length>1&&n.endsWith("/")&&(n=n.slice(0,-1)),n}}}var X=R(()=>{"use strict"});var N,me=R(()=>{"use strict";X();N={dashboard:a("/dashboard"),managePlan:a("/dashboard/manage-plan"),plans:a("/dashboard/plans"),jobSimple:a("/dashboard/jobs/:jobId"),admin:a("/dashboard/admin"),organizations:a("/dashboard/organizations"),organization:a("/dashboard/organizations/:organizationId"),organizationMembers:a("/dashboard/organizations/:organizationId/members"),organizationSettings:a("/dashboard/organizations/:organizationId/settings"),organizationUsage:a("/dashboard/organizations/:organizationId/usage"),organizationProjects:a("/dashboard/organizations/:organizationId/projects"),organizationJobs:a("/dashboard/organizations/:organizationId/jobs"),organizationApiKeys:a("/dashboard/organizations/:organizationId/api-keys"),organizationIntegrations:a("/dashboard/organizations/:organizationId/integrations"),organizationGitHub:a("/dashboard/organizations/:organizationId/github"),organizationSso:a("/dashboard/organizations/:organizationId/sso"),organizationSchedules:a("/dashboard/organizations/:organizationId/schedules"),organizationImportGitHub:a("/dashboard/organizations/:organizationId/import"),settings:a("/dashboard/settings"),settingsAccount:a("/dashboard/settings/account"),tester:a("/tester"),testerJobs:a("/tester/jobs"),testerSettings:a("/tester/settings"),testerTest:a("/tester/test/:jobId"),project:a("/dashboard/:projectId"),playground:a("/dashboard/:projectId/playground"),jobs:a("/dashboard/:projectId/jobs"),job:a("/dashboard/:projectId/jobs/:jobId"),templates:a("/dashboard/:projectId/templates"),template:a("/dashboard/:projectId/templates/:templateId"),issues:a("/dashboard/:projectId/issues"),issue:a("/dashboard/:projectId/issues/:issueNumber"),issueSessions:a("/dashboard/:projectId/issue-sessions"),issueSession:a("/dashboard/:projectId/issue-sessions/:sessionId"),projectSettings:a("/dashboard/:projectId/settings"),schedules:a("/dashboard/:projectId/schedules"),flowCharts:a("/dashboard/:projectId/flowcharts"),flowChart:a("/dashboard/:projectId/flowcharts/:flowchartId"),flowChartView:a("/view/flowchart/:projectId/:flowchartId"),invite:a("/invite/:token"),quickStart:a("/start"),publicJob:a("/j/:jobId/:token"),statuspage:a("/statuspage"),docs:a("/docs/setup"),pricing:a("/pricing"),home:a("/"),learn:a("/learn"),learnLesson:a("/learn/:lessonSlug")}});var y,de=R(()=>{"use strict";X();y={jobs:a("/jobs"),job:a("/jobs/:jobId"),jobCancel:a("/jobs/:jobId/cancel"),jobCreateIssue:a("/jobs/:jobId/create-issue"),jobStatus:a("/jobs/:jobId/status"),jobArtifact:a("/jobs/:jobId/artifacts/:artifactType"),jobFeedback:a("/jobs/:jobId/feedback"),jobShare:a("/jobs/:jobId/share"),jobClaim:a("/jobs/:jobId/claim"),run:a("/run"),publicJob:a("/public/jobs/:jobId/:token"),testerJob:a("/tester/jobs/:jobId"),testerJobUploadUrls:a("/tester/jobs/:jobId/upload-urls"),testerJobProcessResults:a("/tester/jobs/:jobId/process-results"),testerJobProcessingStatus:a("/tester/jobs/:jobId/processing/:processingJobId"),testerJobExtractFrames:a("/tester/jobs/:jobId/extract-frames"),testerJobAbort:a("/tester/jobs/:jobId/abort"),testerJobInvalid:a("/tester/jobs/:jobId/invalid"),testerJobPhase:a("/tester/jobs/:jobId/phase"),livekitTesterToken:a("/tester/jobs/:jobId/livekit-token"),livekitEndSession:a("/tester/jobs/:jobId/livekit-end"),livekitTranscript:a("/tester/jobs/:jobId/livekit-transcript"),livekitViewerToken:a("/jobs/:jobId/livekit-viewer-token"),livekitStatus:a("/jobs/:jobId/livekit-status"),livekitRecording:a("/jobs/:jobId/livekit-recording"),keys:a("/keys"),key:a("/keys/:keyId"),keyRevoke:a("/keys/:keyId/revoke"),keyInfo:a("/key-info"),pats:a("/pats"),pat:a("/pats/:patId"),patRevoke:a("/pats/:patId/revoke"),patInfo:a("/pat-info"),projects:a("/projects"),project:a("/projects/:projectId"),projectJobs:a("/projects/:projectId/jobs"),projectApiKeys:a("/projects/:projectId/api-keys"),projectTransfer:a("/projects/:projectId/transfer"),projectTemplates:a("/projects/:projectId/templates"),projectTemplate:a("/projects/:projectId/templates/:templateId"),projectFlowCharts:a("/projects/:projectId/flowcharts"),projectFlowChartsUpload:a("/projects/:projectId/flowcharts/upload"),projectFlowChart:a("/projects/:projectId/flowcharts/:flowchartId"),projectFlowChartData:a("/projects/:projectId/flowcharts/:flowchartId/data"),projectFlowChartChat:a("/projects/:projectId/flowcharts/:flowchartId/chat"),projectFlowChartShare:a("/projects/:projectId/flowcharts/:flowchartId/share"),projectSchedules:a("/projects/:projectId/schedules"),projectSchedule:a("/projects/:projectId/schedules/:scheduleId"),projectScheduleExecutions:a("/projects/:projectId/schedules/:scheduleId/executions"),bulkCreateProjects:a("/projects/bulk"),githubOAuthAuthorize:a("/github/oauth/authorize"),githubCallback:a("/github/oauth/callback"),githubLink:a("/github/link"),githubIssuesByRepo:a("/github/issues/:owner/:repo"),githubIssueByRepo:a("/github/issues/:owner/:repo/:issueNumber"),githubIssues:a("/github/issues"),githubIssue:a("/github/issues/:issueNumber"),githubIssueComments:a("/github/issues/:issueNumber/comments"),githubIssueLabels:a("/github/issues/labels"),githubIssueAssignees:a("/github/issues/assignees"),githubIssueTest:a("/github/issues/test"),githubIssuesBulkTest:a("/github/issues/bulk-test"),githubTestSessions:a("/github/issues/test-sessions"),githubTestSession:a("/github/issues/test-sessions/:sessionId"),githubTestSessionSeen:a("/github/issues/test-sessions/:sessionId/seen"),githubTestSessionsCounts:a("/github/issues/test-sessions/counts"),githubBulkTest:a("/github/bulk-test"),githubWebhooks:a("/github/webhooks"),authSync:a("/auth/sync"),authMe:a("/auth/me"),authStartup:a("/auth/startup"),authDeleteAccount:a("/auth/account"),authDeletionPreview:a("/auth/account/deletion-preview"),billingBalance:a("/billing/balance"),billingHasCredits:a("/billing/has-credits"),billingPortal:a("/billing/portal"),billingCheckout:a("/billing/checkout"),billingSubscription:a("/billing/subscription"),billingChangePlan:a("/billing/change-plan"),health:a("/health"),status:a("/status"),templates:a("/templates"),issueAnalyzer:a("/issue-analyzer"),prAnalyzer:a("/pr-analyzer"),logs:a("/logs"),relevantIssuesDiscover:a("/relevant-issues/discover"),relevantIssuesLatest:a("/relevant-issues/latest"),onboarding:a("/onboarding"),onboardingComplete:a("/onboarding/complete"),onboardingCheck:a("/onboarding/check"),search:a("/search"),testerApply:a("/tester/apply"),testerProfile:a("/tester/profile"),testerPublicProfile:a("/testers/:testerId/profile"),testerDownloadApp:a("/tester/download-app"),testerDownloadExtension:a("/tester/download-extension"),testerDownloadMobileApp:a("/tester/download-mobile-app"),testerAvailableJobs:a("/tester/jobs/available"),testerAvatarUploadUrl:a("/tester/profile/avatar-upload-url"),testerAppVersion:a("/tester/app-version"),testerPushToken:a("/tester/push-token"),testerDemoJob:a("/tester/demo-job"),extensionTokens:a("/tester/extension-tokens"),extensionToken:a("/tester/extension-tokens/:tokenId"),extensionStream:a("/extension/stream"),testerJobCorrelate:a("/tester/jobs/:jobId/correlate"),testerJobDataStatus:a("/tester/jobs/:jobId/data-status"),testerJobExtensionToken:a("/tester/jobs/:jobId/extension-token"),repoTemplates:a("/repos/:owner/:repo/templates"),repoTemplate:a("/repos/:owner/:repo/templates/:templateName"),organizations:a("/organizations"),organization:a("/organizations/:organizationId"),organizationMembers:a("/organizations/:organizationId/members"),organizationInvite:a("/organizations/:organizationId/invite"),organizationMember:a("/organizations/:organizationId/members/:userId"),organizationProjects:a("/organizations/:organizationId/projects"),organizationJobs:a("/organizations/:organizationId/jobs"),organizationTransferOwnership:a("/organizations/:organizationId/transfer-ownership"),organizationApiKeys:a("/organizations/:organizationId/api-keys"),organizationApiKey:a("/organizations/:organizationId/api-keys/:keyId"),organizationGitHubInstallations:a("/organizations/:organizationId/github/installations"),organizationGitHubInstallation:a("/organizations/:organizationId/github/installations/:installationId"),organizationGitHubRepos:a("/organizations/:organizationId/github/repos"),organizationGitHubInstallationRefresh:a("/organizations/:organizationId/github/installations/:installationId/refresh"),organizationGitHubRepoCheckAccess:a("/organizations/:organizationId/github/repos/check-access"),organizationGitHubRepoFindUrl:a("/organizations/:organizationId/github/repos/find-url"),organizationSchedules:a("/organizations/:organizationId/schedules"),organizationBilling:a("/organizations/:organizationId/billing"),transfersPending:a("/transfers/pending"),transfersOutgoing:a("/transfers/outgoing"),transferAccept:a("/transfers/:transferId/accept"),transferReject:a("/transfers/:transferId/reject"),transferCancel:a("/transfers/:transferId/cancel"),invite:a("/invites/:token"),inviteRedeem:a("/invites/:token/redeem"),agreements:a("/agreements"),agreementCheck:a("/agreements/check"),organizationSsoConnections:a("/organizations/:organizationId/sso/connections"),organizationSsoConnection:a("/organizations/:organizationId/sso/connections/:connectionId"),enterpriseInquiry:a("/enterprise/inquiry"),changelog:a("/changelog"),changelogUnreadCount:a("/changelog/unread-count"),changelogMarkRead:a("/changelog/mark-read"),telemetrySessions:a("/telemetry/sessions"),telemetrySessionEnd:a("/telemetry/sessions/:sessionId/end"),telemetryBatch:a("/telemetry/sessions/:sessionId/events"),telemetrySessionStatus:a("/telemetry/jobs/:jobId/status"),telemetryShortCodeResolve:a("/telemetry/short-codes/:code")}});var ie=R(()=>{"use strict";X();me();de()});import lt from"axios";var f,T=R(()=>{"use strict";C();ie();f=class{client;config;constructor(t){if(this.config=t,!t.apiUrl)throw new Error("apiUrl is required in CLI config");this.client=lt.create({baseURL:t.apiUrl+"/api",timeout:3e4,headers:{"Content-Type":"application/json"}}),this.client.interceptors.request.use(e=>(this.config.apiKey&&(e.headers.Authorization=`Bearer ${this.config.apiKey}`),e.method==="delete"&&!e.data&&delete e.headers["Content-Type"],e)),this.client.interceptors.response.use(e=>e,e=>{throw this.handleError(e)})}handleError(t){if(t.response){let e=t.response.status,n=t.response.data,o=n?.error||n?.message||t.message;switch(e){case 401:case 403:return new B(o,n);case 402:return new Q(o,n);case 404:return new Y(o,n);case 400:case 422:return new O(o,n);default:return new x(o,1,n)}}return t.code==="ECONNABORTED"?new x("Request timeout",5):t.code==="ENOTFOUND"||t.code==="ECONNREFUSED"?new x("Cannot connect to Runhuman API",1):new x(t.message,1)}async createJob(t){return(await this.client.post(y.jobs.build(),t)).data}async getJob(t){return(await this.client.get(y.job.build({jobId:t}))).data}async listJobs(t){return(await this.client.get(y.jobs.build(),{params:t})).data}async cancelJob(t){await this.client.post(y.jobCancel.build({jobId:t}))}async deleteJob(t){await this.client.delete(y.job.build({jobId:t}))}async listProjects(t){return(await this.client.get(y.projects.build(),{params:t})).data}async getProject(t){return(await this.client.get(y.project.build({projectId:t}))).data}async createProject(t){return(await this.client.post(y.projects.build(),t)).data}async updateProject(t,e){return(await this.client.patch(y.project.build({projectId:t}),e)).data}async deleteProject(t){await this.client.delete(y.project.build({projectId:t}))}async listApiKeys(t){return(await this.client.get(y.organizationApiKeys.build({organizationId:t}))).data}async createApiKey(t,e){return(await this.client.post(y.organizationApiKeys.build({organizationId:t}),{name:e})).data}async getApiKey(t){return(await this.client.get(y.key.build({keyId:t}))).data}async deleteApiKey(t){await this.client.delete(y.key.build({keyId:t}))}async listOrganizations(t){return(await this.client.get(y.organizations.build(),{params:t})).data}async getOrganization(t){return(await this.client.get(y.organization.build({organizationId:t}))).data}async getOrganizationBilling(t){return(await this.client.get(y.organizationBilling.build({organizationId:t}))).data}async listOrganizationProjects(t,e){return(await this.client.get(y.organizationProjects.build({organizationId:t}),{params:e})).data}async listTemplates(t){return(await this.client.get(y.projectTemplates.build({projectId:t}))).data}async getTemplate(t,e){return(await this.client.get(y.projectTemplate.build({projectId:t,templateId:e}))).data}async createTemplate(t,e){return(await this.client.post(y.projectTemplates.build({projectId:t}),e)).data}async updateTemplate(t,e,n){return(await this.client.patch(y.projectTemplate.build({projectId:t,templateId:e}),n)).data}async deleteTemplate(t,e){await this.client.delete(y.projectTemplate.build({projectId:t,templateId:e}))}async getCurrentUser(){return(await this.client.get(y.authMe.build())).data}async listGithubRepos(t,e){return(await this.client.get(y.organizationGitHubRepos.build({organizationId:t}),{params:e})).data}async listGithubIssues(t,e,n){return(await this.client.get(y.githubIssuesByRepo.build({owner:t,repo:e}),{params:n})).data}async getGithubIssue(t,e,n){return(await this.client.get(y.githubIssueByRepo.build({owner:t,repo:e,issueNumber:String(n)}))).data}async initiateTransfer(t,e){return(await this.client.post(y.projectTransfer.build({projectId:t}),{toOrganizationId:e})).data}async listPendingTransfers(){return(await this.client.get(y.transfersPending.build())).data}async listOutgoingTransfers(){return(await this.client.get(y.transfersOutgoing.build())).data}async acceptTransfer(t){return(await this.client.post(y.transferAccept.build({transferId:t}),{})).data}async rejectTransfer(t){return(await this.client.post(y.transferReject.build({transferId:t}),{})).data}async cancelTransfer(t){return(await this.client.post(y.transferCancel.build({transferId:t}),{})).data}}});import{cosmiconfig as ut}from"cosmiconfig";import{homedir as pt}from"os";import{join as L}from"path";import{readFileSync as K,writeFileSync as M,existsSync as v,mkdirSync as ae,chmodSync as mt}from"fs";function ft(i){return gt.includes(i)}var dt,D,z,q,gt,g,A=R(()=>{"use strict";dt="runhuman",D=L(pt(),".config","runhuman"),z=L(D,"config.json"),q=L(D,"credentials.json"),gt=["pretty","json","compact"];g=class{constructor(t=process.cwd()){this.cwd=t}projectConfig=null;globalConfig=null;envConfig=null;async loadConfig(t={}){this.envConfig=this.loadEnvConfig(),this.projectConfig=await this.loadProjectConfig(),this.globalConfig=this.loadGlobalConfig();let e=this.loadCredentials(),n=e?.accessToken?{apiKey:e.accessToken}:{},o=Object.fromEntries(Object.entries(t).filter(([,u])=>u!==void 0));return{...this.getDefaults(),...this.globalConfig,...this.projectConfig,...n,...this.envConfig,...o}}getDefaults(){return{apiUrl:"https://runhuman.com",outputFormat:"pretty",color:!0,autoOpenBrowser:!0,defaultDuration:5,defaultDeviceClass:"desktop"}}loadEnvConfig(){let t={};return process.env.RUNHUMAN_API_KEY&&(t.apiKey=process.env.RUNHUMAN_API_KEY),process.env.RUNHUMAN_API_URL&&(t.apiUrl=process.env.RUNHUMAN_API_URL),process.env.RUNHUMAN_PROJECT&&(t.project=process.env.RUNHUMAN_PROJECT),process.env.RUNHUMAN_DEFAULT_URL&&(t.defaultUrl=process.env.RUNHUMAN_DEFAULT_URL),process.env.RUNHUMAN_DEFAULT_DURATION&&(t.defaultDuration=parseInt(process.env.RUNHUMAN_DEFAULT_DURATION,10)),process.env.RUNHUMAN_DEFAULT_DEVICE_CLASS&&(t.defaultDeviceClass=process.env.RUNHUMAN_DEFAULT_DEVICE_CLASS),process.env.RUNHUMAN_OUTPUT_FORMAT&&ft(process.env.RUNHUMAN_OUTPUT_FORMAT)&&(t.outputFormat=process.env.RUNHUMAN_OUTPUT_FORMAT),process.env.RUNHUMAN_NO_COLOR==="1"&&(t.color=!1),t}async loadProjectConfig(){try{return(await ut(dt).search(this.cwd))?.config||null}catch{return null}}loadGlobalConfig(){try{if(!v(z))return null;let t=K(z,"utf-8");return JSON.parse(t)}catch{return null}}async get(t){return(await this.loadConfig())[t]}async set(t,e,n=!1){n?await this.setGlobalConfig(t,e):await this.setProjectConfig(t,e)}async setGlobalConfig(t,e){v(D)||ae(D,{recursive:!0});let n={};if(v(z)){let o=K(z,"utf-8");n=JSON.parse(o)}n[t]=e,M(z,JSON.stringify(n,null,2))}async setProjectConfig(t,e){let n=L(this.cwd,".runhumanrc"),o={};if(v(n)){let r=K(n,"utf-8");o=JSON.parse(r)}o[t]=e,M(n,JSON.stringify(o,null,2))}async saveProjectConfig(t){let e=L(this.cwd,".runhumanrc"),n={};if(v(e)){let r=K(e,"utf-8");n=JSON.parse(r)}let o={...n,...t};M(e,JSON.stringify(o,null,2))}async list(){let t=await this.loadConfig();return{global:this.globalConfig,project:this.projectConfig,env:this.envConfig,effective:t}}async reset(t){if((t==="global"||t==="all")&&v(z)&&M(z,"{}"),t==="project"||t==="all"){let e=L(this.cwd,".runhumanrc");v(e)&&M(e,"{}")}}saveCredentials(t){v(D)||ae(D,{recursive:!0}),M(q,JSON.stringify(t,null,2));try{process.platform!=="win32"&&mt(q,384)}catch{}}loadCredentials(){try{if(!v(q))return null;let t=K(q,"utf-8");return JSON.parse(t)}catch{return null}}clearCredentials(){v(q)&&M(q,"{}")}saveUserInfo(t){let e=L(D,"user.json");v(D)||ae(D,{recursive:!0}),M(e,JSON.stringify(t,null,2))}loadUserInfo(){try{let t=L(D,"user.json");if(!v(t))return null;let e=K(t,"utf-8");return JSON.parse(e)}catch{return null}}clearUserInfo(){let t=L(D,"user.json");v(t)&&M(t,"{}")}}});import _ from"chalk";import ht from"cli-table3";var l,I=R(()=>{"use strict";l=class{constructor(t={}){this.options=t}output(t){this.options.json?console.log(JSON.stringify(t,null,2)):t.success?t.data&&!this.options.quiet&&this.outputPretty(t.data):this.outputError(t.error?.message||"An error occurred")}outputPretty(t){typeof t=="string"?console.log(t):(Array.isArray(t),console.log(JSON.stringify(t,null,2)))}outputError(t,e){if(this.options.json){let n={success:!1,error:{message:t,details:e},timestamp:new Date().toISOString()};console.error(JSON.stringify(n,null,2))}else console.error(this.color("red",`
3
3
  Error: ${t}
4
4
  `)),e?.code==="INSUFFICIENT_TOKENS"&&e?.link?(console.error(this.color("yellow","Add funds to continue:")),console.error(this.color("cyan",e.link)),console.error("")):e&&console.error(this.color("gray",JSON.stringify(e,null,2)))}success(t){!this.options.json&&!this.options.quiet&&console.log(this.color("green",`
5
5
  ${t}
6
6
  `))}info(t){!this.options.json&&!this.options.quiet&&console.log(this.color("blue",t))}warn(t){!this.options.json&&!this.options.quiet&&console.warn(this.color("yellow",`Warning: ${t}`))}formatJobList(t){if(this.options.format==="compact")return t.map(n=>`${n.id} ${n.status} ${n.url}`).join(`
7
- `);let e=new ut({head:["Job ID","Status","URL","Created","Duration","Cost"].map(n=>this.color("cyan",n)),colWidths:[15,12,30,14,10,10]});return t.forEach(n=>{e.push([n.id,this.formatStatus(n.status),n.url?this.truncate(n.url,28):"-",n.createdAt?this.formatDate(n.createdAt):"-",n.testDurationSeconds?this.formatDuration(n.testDurationSeconds):"-",n.costUsd?`$${n.costUsd.toFixed(3)}`:"-"])}),e.toString()}formatStatus(t){let e={pending:"yellow",waiting:"blue",working:"blue",creating_issues:"cyan",completed:"green",incomplete:"yellow",abandoned:"red",rejected:"gray",error:"red",failed:"red"},n=t.replaceAll("_"," ");return this.color(e[t]||"white",n)}formatDuration(t){if(t<60)return`${t}s`;let e=Math.floor(t/60),n=t%60;if(e<60)return`${e}m ${n}s`;let o=Math.floor(e/60),r=e%60;return`${o}h ${r}m ${n}s`}formatDate(t){let e=new Date(t),o=new Date().getTime()-e.getTime(),r=Math.floor(o/1e3),u=Math.floor(r/60),i=Math.floor(u/60),c=Math.floor(i/24);return r<60?`${r}s ago`:u<60?`${u}m ago`:i<24?`${i}h ago`:c<30?`${c}d ago`:e.toLocaleDateString()}truncate(t,e){return t.length<=e?t:t.substring(0,e-3)+"..."}color(t,e){if(this.options.color===!1)return e;let o={red:J.red,green:J.green,blue:J.blue,yellow:J.yellow,cyan:J.cyan,gray:J.gray,white:J.white}[t];return o?o(e):e}static result(t){return{success:!0,data:t,timestamp:new Date().toISOString()}}static error(t,e,n){return{success:!1,error:{message:t,code:e,details:n},timestamp:new Date().toISOString()}}}});var ae={};Xe(ae,{waitCommand:()=>ie,waitForJob:()=>fe});import{Command as to}from"commander";import oo from"ora";async function fe(s,t,e,n=600){let o=Date.now(),r=n*1e3,u=1e4,i=null;for(e.options.json||(i=oo("\u23F3 Waiting for job completion...").start());;){let c=Date.now()-o;if(c>=r)throw i&&i.fail("Timeout waiting for job completion"),new Q(`Job did not complete within ${n} seconds`);let p=await t.getJob(s);if(i){let m=e.formatDuration(Math.floor(c/1e3));i.text=`\u23F3 Waiting for job completion... (${m} elapsed, status: ${p.status})`}if(p.status==="completed"){if(i&&i.succeed("\u2705 Test Completed!"),!e.options.json){if(console.log(`
7
+ `);let e=new ht({head:["Job ID","Status","URL","Created","Duration","Cost"].map(n=>this.color("cyan",n)),colWidths:[15,12,30,14,10,10]});return t.forEach(n=>{e.push([n.id,this.formatStatus(n.status),n.url?this.truncate(n.url,28):"-",n.createdAt?this.formatDate(n.createdAt):"-",n.testDurationSeconds?this.formatDuration(n.testDurationSeconds):"-",n.costUsd?`$${n.costUsd.toFixed(3)}`:"-"])}),e.toString()}formatStatus(t){let e={pending:"yellow",waiting:"blue",working:"blue",completed:"green",incomplete:"yellow",abandoned:"red",rejected:"gray",error:"red",failed:"red"},n=t.replaceAll("_"," ");return this.color(e[t]||"white",n)}formatDuration(t){if(t<60)return`${t}s`;let e=Math.floor(t/60),n=t%60;if(e<60)return`${e}m ${n}s`;let o=Math.floor(e/60),r=e%60;return`${o}h ${r}m ${n}s`}formatDate(t){let e=new Date(t),o=new Date().getTime()-e.getTime(),r=Math.floor(o/1e3),u=Math.floor(r/60),s=Math.floor(u/60),c=Math.floor(s/24);return r<60?`${r}s ago`:u<60?`${u}m ago`:s<24?`${s}h ago`:c<30?`${c}d ago`:e.toLocaleDateString()}truncate(t,e){return t.length<=e?t:t.substring(0,e-3)+"..."}color(t,e){if(this.options.color===!1)return e;let o={red:_.red,green:_.green,blue:_.blue,yellow:_.yellow,cyan:_.cyan,gray:_.gray,white:_.white}[t];return o?o(e):e}static result(t){return{success:!0,data:t,timestamp:new Date().toISOString()}}static error(t,e,n){return{success:!1,error:{message:t,code:e,details:n},timestamp:new Date().toISOString()}}}});var le={};st(le,{waitCommand:()=>ce,waitForJob:()=>ye});import{Command as yo}from"commander";import wo from"ora";async function ye(i,t,e,n=600){let o=Date.now(),r=n*1e3,u=1e4,s=null;for(e.options.json||(s=wo("\u23F3 Waiting for job completion...").start());;){let c=Date.now()-o;if(c>=r)throw s&&s.fail("Timeout waiting for job completion"),new Z(`Job did not complete within ${n} seconds`);let p=await t.getJob(i);if(s){let m=e.formatDuration(Math.floor(c/1e3));s.text=`\u23F3 Waiting for job completion... (${m} elapsed, status: ${p.status})`}if(p.status==="completed"){if(s&&s.succeed("\u2705 Test Completed!"),!e.options.json){if(console.log(`
8
8
  Duration: `+(p.testDurationSeconds?e.formatDuration(p.testDurationSeconds):"N/A")),console.log(" Cost: $"+(p.costUsd||0).toFixed(3)),p.testerAlias&&console.log(" Tester: "+p.testerAlias),p.result){console.log(`
9
9
  \u{1F4CB} Results Summary:`);for(let[m,h]of Object.entries(p.result))console.log(` ${m}: ${h}`)}console.log(`
10
- \u{1F4BE} Full results:`),console.log(` runhuman results ${s}
11
- `)}return}if(p.status==="error"||p.status==="incomplete"||p.status==="abandoned")throw i&&i.fail(`Test ${p.status}`),new Error(`Job ${p.status}: ${p.testerResponse||"No details available"}`);if(p.status==="rejected")throw i&&i.fail("Test was rejected"),new Error("Job was rejected");await new Promise(m=>setTimeout(m,u))}}function ie(){let s=new to("wait");return s.description("Wait for a job to complete and display results").argument("<jobId>","Job ID to wait for").option("--timeout <seconds>","Max wait time (default: 600)",parseInt).option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u=new f(o);if(await fe(t,u,r,e.timeout||600),e.json){let i=await u.getJob(t),c=l.result(i);r.output(c)}}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s}var ee=E(()=>{"use strict";k();A();I();C()});import{Command as Xo}from"commander";k();A();I();C();import{Command as no}from"commander";import ro from"ora";re();function he(){let s=new no("create");return s.description("Create a new QA test job").argument("[url]","URL to test").option("-d, --description <text>","Test instructions for the human tester").option("-t, --template <name>","Use a template as base configuration").option("--duration <minutes>","Target duration (1-60 minutes)",parseInt).option("--screen-size <preset>","Screen size: desktop|laptop|tablet|mobile").option("--schema <file>","Path to JSON schema file for structured output").option("--schema-inline <json>","Inline JSON schema").option("--metadata <json>","Metadata for tracking (JSON string)").option("--github-repo <owner/repo>","GitHub repo for context").option("--create-issues","Auto-create GitHub issues from findings").option("--sync","Wait for result before exiting (synchronous mode)").option("--wait <seconds>","Max wait time in sync mode (default: 300)",parseInt).option("--project <id>","Project ID (or use default from config)").option("--api-key <key>","API key (or use from config/env)").option("--json","Output as JSON (for scripting)").option("--quiet","Minimal output (only job ID)").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,project:e.project}),r=new l({json:e.json,quiet:e.quiet,color:o.color}),u=new f(o);if(!t&&!e.template&&!o.defaultUrl)throw new z("URL is required (provide as argument, via --template, or set defaultUrl in config)");if(!e.description&&!e.template)throw new z("Description is required (use -d flag or --template)");if(!o.project)throw new z(`Project ID is required. Set a default project with:
10
+ \u{1F4BE} Full results:`),console.log(` runhuman results ${i}
11
+ `)}return}if(p.status==="error"||p.status==="incomplete"||p.status==="abandoned")throw s&&s.fail(`Test ${p.status}`),new Error(`Job ${p.status}: ${p.testerResponse||"No details available"}`);if(p.status==="rejected")throw s&&s.fail("Test was rejected"),new Error("Job was rejected");await new Promise(m=>setTimeout(m,u))}}function ce(){let i=new yo("wait");return i.description("Wait for a job to complete and display results").argument("<jobId>","Job ID to wait for").option("--timeout <seconds>","Max wait time (default: 600)",parseInt).option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u=new f(o);if(await ye(t,u,r,e.timeout||600),e.json){let s=await u.getJob(t),c=l.result(s);r.output(c)}}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i}var oe=R(()=>{"use strict";T();A();I();C()});import{Command as hn}from"commander";T();A();I();C();import{Command as jo}from"commander";import Co from"ora";ie();var ee=["ios","android","pc","mac"],te=["english","spanish"];function we(){let i=new jo("create");return i.description("Create a new QA test job").argument("[url]","URL to test").option("-d, --description <text>","Test instructions for the human tester").option("-t, --template <name>","Use a template as base configuration").option("--duration <minutes>","Target duration (1-60 minutes)",parseInt).option("--device-class <class>","Device class: desktop|mobile").option("--schema <file>","Path to JSON schema file for structured output").option("--schema-inline <json>","Inline JSON schema").option("--metadata <json>","Metadata for tracking (JSON string)").option("--github-repo <owner/repo>","GitHub repo for context").option("--required-devices <devices>","Required tester devices (comma-separated: ios,android,pc,mac)").option("--required-languages <languages>","Required tester languages (comma-separated: english,spanish)").option("--require-social-videos","Require tester to create social videos").option("--sync","Wait for result before exiting (synchronous mode)").option("--wait <seconds>","Max wait time in sync mode (default: 300)",parseInt).option("--project <id>","Project ID (or use default from config)").option("--api-key <key>","API key (or use from config/env)").option("--json","Output as JSON (for scripting)").option("--quiet","Minimal output (only job ID)").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,project:e.project}),r=new l({json:e.json,quiet:e.quiet,color:o.color}),u=new f(o);if(!t&&!e.template&&!o.defaultUrl)throw new O("URL is required (provide as argument, via --template, or set defaultUrl in config)");if(!e.description&&!e.template)throw new O("Description is required (use -d flag or --template)");if(!o.project)throw new O(`Project ID is required. Set a default project with:
12
12
  runhuman projects switch <project-id>
13
- Or use the --project flag`);let i={projectId:o.project,url:t||o.defaultUrl||"",description:e.description||"",duration:e.duration||o.defaultDuration,screenSize:e.screenSize||o.defaultScreenSize};if(e.schema){let h=await(await import("fs/promises")).readFile(e.schema,"utf-8");i.schema=JSON.parse(h)}else e.schemaInline&&(i.schema=JSON.parse(e.schemaInline));e.metadata&&(i.metadata=JSON.parse(e.metadata)),e.githubRepo&&(i.githubRepo=e.githubRepo),e.createIssues&&(i.createIssues=!0),e.template&&(i.templateId=e.template);let c=e.json?null:ro("Creating QA test job...").start(),p=await u.createJob(i);if(c&&c.succeed("Job created successfully!"),e.json){let m=l.result({jobId:p.jobId,status:p.status,message:p.message,dashboardUrl:`${o.apiUrl}${D.jobSimple.build({jobId:p.jobId})}`,estimatedCompletionTime:p.estimatedCompletionTime});r.output(m)}else e.quiet?console.log(p.jobId):(console.log(`
14
- `+"=".repeat(60)),console.log(" Job ID: "+p.jobId),console.log(" Status: "+p.status),console.log(` Dashboard: ${o.apiUrl}${D.jobSimple.build({jobId:p.jobId})}`),console.log("=".repeat(60)+`
13
+ Or use the --project flag`);let s={projectId:o.project,url:t||o.defaultUrl||"",description:e.description||"",duration:e.duration||o.defaultDuration,deviceClass:e.deviceClass||o.defaultDeviceClass};if(e.schema){let h=await(await import("fs/promises")).readFile(e.schema,"utf-8");s.schema=JSON.parse(h)}else e.schemaInline&&(s.schema=JSON.parse(e.schemaInline));if(e.metadata&&(s.metadata=JSON.parse(e.metadata)),e.githubRepo&&(s.githubRepo=e.githubRepo),e.template&&(s.templateId=e.template),e.requiredDevices){let m=e.requiredDevices.split(",");for(let h of m)if(!ee.includes(h))throw new O(`Invalid device "${h}". Valid values: ${ee.join(", ")}`);s.requiredDevices=m}if(e.requiredLanguages){let m=e.requiredLanguages.split(",");for(let h of m)if(!te.includes(h))throw new O(`Invalid language "${h}". Valid values: ${te.join(", ")}`);s.requiredLanguages=m}e.requireSocialVideos&&(s.requireSocialVideos=!0);let c=e.json?null:Co("Creating QA test job...").start(),p=await u.createJob(s);if(c&&c.succeed("Job created successfully!"),e.json){let m=l.result({jobId:p.jobId,status:p.status,message:p.message,dashboardUrl:`${o.apiUrl}${N.jobSimple.build({jobId:p.jobId})}`,estimatedCompletionTime:p.estimatedCompletionTime});r.output(m)}else e.quiet?console.log(p.jobId):(console.log(`
14
+ `+"=".repeat(60)),console.log(" Job ID: "+p.jobId),console.log(" Status: "+p.status),console.log(` Dashboard: ${o.apiUrl}${N.jobSimple.build({jobId:p.jobId})}`),console.log("=".repeat(60)+`
15
15
  `),console.log("\u{1F4A1} Track progress:"),console.log(` runhuman status ${p.jobId}`),console.log(` runhuman wait ${p.jobId}
16
- `));if(e.sync){let{waitForJob:m}=await Promise.resolve().then(()=>(ee(),ae));await m(p.jobId,u,r,e.wait||300)}}catch(n){let o=d(n);new l({json:e.json,quiet:!1}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s}k();A();I();import{Command as so}from"commander";C();function be(){let s=new so("status");return s.description("Check the current status of a job").argument("<jobId>","Job ID to check").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),i=await new f(o).getJob(t);if(e.json){let c=l.result(i);r.output(c)}else console.log(`
16
+ `));if(e.sync){let{waitForJob:m}=await Promise.resolve().then(()=>(oe(),le));await m(p.jobId,u,r,e.wait||300)}}catch(n){let o=d(n);new l({json:e.json,quiet:!1}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i}T();A();I();import{Command as Io}from"commander";C();function je(){let i=new Io("status");return i.description("Check the current status of a job").argument("<jobId>","Job ID to check").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),s=await new f(o).getJob(t);if(e.json){let c=l.result(s);r.output(c)}else console.log(`
17
17
  \u{1F4CA} Job Status: `+t+`
18
- `),console.log(" Status: "+r.formatStatus(i.status)),i.testerAlias&&console.log(" Tester: "+i.testerAlias),i.url&&console.log(" URL: "+i.url),i.description&&console.log(" Description: "+i.description),i.createdAt&&console.log(" Created: "+i.createdAt),i.completedAt&&console.log(" Completed: "+i.completedAt),i.testDurationSeconds&&console.log(" Duration: "+r.formatDuration(i.testDurationSeconds)),i.costUsd&&console.log(" Cost: $"+i.costUsd.toFixed(3)),console.log(`
19
- Dashboard: ${o.apiUrl}${D.jobSimple.build({jobId:t})}
20
- `),i.status==="pending"||i.status==="waiting"||i.status==="working"?(console.log("\u{1F4A1} Wait for completion:"),console.log(` runhuman wait ${t}
21
- `)):i.status==="completed"&&(console.log("\u{1F4A1} View results:"),console.log(` runhuman results ${t}
22
- `))}catch(n){let o=new l({json:e.json}),r=d(n);o.outputError(r.message,r.details),process.exit(r.exitCode)}}),s}ee();k();A();I();C();import{Command as ao}from"commander";var ye="=".repeat(80);function R(s){return`
23
- ${ye}
24
- ${s}
25
- ${ye}
26
- `}function W(s){return new Date(s).toLocaleTimeString()}function io(s){let t=Math.floor(s/60),e=Math.floor(s%60);return`${String(t).padStart(2,"0")}:${String(e).padStart(2,"0")}`}function we(s){if(!s.transcription?.segments?.length)return R("Transcript")+` No transcript available
27
- `;let t=s.transcription.segments.map(e=>{let n=e.words[0];return` [${n?io(n.start):"00:00"}] ${e.text}`});return R("Transcript")+t.join(`
18
+ `),console.log(" Status: "+r.formatStatus(s.status)),s.testerAlias&&console.log(" Tester: "+s.testerAlias),s.url&&console.log(" URL: "+s.url),s.description&&console.log(" Description: "+s.description),s.createdAt&&console.log(" Created: "+s.createdAt),s.completedAt&&console.log(" Completed: "+s.completedAt),s.testDurationSeconds&&console.log(" Duration: "+r.formatDuration(s.testDurationSeconds)),s.costUsd&&console.log(" Cost: $"+s.costUsd.toFixed(3)),s.deviceClass&&console.log(" Device Class: "+s.deviceClass),s.requiredDevices?.length&&console.log(" Required Devices: "+s.requiredDevices.join(", ")),s.requiredLanguages?.length&&console.log(" Required Langs: "+s.requiredLanguages.join(", ")),s.requireSocialVideos&&console.log(" Social Videos: required"),console.log(`
19
+ Dashboard: ${o.apiUrl}${N.jobSimple.build({jobId:t})}
20
+ `),s.status==="pending"||s.status==="waiting"||s.status==="working"?(console.log("\u{1F4A1} Wait for completion:"),console.log(` runhuman wait ${t}
21
+ `)):s.status==="completed"&&(console.log("\u{1F4A1} View results:"),console.log(` runhuman results ${t}
22
+ `))}catch(n){let o=new l({json:e.json}),r=d(n);o.outputError(r.message,r.details),process.exit(r.exitCode)}}),i}oe();T();A();I();C();import{Command as Ao}from"commander";var Ce="=".repeat(80);function U(i){return`
23
+ ${Ce}
24
+ ${i}
25
+ ${Ce}
26
+ `}function G(i){return new Date(i).toLocaleTimeString()}function So(i){let t=Math.floor(i/60),e=Math.floor(i%60);return`${String(t).padStart(2,"0")}:${String(e).padStart(2,"0")}`}function Ie(i){if(!i.transcription?.segments?.length)return U("Transcript")+` No transcript available
27
+ `;let t=i.transcription.segments.map(e=>{let n=e.words[0];return` [${n?So(n.start):"00:00"}] ${e.text}`});return U("Transcript")+t.join(`
28
28
  `)+`
29
- `}function je(s){let t=s.testerData?.consoleMessages;if(!t?.length)return R("Console Logs")+` No console logs recorded
30
- `;let e=t.map(o=>{let r=W(o.timestamp);return` [${o.type}] ${r} ${o.message}`}),n=R("Console Logs")+e.join(`
29
+ `}function Se(i){let t=i.testerData?.consoleMessages;if(!t?.length)return U("Console Logs")+` No console logs recorded
30
+ `;let e=t.map(o=>{let r=G(o.timestamp);return` [${o.type}] ${r} ${o.message}`}),n=U("Console Logs")+e.join(`
31
31
  `)+`
32
- `;if(s.testerData?.truncationInfo){let o=s.testerData.truncationInfo;n+=`
32
+ `;if(i.testerData?.truncationInfo){let o=i.testerData.truncationInfo;n+=`
33
33
  (Truncated: ${JSON.stringify(o)})
34
- `}return n}function Ce(s){let t=s.testerData?.networkRequests;if(!t?.length)return R("Network Requests")+` No network requests recorded
35
- `;let e=t.map(n=>{let o=W(n.timestamp),r=n.status??"---";return` ${n.method} ${r} ${n.url} (${o})`});return R("Network Requests")+e.join(`
34
+ `}return n}function Ae(i){let t=i.testerData?.networkRequests;if(!t?.length)return U("Network Requests")+` No network requests recorded
35
+ `;let e=t.map(n=>{let o=G(n.timestamp),r=n.status??"---";return` ${n.method} ${r} ${n.url} (${o})`});return U("Network Requests")+e.join(`
36
36
  `)+`
37
- `}function Ie(s){let t=s.testerData?.events;if(!t?.length)return R("User Events")+` No events recorded
38
- `;let e=t.map(n=>{let o=W(n.timestamp),r;switch(n.type){case"click":r=`Click at (${n.x}, ${n.y})${n.element?` on ${n.element}`:""}`;break;case"page_load":r=`${n.event}: ${n.url}`;break;case"form_submit":r=`Form submit (${n.formInfo.fieldCount} fields)`;break;case"spa_route_change":r=`Route: ${n.route}`;break;case"keyboard_input":r=`Typed in ${n.elementInfo.tagName}`;break}return` [${n.type}] ${o} ${r}`});return R("User Events")+e.join(`
37
+ `}function Te(i){let t=i.testerData?.events;if(!t?.length)return U("User Events")+` No events recorded
38
+ `;let e=t.map(n=>{let o=G(n.timestamp),r;switch(n.type){case"click":r=`Click at (${n.x}, ${n.y})${n.element?` on ${n.element}`:""}`;break;case"page_load":r=`${n.event}: ${n.url}`;break;case"form_submit":r=`Form submit (${n.formInfo.fieldCount} fields)`;break;case"spa_route_change":r=`Route: ${n.route}`;break;case"keyboard_input":r=`Typed in ${n.elementInfo.tagName}`;break}return` [${n.type}] ${o} ${r}`});return U("User Events")+e.join(`
39
39
  `)+`
40
- `}function Se(s){if(!s.keyMoments?.length)return R("Key Moments")+` No key moments available
41
- `;let t=s.keyMoments.map(e=>{let n=W(e.timestamp);return` [${e.type}] ${n} ${e.description} (significance: ${e.significance})`});return R("Key Moments")+t.join(`
40
+ `}function Ee(i){if(!i.keyMoments?.length)return U("Key Moments")+` No key moments available
41
+ `;let t=i.keyMoments.map(e=>{let n=G(e.timestamp);return` [${e.type}] ${n} ${e.description} (significance: ${e.significance})`});return U("Key Moments")+t.join(`
42
42
  `)+`
43
- `}function Ae(s){if(!s.conversationHistory?.length)return R("Conversation History")+` No conversation messages
44
- `;let t=s.conversationHistory.map(e=>{let n=W(e.timestamp),o=e.role.charAt(0).toUpperCase()+e.role.slice(1);return` [${n}] ${o}: ${e.content}`});return R("Conversation History")+t.join(`
43
+ `}function ke(i){if(!i.conversationHistory?.length)return U("Conversation History")+` No conversation messages
44
+ `;let t=i.conversationHistory.map(e=>{let n=G(e.timestamp),o=e.role.charAt(0).toUpperCase()+e.role.slice(1);return` [${n}] ${o}: ${e.content}`});return U("Conversation History")+t.join(`
45
45
  `)+`
46
- `}function Pe(){let s=new ao("results");return s.description("Display detailed results for a completed job").argument("<jobId>","Job ID to show results for").option("--json","Output as JSON").option("--schema-only","Show only extracted schema data").option("--raw","Show raw tester response (no processing)").option("--transcript","Show voice transcript").option("--console-logs","Show console log output").option("--network","Show network requests").option("--events","Show user interaction events").option("--key-moments","Show key moments").option("--conversation","Show conversation history").option("--all","Show all rich test data").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),i=await new f(o).getJob(t);if(e.json){let p=l.result(i);r.output(p);return}if(console.log(`
46
+ `}function Pe(){let i=new Ao("results");return i.description("Display detailed results for a completed job").argument("<jobId>","Job ID to show results for").option("--json","Output as JSON").option("--schema-only","Show only extracted schema data").option("--raw","Show raw tester response (no processing)").option("--transcript","Show voice transcript").option("--console-logs","Show console log output").option("--network","Show network requests").option("--events","Show user interaction events").option("--key-moments","Show key moments").option("--conversation","Show conversation history").option("--all","Show all rich test data").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),s=await new f(o).getJob(t);if(e.json){let p=l.result(s);r.output(p);return}if(console.log(`
47
47
  \u{1F4CA} Test Results: `+t+`
48
48
  `),console.log("=".repeat(80)),console.log("Job Information"),console.log("=".repeat(80)+`
49
- `),console.log(" Job ID: "+i.id),console.log(" Status: "+i.status),i.url&&console.log(" URL: "+i.url),i.description&&console.log(" Description: "+i.description),i.createdAt&&console.log(" Started: "+i.createdAt),i.completedAt&&console.log(" Completed: "+i.completedAt),i.testDurationSeconds&&console.log(" Duration: "+r.formatDuration(i.testDurationSeconds)),i.costUsd&&console.log(" Cost: $"+i.costUsd.toFixed(3)),i.testerAlias&&console.log(" Tester: "+i.testerAlias),i.result&&Object.keys(i.result).length>0&&!e.raw){console.log(`
49
+ `),console.log(" Job ID: "+s.id),console.log(" Status: "+s.status),s.url&&console.log(" URL: "+s.url),s.description&&console.log(" Description: "+s.description),s.createdAt&&console.log(" Started: "+s.createdAt),s.completedAt&&console.log(" Completed: "+s.completedAt),s.testDurationSeconds&&console.log(" Duration: "+r.formatDuration(s.testDurationSeconds)),s.costUsd&&console.log(" Cost: $"+s.costUsd.toFixed(3)),s.testerAlias&&console.log(" Tester: "+s.testerAlias),s.deviceClass&&console.log(" Device Class: "+s.deviceClass),s.requiredDevices?.length&&console.log(" Required Devices: "+s.requiredDevices.join(", ")),s.requiredLanguages?.length&&console.log(" Required Langs: "+s.requiredLanguages.join(", ")),s.requireSocialVideos&&console.log(" Social Videos: required"),s.result&&Object.keys(s.result).length>0&&!e.raw){console.log(`
50
50
  `+"=".repeat(80)),console.log("Structured Results (Extracted)"),console.log("=".repeat(80)+`
51
- `);for(let[p,m]of Object.entries(i.result)){let h=typeof m=="object"?JSON.stringify(m,null,2):String(m);console.log(` ${p}:`.padEnd(30)+h)}}i.testerResponse&&!e.schemaOnly&&(console.log(`
51
+ `);for(let[p,m]of Object.entries(s.result)){let h=typeof m=="object"?JSON.stringify(m,null,2):String(m);console.log(` ${p}:`.padEnd(30)+h)}}s.testerResponse&&!e.schemaOnly&&(console.log(`
52
52
  `+"=".repeat(80)),console.log("Tester Feedback"),console.log("=".repeat(80)+`
53
- `),console.log(" "+i.testerResponse.split(`
53
+ `),console.log(" "+s.testerResponse.split(`
54
54
  `).join(`
55
- `)));let c=e.all;(c||e.transcript)&&console.log(we(i)),(c||e.consoleLogs)&&console.log(je(i)),(c||e.network)&&console.log(Ce(i)),(c||e.events)&&console.log(Ie(i)),(c||e.keyMoments)&&console.log(Se(i)),(c||e.conversation)&&console.log(Ae(i)),console.log("=".repeat(80)+`
56
- `),i.richResultsGated&&(console.log(" \u2139 Rich test data (transcript, logs, network) requires a paid plan."),console.log(` Upgrade at https://runhuman.com/pricing
57
- `))}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s}k();A();I();C();import{Command as co}from"commander";function ke(){let s=new co("list");return s.description("List all jobs with optional filtering").argument("[filter]","Status filter: all|pending|claimed|in_progress|completed|failed|timeout").option("--project <id>","Filter by project").option("--limit <number>","Number of results (default: 20)",parseInt).option("--offset <number>","Pagination offset (default: 0)",parseInt).option("--json","Output as JSON").option("--format <type>","Output format: table|json|compact").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,format:e.format,color:o.color}),u=new f(o),i=e.project||o.project;if(!i)throw new Error("Project ID required (use --project or set default project)");let c={limit:e.limit||20,offset:e.offset||0,projectId:i};t&&t!=="all"&&(c.status=t);let{items:p,pagination:m}=await u.listJobs(c);if(e.json){let h=l.result({jobs:p,pagination:m});r.output(h)}else{if(m.total===0){console.log(`
55
+ `)));let c=e.all;(c||e.transcript)&&console.log(Ie(s)),(c||e.consoleLogs)&&console.log(Se(s)),(c||e.network)&&console.log(Ae(s)),(c||e.events)&&console.log(Te(s)),(c||e.keyMoments)&&console.log(Ee(s)),(c||e.conversation)&&console.log(ke(s)),console.log("=".repeat(80)+`
56
+ `),s.richResultsGated&&(console.log(" \u2139 Rich test data (transcript, logs, network) requires a paid plan."),console.log(` Upgrade at https://runhuman.com/pricing
57
+ `))}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i}T();A();I();C();import{Command as To}from"commander";function xe(){let i=new To("list");return i.description("List all jobs with optional filtering").argument("[filter]","Status filter: all|pending|claimed|in_progress|completed|failed|timeout").option("--project <id>","Filter by project").option("--limit <number>","Number of results (default: 20)",parseInt).option("--offset <number>","Pagination offset (default: 0)",parseInt).option("--json","Output as JSON").option("--format <type>","Output format: table|json|compact").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,format:e.format,color:o.color}),u=new f(o),s=e.project||o.project;if(!s)throw new Error("Project ID required (use --project or set default project)");let c={limit:e.limit||20,offset:e.offset||0,projectId:s};t&&t!=="all"&&(c.status=t);let{items:p,pagination:m}=await u.listJobs(c);if(e.json){let h=l.result({jobs:p,pagination:m});r.output(h)}else{if(m.total===0){console.log(`
58
58
  \u{1F4CB} Recent Jobs (0)
59
59
  `),console.log(`No jobs found.
60
60
  `),console.log(`\u{1F4A1} Create a job: runhuman create <url> -d "Test description"
@@ -62,12 +62,12 @@ ${ye}
62
62
  \u{1F4CB} Recent Jobs (${p.length} of ${m.total})
63
63
  `),console.log(r.formatJobList(p)),console.log(`
64
64
  \u{1F4A1} View details: runhuman status <jobId>`),console.log(` View results: runhuman results <jobId>
65
- `)}}catch(n){let o=new l({json:e.json}),r=d(n);o.outputError(r.message,r.details),process.exit(r.exitCode)}}),s}k();A();I();C();import{Command as lo}from"commander";import uo from"inquirer";function xe(){let s=new lo("delete");return s.description("Delete a job permanently").argument("<jobId>","Job ID to delete").option("--force","Skip confirmation prompt").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color});if(!e.json&&!e.force){let{confirmed:i}=await uo.prompt([{type:"confirm",name:"confirmed",message:`Permanently delete job ${t}? This cannot be undone.`,default:!1}]);if(!i)return}if(await new f(o).deleteJob(t),e.json){let i=l.result({success:!0,message:"Job deleted successfully",jobId:t});r.output(i)}else console.log(`
65
+ `)}}catch(n){let o=new l({json:e.json}),r=d(n);o.outputError(r.message,r.details),process.exit(r.exitCode)}}),i}T();A();I();C();import{Command as Eo}from"commander";import ko from"inquirer";function ve(){let i=new Eo("delete");return i.description("Delete a job permanently").argument("<jobId>","Job ID to delete").option("--force","Skip confirmation prompt").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color});if(!e.json&&!e.force){let{confirmed:s}=await ko.prompt([{type:"confirm",name:"confirmed",message:`Permanently delete job ${t}? This cannot be undone.`,default:!1}]);if(!s)return}if(await new f(o).deleteJob(t),e.json){let s=l.result({success:!0,message:"Job deleted successfully",jobId:t});r.output(s)}else console.log(`
66
66
  \u2705 Job deleted successfully
67
67
  `),console.log(` Job ID: ${t}`),console.log(` Status: Permanently deleted
68
- `)}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s}k();A();I();C();import{Command as po}from"commander";import mo from"chokidar";import{existsSync as te,mkdirSync as go,readFileSync as ce,writeFileSync as fo,unlinkSync as ho}from"fs";import{join as Ue}from"path";import{homedir as Te}from"os";var M=Ue(Te(),".config","runhuman","watch.pid");function Oe(){let s=new po("watch");return s.description("Watch files and auto-create QA test jobs on changes").argument("[patterns...]",'File patterns to watch (e.g., "src/**/*.tsx")').option("--url <url>","URL to test (required)").option("--template <name>","Template to use for tests").option("--description <text>","Test description").option("--debounce <ms>","Debounce delay in milliseconds",parseInt).option("--ignore <patterns...>","Patterns to ignore").option("--stop","Stop existing watch process").option("--status","Check if watch is running").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{if(e.stop){await yo();return}if(e.status){wo();return}Re()&&(console.log(`
68
+ `)}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i}T();A();I();C();import{Command as Po}from"commander";import xo from"chokidar";import{existsSync as ne,mkdirSync as vo,readFileSync as ue,writeFileSync as Uo,unlinkSync as Do}from"fs";import{join as Ue}from"path";import{homedir as De}from"os";var $=Ue(De(),".config","runhuman","watch.pid");function Oe(){let i=new Po("watch");return i.description("Watch files and auto-create QA test jobs on changes").argument("[patterns...]",'File patterns to watch (e.g., "src/**/*.tsx")').option("--url <url>","URL to test (required)").option("--template <name>","Template to use for tests").option("--description <text>","Test description").option("--debounce <ms>","Debounce delay in milliseconds",parseInt).option("--ignore <patterns...>","Patterns to ignore").option("--stop","Stop existing watch process").option("--status","Check if watch is running").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{if(e.stop){await Ro();return}if(e.status){No();return}Re()&&(console.log(`
69
69
  \u26A0\uFE0F Watch mode is already running`),console.log(` Use --stop to stop it first
70
- `),process.exit(1));let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=o.watch||{},u=t.length>0?t:r.patterns||["src/**/*"],i=e.ignore||r.ignore||["**/node_modules/**","**/dist/**","**/build/**","**/.git/**"],c=e.debounce||r.debounce||2e3,p=e.url||r.url||o.defaultUrl,m=e.description||r.description||"Auto-test from watch mode",h=e.template||r.template;p||(console.log(`
70
+ `),process.exit(1));let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=o.watch||{},u=t.length>0?t:r.patterns||["src/**/*"],s=e.ignore||r.ignore||["**/node_modules/**","**/dist/**","**/build/**","**/.git/**"],c=e.debounce||r.debounce||2e3,p=e.url||r.url||o.defaultUrl,m=e.description||r.description||"Auto-test from watch mode",h=e.template||r.template;p||(console.log(`
71
71
  \u274C Error: URL required
72
72
  `),console.log(`Provide via --url flag or set in .runhumanrc:
73
73
  `),console.log(' runhuman watch --url "https://myapp.com"'),console.log(` OR add to .runhumanrc: { "watch": { "url": "..." } }
@@ -76,36 +76,36 @@ ${ye}
76
76
  `),console.log(`Run: runhuman projects switch <project-id>
77
77
  `),process.exit(1));let b=new l({color:o.color});console.log(`
78
78
  \u{1F440} Starting watch mode
79
- `),console.log(` Watching: ${u.join(", ")}`),console.log(` Ignoring: ${i.join(", ")}`),console.log(` Debounce: ${c}ms`),console.log(` URL: ${p}`),h&&console.log(` Template: ${h}`),console.log(`
79
+ `),console.log(` Watching: ${u.join(", ")}`),console.log(` Ignoring: ${s.join(", ")}`),console.log(` Debounce: ${c}ms`),console.log(` URL: ${p}`),h&&console.log(` Template: ${h}`),console.log(`
80
80
  Press Ctrl+C to stop
81
- `),bo(process.pid);let w=new f(o),j=null,x=new Set,U=mo.watch(u,{ignored:i,persistent:!0,ignoreInitial:!0});U.on("change",F=>{x.add(F),console.log(` \u{1F4DD} Changed: ${F}`),j&&clearTimeout(j),j=setTimeout(async()=>{let le=Array.from(x);x.clear(),console.log(`
82
- \u{1F680} Creating test job for ${le.length} file(s)...
83
- `);try{let ne={projectId:o.project,url:p,description:`${m}
81
+ `),Oo(process.pid);let w=new f(o),j=null,k=new Set,P=xo.watch(u,{ignored:s,persistent:!0,ignoreInitial:!0});P.on("change",F=>{k.add(F),console.log(` \u{1F4DD} Changed: ${F}`),j&&clearTimeout(j),j=setTimeout(async()=>{let pe=Array.from(k);k.clear(),console.log(`
82
+ \u{1F680} Creating test job for ${pe.length} file(s)...
83
+ `);try{let se={projectId:o.project,url:p,description:`${m}
84
84
 
85
85
  Changed files:
86
- ${le.map(Qe=>`- ${Qe}`).join(`
87
- `)}`,templateId:h},q=await w.createJob(ne);console.log(` \u2705 Job created: ${q.jobId}`),console.log(` \u{1F4CA} Dashboard: ${o.apiUrl}${D.jobSimple.build({jobId:q.jobId})}
86
+ ${pe.map(nt=>`- ${nt}`).join(`
87
+ `)}`,templateId:h},H=await w.createJob(se);console.log(` \u2705 Job created: ${H.jobId}`),console.log(` \u{1F4CA} Dashboard: ${o.apiUrl}${N.jobSimple.build({jobId:H.jobId})}
88
88
  `),console.log(` Watching for more changes...
89
- `)}catch(ne){let q=d(ne);b.outputError(q.message,q.details),console.log(`
89
+ `)}catch(se){let H=d(se);b.outputError(H.message,H.details),console.log(`
90
90
  Watching for more changes...
91
- `)}},c)}),U.on("error",F=>{console.error(`
91
+ `)}},c)}),P.on("error",F=>{console.error(`
92
92
  \u274C Watch error: ${F instanceof Error?F.message:String(F)}
93
- `)});let H=()=>{console.log(`
93
+ `)});let V=()=>{console.log(`
94
94
 
95
95
  \u{1F44B} Stopping watch mode...
96
- `),U.close(),V(),process.exit(0)};process.on("SIGINT",H),process.on("SIGTERM",H)}catch(n){let o=d(n);new l({}).outputError(o.message,o.details),V(),process.exit(o.exitCode)}}),s}function bo(s){let t=Ue(Te(),".config","runhuman");te(t)||go(t,{recursive:!0}),fo(M,s.toString())}function V(){te(M)&&ho(M)}function Re(){if(!te(M))return!1;try{let s=parseInt(ce(M,"utf-8"));return process.kill(s,0),!0}catch{return V(),!1}}async function yo(){if(!te(M)){console.log(`
96
+ `),P.close(),W(),process.exit(0)};process.on("SIGINT",V),process.on("SIGTERM",V)}catch(n){let o=d(n);new l({}).outputError(o.message,o.details),W(),process.exit(o.exitCode)}}),i}function Oo(i){let t=Ue(De(),".config","runhuman");ne(t)||vo(t,{recursive:!0}),Uo($,i.toString())}function W(){ne($)&&Do($)}function Re(){if(!ne($))return!1;try{let i=parseInt(ue($,"utf-8"));return process.kill(i,0),!0}catch{return W(),!1}}async function Ro(){if(!ne($)){console.log(`
97
97
  \u2139\uFE0F Watch mode is not running
98
- `);return}try{let s=parseInt(ce(M,"utf-8"));process.kill(s,"SIGTERM"),V(),console.log(`
98
+ `);return}try{let i=parseInt(ue($,"utf-8"));process.kill(i,"SIGTERM"),W(),console.log(`
99
99
  \u2705 Watch mode stopped
100
- `)}catch{V(),console.log(`
100
+ `)}catch{W(),console.log(`
101
101
  \u2139\uFE0F Watch process not found (already stopped)
102
- `)}}function wo(){if(Re()){let s=parseInt(ce(M,"utf-8"));console.log(`
103
- \u2705 Watch mode is running`),console.log(` \u{1F4DD} PID: ${s}`),console.log(`
102
+ `)}}function No(){if(Re()){let i=parseInt(ue($,"utf-8"));console.log(`
103
+ \u2705 Watch mode is running`),console.log(` \u{1F4DD} PID: ${i}`),console.log(`
104
104
  Stop with: runhuman watch --stop
105
105
  `)}else console.log(`
106
106
  \u2139\uFE0F Watch mode is not running
107
- `)}k();A();C();I();import{Command as Ao}from"commander";import jo from"http";import{URL as Co}from"url";import Io from"open";async function oe(s){let{apiUrl:t,autoOpenBrowser:e=!0}=s;return new Promise((n,o)=>{let r=jo.createServer((i,c)=>{if(!i.url){c.writeHead(400),c.end("Bad request");return}let p=new Co(i.url,"http://localhost");if(p.pathname==="/callback"){let m=p.searchParams.get("token"),h=p.searchParams.get("email"),b=p.searchParams.get("projectId")||"",w=p.searchParams.get("error");if(w){c.writeHead(200,{"Content-Type":"text/html"}),c.end(ve(w)),r.close(),o(new Error(w));return}if(m&&h){c.writeHead(200,{"Content-Type":"text/html"}),c.end(So(h)),r.close(),n({token:m,email:h,projectId:b});return}c.writeHead(400,{"Content-Type":"text/html"}),c.end(ve("Missing token or email in callback")),r.close(),o(new Error("Missing token or email in callback"));return}c.writeHead(404),c.end("Not found")});r.listen(0,"127.0.0.1",async()=>{let i=r.address();if(!i||typeof i=="string"){o(new Error("Failed to start local server"));return}let p=`http://127.0.0.1:${i.port}/callback`,m=`${t}/cli/auth?callback=${encodeURIComponent(p)}`;if(console.log(""),e){console.log("Opening browser for authentication...");try{await Io(m)}catch{console.log("Could not open browser automatically."),console.log(`
108
- Please visit: ${m}`)}}else console.log(`Please visit: ${m}`);console.log(""),console.log("Waiting for authentication...")});let u=setTimeout(()=>{r.close(),o(new Error("Authentication timed out. Please try again."))},60*1e3);r.on("close",()=>clearTimeout(u)),r.on("error",i=>{clearTimeout(u),o(new Error(`Failed to start local server: ${i.message}`))})})}function So(s){return`<!DOCTYPE html>
107
+ `)}T();A();C();I();import{Command as _o}from"commander";import Mo from"http";import{URL as Lo}from"url";import $o from"open";async function re(i){let{apiUrl:t,autoOpenBrowser:e=!0}=i;return new Promise((n,o)=>{let r=Mo.createServer((s,c)=>{if(!s.url){c.writeHead(400),c.end("Bad request");return}let p=new Lo(s.url,"http://localhost");if(p.pathname==="/callback"){let m=p.searchParams.get("token"),h=p.searchParams.get("email"),b=p.searchParams.get("projectId")||"",w=p.searchParams.get("error");if(w){c.writeHead(200,{"Content-Type":"text/html"}),c.end(Ne(w)),r.close(),o(new Error(w));return}if(m&&h){c.writeHead(200,{"Content-Type":"text/html"}),c.end(zo(h)),r.close(),n({token:m,email:h,projectId:b});return}c.writeHead(400,{"Content-Type":"text/html"}),c.end(Ne("Missing token or email in callback")),r.close(),o(new Error("Missing token or email in callback"));return}c.writeHead(404),c.end("Not found")});r.listen(0,"127.0.0.1",async()=>{let s=r.address();if(!s||typeof s=="string"){o(new Error("Failed to start local server"));return}let p=`http://127.0.0.1:${s.port}/callback`,m=`${t}/cli/auth?callback=${encodeURIComponent(p)}`;if(console.log(""),e){console.log("Opening browser for authentication...");try{await $o(m)}catch{console.log("Could not open browser automatically."),console.log(`
108
+ Please visit: ${m}`)}}else console.log(`Please visit: ${m}`);console.log(""),console.log("Waiting for authentication...")});let u=setTimeout(()=>{r.close(),o(new Error("Authentication timed out. Please try again."))},60*1e3);r.on("close",()=>clearTimeout(u)),r.on("error",s=>{clearTimeout(u),o(new Error(`Failed to start local server: ${s.message}`))})})}function zo(i){return`<!DOCTYPE html>
109
109
  <html>
110
110
  <head>
111
111
  <title>Runhuman CLI - Authenticated</title>
@@ -143,11 +143,11 @@ Please visit: ${m}`)}}else console.log(`Please visit: ${m}`);console.log(""),con
143
143
  <body>
144
144
  <div class="container">
145
145
  <h1>Successfully authenticated!</h1>
146
- <p>Logged in as <span class="email">${s}</span></p>
146
+ <p>Logged in as <span class="email">${i}</span></p>
147
147
  <p class="close-note">You can close this tab and return to the terminal.</p>
148
148
  </div>
149
149
  </body>
150
- </html>`}function ve(s){return`<!DOCTYPE html>
150
+ </html>`}function Ne(i){return`<!DOCTYPE html>
151
151
  <html>
152
152
  <head>
153
153
  <title>Runhuman CLI - Authentication Failed</title>
@@ -187,115 +187,121 @@ Please visit: ${m}`)}}else console.log(`Please visit: ${m}`);console.log(""),con
187
187
  <div class="container">
188
188
  <h1>Authentication failed</h1>
189
189
  <p>Please try again from the terminal.</p>
190
- <div class="error">${s}</div>
190
+ <div class="error">${i}</div>
191
191
  </div>
192
192
  </body>
193
- </html>`}function Ee(){let s=new Ao("login");return s.description("Authenticate with Runhuman").option("--token <token>","Login with API key (skip browser)").option("--no-browser","Print auth URL instead of opening browser").option("--json","Output as JSON").action(async t=>{try{let e=new g,n=await e.loadConfig(),o=new l({json:t.json,color:n.color});if(t.token)await Po(e,o,t.token,t.json);else{let r=t.browser!==!1&&n.autoOpenBrowser!==!1;await ko(e,o,n.apiUrl,r,t.json)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),s}async function Po(s,t,e,n){s.saveCredentials({accessToken:e});let o=await s.loadConfig({apiKey:e}),u=await new f(o).getCurrentUser();s.saveUserInfo(u),n?t.output(l.result({success:!0,user:u})):(t.success("Successfully logged in!"),console.log(` User: ${u.email}`),console.log(` Account ID: ${u.accountId}
194
- `))}async function ko(s,t,e,n,o){o||console.log("Logging in to Runhuman...");let r=await oe({apiUrl:e||"https://runhuman.com",autoOpenBrowser:n});s.saveCredentials({accessToken:r.token}),await s.set("project",r.projectId,!0);let u=await s.loadConfig({apiKey:r.token}),c=await new f(u).getCurrentUser();s.saveUserInfo(c),o?t.output(l.result({success:!0,user:c,projectId:r.projectId})):(console.log(""),t.success("Successfully logged in!"),console.log(` User: ${c.email}`),console.log(` Account ID: ${c.accountId}`),console.log(` Default Project: ${r.projectId}
195
- `)),process.exit(0)}A();C();I();import{Command as xo}from"commander";function De(){let s=new xo("logout");return s.description("Log out and clear stored credentials").option("--force","Skip confirmation prompt").option("--json","Output as JSON").action(async t=>{try{let e=new g,n=new l({json:t.json});if(e.clearCredentials(),e.clearUserInfo(),t.json){let o=l.result({success:!0,message:"Logged out successfully"});n.output(o)}else n.success("Logged out successfully!"),console.log(`Credentials have been cleared.
196
- `)}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),s}k();A();C();I();import{Command as Uo}from"commander";function Ne(){let s=new Uo("whoami");return s.description("Display current user information").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=new l({json:t.json}),u=await new f(n).getCurrentUser();if(t.json){let i=l.result({user:u});o.output(i)}else console.log(`
193
+ </html>`}function Me(){let i=new _o("login");return i.description("Authenticate with Runhuman").option("--token <token>","Login with API key (skip browser)").option("--no-browser","Print auth URL instead of opening browser").option("--json","Output as JSON").action(async t=>{try{let e=new g,n=await e.loadConfig(),o=new l({json:t.json,color:n.color});if(t.token)await Jo(e,o,t.token,t.json);else{let r=t.browser!==!1&&n.autoOpenBrowser!==!1;await Fo(e,o,n.apiUrl,r,t.json)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i}async function Jo(i,t,e,n){i.saveCredentials({accessToken:e});let o=await i.loadConfig({apiKey:e}),u=await new f(o).getCurrentUser();i.saveUserInfo(u),n?t.output(l.result({success:!0,user:u})):(t.success("Successfully logged in!"),console.log(` User: ${u.email}`),console.log(` Account ID: ${u.accountId}
194
+ `))}async function Fo(i,t,e,n,o){o||console.log("Logging in to Runhuman...");let r=await re({apiUrl:e||"https://runhuman.com",autoOpenBrowser:n});i.saveCredentials({accessToken:r.token}),await i.set("project",r.projectId,!0);let u=await i.loadConfig({apiKey:r.token}),c=await new f(u).getCurrentUser();i.saveUserInfo(c),o?t.output(l.result({success:!0,user:c,projectId:r.projectId})):(console.log(""),t.success("Successfully logged in!"),console.log(` User: ${c.email}`),console.log(` Account ID: ${c.accountId}`),console.log(` Default Project: ${r.projectId}
195
+ `)),process.exit(0)}A();C();I();import{Command as Ko}from"commander";function Le(){let i=new Ko("logout");return i.description("Log out and clear stored credentials").option("--force","Skip confirmation prompt").option("--json","Output as JSON").action(async t=>{try{let e=new g,n=new l({json:t.json});if(e.clearCredentials(),e.clearUserInfo(),t.json){let o=l.result({success:!0,message:"Logged out successfully"});n.output(o)}else n.success("Logged out successfully!"),console.log(`Credentials have been cleared.
196
+ `)}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i}T();A();C();I();import{Command as qo}from"commander";function $e(){let i=new qo("whoami");return i.description("Display current user information").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=new l({json:t.json}),u=await new f(n).getCurrentUser();if(t.json){let s=l.result({user:u});o.output(s)}else console.log(`
197
197
  \u{1F464} Current User
198
198
  `),console.log(" Email: "+u.email),console.log(" Account ID: "+u.accountId),n.project&&console.log(`
199
- Default Project: `+n.project),console.log()}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),s}A();C();I();import{Command as To}from"commander";function ze(){let s=new To("config");return s.description("Manage CLI configuration"),s.command("get").description("Get a configuration value").argument("<key>","Configuration key").option("--json","Output as JSON").action(async(t,e)=>{try{let o=await new g().get(t),r=new l({json:e.json});if(e.json){let u=l.result({[t]:o});r.output(u)}else console.log(o!==void 0?o:"(not set)")}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("set").description("Set a configuration value").argument("<key>","Configuration key").argument("<value>","Configuration value").option("--global","Set globally (not project-specific)").option("--json","Output as JSON").action(async(t,e,n)=>{try{await new g().set(t,e,n.global);let r=new l({json:n.json});if(n.json){let u=l.result({success:!0,key:t,value:e,scope:n.global?"global":"project"});r.output(u)}else r.success(`Set ${t} = ${e}`+(n.global?" (global)":" (project)"))}catch(o){let r=d(o);new l({json:n.json}).outputError(r.message,r.details),process.exit(r.exitCode)}}),s.command("list").description("List all configuration values").option("--show-secrets","Show API keys (default: masked)").option("--json","Output as JSON").action(async t=>{try{let n=await new g().list(),o=new l({json:t.json});if(t.json){let r=l.result(n);o.output(r)}else{if(console.log(`
199
+ Default Project: `+n.project),console.log()}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i}A();C();I();import{Command as Vo}from"commander";function _e(){let i=new Vo("config");return i.description("Manage CLI configuration"),i.command("get").description("Get a configuration value").argument("<key>","Configuration key").option("--json","Output as JSON").action(async(t,e)=>{try{let o=await new g().get(t),r=new l({json:e.json});if(e.json){let u=l.result({[t]:o});r.output(u)}else console.log(o!==void 0?o:"(not set)")}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("set").description("Set a configuration value").argument("<key>","Configuration key").argument("<value>","Configuration value").option("--global","Set globally (not project-specific)").option("--json","Output as JSON").action(async(t,e,n)=>{try{await new g().set(t,e,n.global);let r=new l({json:n.json});if(n.json){let u=l.result({success:!0,key:t,value:e,scope:n.global?"global":"project"});r.output(u)}else r.success(`Set ${t} = ${e}`+(n.global?" (global)":" (project)"))}catch(o){let r=d(o);new l({json:n.json}).outputError(r.message,r.details),process.exit(r.exitCode)}}),i.command("list").description("List all configuration values").option("--show-secrets","Show API keys (default: masked)").option("--json","Output as JSON").action(async t=>{try{let n=await new g().list(),o=new l({json:t.json});if(t.json){let r=l.result(n);o.output(r)}else{if(console.log(`
200
200
  \u2699\uFE0F Configuration
201
- `),n.global&&Object.keys(n.global).length>0){console.log("Global (~/.config/runhuman/config.json):");for(let[r,u]of Object.entries(n.global)){let i=r==="apiKey"&&!t.showSecrets?$e(String(u)):u;console.log(` ${r}:`.padEnd(20)+i)}console.log()}if(n.project&&Object.keys(n.project).length>0){console.log("Project (.runhumanrc):");for(let[r,u]of Object.entries(n.project)){let i=r==="apiKey"&&!t.showSecrets?$e(String(u)):u;console.log(` ${r}:`.padEnd(20)+i)}console.log()}console.log("\u{1F4A1} Set value: runhuman config set <key> <value>"),console.log(` Get value: runhuman config get <key>
202
- `)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),s.command("reset").description("Reset configuration to defaults").option("--global","Reset global config").option("--project","Reset project config").option("--all","Reset all config").option("--force","Skip confirmation prompt").option("--json","Output as JSON").action(async t=>{try{if(!t.global&&!t.project&&!t.all)throw new Error("Specify --global, --project, or --all");let e=t.all?"all":t.global?"global":"project";t.force||(console.log(`\u26A0\uFE0F This will reset ${e} configuration to defaults.`),console.log(`Use --force to skip this prompt.
203
- `),process.exit(0)),await new g().reset(e);let o=new l({json:t.json});if(t.json){let r=l.result({success:!0,scope:e});o.output(r)}else o.success(`Reset ${e} configuration`)}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),s}function $e(s){return s.length<=8?"****":s.substring(0,4)+"*".repeat(s.length-8)+s.substring(s.length-4)}C();I();import{Command as Oo}from"commander";import Ro from"inquirer";import{writeFileSync as vo}from"fs";import{join as Eo}from"path";function Me(){let s=new Oo("init");return s.description("Initialize a new Runhuman project with configuration").option("--name <text>","Project name").option("--url <url>","Default URL").option("--github-repo <owner/repo>","GitHub repository").option("--yes","Skip all prompts (use defaults)").option("--json","Output as JSON").action(async t=>{try{let e=new l({json:t.json});!t.json&&!t.yes&&(console.log(`\u{1F680} Welcome to Runhuman!
201
+ `),n.global&&Object.keys(n.global).length>0){console.log("Global (~/.config/runhuman/config.json):");for(let[r,u]of Object.entries(n.global)){let s=r==="apiKey"&&!t.showSecrets?ze(String(u)):u;console.log(` ${r}:`.padEnd(20)+s)}console.log()}if(n.project&&Object.keys(n.project).length>0){console.log("Project (.runhumanrc):");for(let[r,u]of Object.entries(n.project)){let s=r==="apiKey"&&!t.showSecrets?ze(String(u)):u;console.log(` ${r}:`.padEnd(20)+s)}console.log()}console.log("\u{1F4A1} Set value: runhuman config set <key> <value>"),console.log(` Get value: runhuman config get <key>
202
+ `)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i.command("reset").description("Reset configuration to defaults").option("--global","Reset global config").option("--project","Reset project config").option("--all","Reset all config").option("--force","Skip confirmation prompt").option("--json","Output as JSON").action(async t=>{try{if(!t.global&&!t.project&&!t.all)throw new Error("Specify --global, --project, or --all");let e=t.all?"all":t.global?"global":"project";t.force||(console.log(`\u26A0\uFE0F This will reset ${e} configuration to defaults.`),console.log(`Use --force to skip this prompt.
203
+ `),process.exit(0)),await new g().reset(e);let o=new l({json:t.json});if(t.json){let r=l.result({success:!0,scope:e});o.output(r)}else o.success(`Reset ${e} configuration`)}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i}function ze(i){return i.length<=8?"****":i.substring(0,4)+"*".repeat(i.length-8)+i.substring(i.length-4)}C();I();import{Command as Ho}from"commander";import Go from"inquirer";import{writeFileSync as Wo}from"fs";import{join as Bo}from"path";function Je(){let i=new Ho("init");return i.description("Initialize a new Runhuman project with configuration").option("--name <text>","Project name").option("--url <url>","Default URL").option("--github-repo <owner/repo>","GitHub repository").option("--yes","Skip all prompts (use defaults)").option("--json","Output as JSON").action(async t=>{try{let e=new l({json:t.json});!t.json&&!t.yes&&(console.log(`\u{1F680} Welcome to Runhuman!
204
204
  `),console.log("Let's set up your project. This will create:"),console.log(" \u2022 A configuration file (.runhumanrc)"),console.log(` \u2022 Setup your project defaults
205
205
  `),console.log("=".repeat(60)+`
206
- `));let n=t.name,o=t.url,r=t.githubRepo;if(!t.yes&&!t.json){let c=await Ro.prompt([{type:"input",name:"projectName",message:"Project name:",default:"My Project",when:!n},{type:"input",name:"defaultUrl",message:"Default URL (optional):",when:!o},{type:"input",name:"githubRepo",message:"Link to GitHub repository (optional, e.g., owner/repo):",when:!r}]);n=n||c.projectName,o=o||c.defaultUrl,r=r||c.githubRepo}let u={defaultUrl:o||void 0,githubRepo:r||void 0,defaultDuration:5,defaultScreenSize:"desktop"},i=Eo(process.cwd(),".runhumanrc");if(vo(i,JSON.stringify(u,null,2)),t.json){let c=l.result({success:!0,configPath:i,config:u});e.output(c)}else console.log(`
206
+ `));let n=t.name,o=t.url,r=t.githubRepo;if(!t.yes&&!t.json){let c=await Go.prompt([{type:"input",name:"projectName",message:"Project name:",default:"My Project",when:!n},{type:"input",name:"defaultUrl",message:"Default URL (optional):",when:!o},{type:"input",name:"githubRepo",message:"Link to GitHub repository (optional, e.g., owner/repo):",when:!r}]);n=n||c.projectName,o=o||c.defaultUrl,r=r||c.githubRepo}let u={defaultUrl:o||void 0,githubRepo:r||void 0,defaultDuration:5,defaultDeviceClass:"desktop"},s=Bo(process.cwd(),".runhumanrc");if(Wo(s,JSON.stringify(u,null,2)),t.json){let c=l.result({success:!0,configPath:s,config:u});e.output(c)}else console.log(`
207
207
  `+"=".repeat(60)),e.success("Project initialized successfully!"),console.log(`\u{1F4C1} Configuration saved to: .runhumanrc
208
208
  `),console.log(`\u{1F389} All set! Try creating your first test:
209
209
  `),console.log(` runhuman create https://example.com -d "Test homepage"
210
210
  `),console.log(`\u{1F4DA} Learn more: https://runhuman.com/docs/cli
211
- `)}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),s}k();A();C();I();import{Command as Do}from"commander";import No from"inquirer";import $o from"cli-table3";function Le(){let s=new Do("projects");return s.description("Manage projects"),s.command("list").alias("ls").description("List all projects").option("--limit <number>","Number of results (default: 20)",parseInt).option("--offset <number>","Pagination offset (default: 0)",parseInt).option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=new l({json:t.json,color:n.color}),r=new f(n),u=t.limit||20,i=t.offset||0,[{items:c,pagination:p},{items:m}]=await Promise.all([r.listProjects({limit:u,offset:i}),r.listOrganizations({})]),h=new Map(m.map(b=>[b.id,b.name]));if(t.json){let b=l.result({projects:c,pagination:p});o.output(b)}else{if(p.total===0){console.log(`
211
+ `)}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i}T();A();C();I();import{Command as Yo}from"commander";import Fe from"inquirer";import Zo from"cli-table3";function Ke(){let i=new Yo("projects");return i.description("Manage projects"),i.command("list").alias("ls").description("List all projects").option("--limit <number>","Number of results (default: 20)",parseInt).option("--offset <number>","Pagination offset (default: 0)",parseInt).option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=new l({json:t.json,color:n.color}),r=new f(n),u=t.limit||20,s=t.offset||0,[{items:c,pagination:p},{items:m}]=await Promise.all([r.listProjects({limit:u,offset:s}),r.listOrganizations({})]),h=new Map(m.map(b=>[b.id,b.name]));if(t.json){let b=l.result({projects:c,pagination:p});o.output(b)}else{if(p.total===0){console.log(`
212
212
  \u{1F4C1} Your Projects (0)
213
213
  `),console.log(`No projects found.
214
214
  `),console.log(`\u{1F4A1} Create a project: runhuman projects create <name> --organization <org-id>
215
215
  `);return}console.log(`
216
216
  \u{1F4C1} Your Projects (${c.length} of ${p.total})
217
- `);let b=new $o({head:["Name","Organization","Project ID","Created"].map(x=>x),colWidths:[25,25,25,15]});c.forEach(x=>{let U=h.get(x.organizationId)||"(unknown)";b.push([x.name,U,x.id,new Date(x.createdAt).toLocaleDateString()])}),console.log(b.toString());let w=i+1,j=i+c.length;console.log(`
217
+ `);let b=new Zo({head:["Name","Organization","Project ID","Created"].map(k=>k),colWidths:[25,25,25,15]});c.forEach(k=>{let P=h.get(k.organizationId)||"(unknown)";b.push([k.name,P,k.id,new Date(k.createdAt).toLocaleDateString()])}),console.log(b.toString());let w=s+1,j=s+c.length;console.log(`
218
218
  Showing ${w}-${j} of ${p.total} projects`),console.log(`
219
- \u{1F4A1} View project: runhuman projects show <id>`),console.log("\u{1F4A1} Filter by org: runhuman orgs projects <org-id>"),p.hasMore&&console.log(`\u{1F4A1} Next page: runhuman projects list --offset ${i+u}`),console.log()}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),s.command("create").alias("new").description("Create a new project in an organization").argument("<name>","Project name").option("--organization <id>","Organization ID (required)").option("--default-url <url>","Default URL for tests").option("--github-repo <owner/repo>","Link to GitHub repository").option("--set-default","Set as default project").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let n=new g,o=await n.loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u=e.organization;if(!u)throw new Error("Organization ID required (use --organization)");let c=await new f(o).createProject({name:t,organizationId:u,defaultUrl:e.defaultUrl,githubRepo:e.githubRepo});if(e.setDefault&&await n.set("project",c.id,!1),e.json){let p=l.result(c);r.output(p)}else r.success("Project created successfully!"),console.log(" Project ID: "+c.id),console.log(" Name: "+c.name),e.setDefault&&console.log(" Set as default project"),console.log()}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("show").alias("info").alias("get").description("Show detailed project information").argument("<projectId>","Project ID to show").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u=new f(o),i=await u.getProject(t),[c,p]=await Promise.all([u.getOrganization(i.organizationId),u.getOrganizationBilling(i.organizationId)]);if(e.json){let m=l.result({project:i,organization:c,balance:{balance:p.balance,balanceUsd:p.balanceUsd}});r.output(m)}else console.log(`
219
+ \u{1F4A1} View project: runhuman projects show <id>`),console.log("\u{1F4A1} Filter by org: runhuman orgs projects <org-id>"),p.hasMore&&console.log(`\u{1F4A1} Next page: runhuman projects list --offset ${s+u}`),console.log()}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i.command("create").alias("new").description("Create a new project in an organization").argument("<name>","Project name").option("--organization <id>","Organization ID (required)").option("--default-url <url>","Default URL for tests").option("--github-repo <owner/repo>","Link to GitHub repository").option("--set-default","Set as default project").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let n=new g,o=await n.loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u=e.organization;if(!u)throw new Error("Organization ID required (use --organization)");let c=await new f(o).createProject({name:t,organizationId:u,defaultUrl:e.defaultUrl,githubRepo:e.githubRepo});if(e.setDefault&&await n.set("project",c.id,!1),e.json){let p=l.result(c);r.output(p)}else r.success("Project created successfully!"),console.log(" Project ID: "+c.id),console.log(" Name: "+c.name),e.setDefault&&console.log(" Set as default project"),console.log()}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("show").alias("info").alias("get").description("Show detailed project information").argument("<projectId>","Project ID to show").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u=new f(o),s=await u.getProject(t),[c,p]=await Promise.all([u.getOrganization(s.organizationId),u.getOrganizationBilling(s.organizationId)]);if(e.json){let m=l.result({project:s,organization:c,balance:{balance:p.balance,balanceUsd:p.balanceUsd}});r.output(m)}else console.log(`
220
220
  \u{1F4C1} Project Details
221
- `),console.log(" Project ID: "+i.id),console.log(" Name: "+i.name),console.log(" Organization: "+c.name+" ("+c.id+")"),console.log(" Org Balance: "+p.balanceUsd),i.defaultUrl&&console.log(" Default URL: "+i.defaultUrl),i.githubRepo&&console.log(" GitHub Repo: "+i.githubRepo),console.log(" Created: "+new Date(i.createdAt).toLocaleString()),console.log(" Last Updated: "+new Date(i.updatedAt).toLocaleString()),console.log(),console.log("\u{1F4A1} View organization: runhuman orgs show "+c.id),console.log("\u{1F4A1} List org projects: runhuman orgs projects "+c.id),console.log("\u{1F4A1} Check org balance: runhuman orgs balance "+c.id),console.log()}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("switch").alias("use").description("Set default project for CLI commands").argument("<projectId>","Project ID to use as default").option("--global","Set as global default instead of local").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let n=new g,o=await n.loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),i=await new f(o).getProject(t);if(await n.set("project",t,e.global!==!1),e.json){let c=l.result({success:!0,projectId:t,projectName:i.name,scope:e.global!==!1?"global":"local"});r.output(c)}else r.success(`Default project set to: ${i.name} (${t})`),e.global!==!1?console.log(" Scope: global (all directories)"):console.log(" Scope: local (current directory only)"),console.log()}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("update").description("Update project settings").argument("<projectId>","Project ID to update").option("--name <text>","Update name").option("--default-url <url>","Update default URL").option("--github-repo <owner/repo>","Update GitHub repo").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u={name:e.name,defaultUrl:e.defaultUrl,githubRepo:e.githubRepo},c=await new f(o).updateProject(t,u);if(e.json){let p=l.result(c);r.output(p)}else r.success("Project updated successfully!")}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("delete").alias("rm").description("Delete a project permanently").argument("<projectId>","Project ID to delete").option("--force","Skip confirmation prompt").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{if(!e.json&&!e.force){let{confirmed:i}=await No.prompt([{type:"confirm",name:"confirmed",message:`Permanently delete project ${t} and all its data? This cannot be undone.`,default:!1}]);if(!i)return}let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color});if(await new f(o).deleteProject(t),e.json){let i=l.result({success:!0});r.output(i)}else r.success("Project deleted successfully!")}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s}k();A();C();I();import{Command as zo}from"commander";import Je from"cli-table3";function _e(){let s=new zo("orgs");return s.alias("organizations"),s.description("Manage organizations"),s.command("list").alias("ls").description("List all organizations you belong to").option("--limit <number>","Number of results (default: 20)",parseInt).option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=new l({json:t.json,color:n.color}),r=new f(n),{items:u,total:i}=await r.listOrganizations({limit:t.limit||20});if(t.json){let c=l.result({organizations:u,pagination:{total:i,limit:t.limit||20,offset:0,hasMore:u.length<i}});o.output(c)}else{console.log(`
222
- \u{1F3E2} Your Organizations (${u.length} of ${i})
223
- `);let c=new Je({head:["Organization ID","Name","Projects","Created"].map(p=>p),colWidths:[25,30,12,15]});u.forEach(p=>{c.push([p.id,p.name,p.projectCount?.toString()||"0",new Date(p.createdAt).toLocaleDateString()])}),console.log(c.toString()),console.log(`
221
+ `),console.log(" Project ID: "+s.id),console.log(" Name: "+s.name),console.log(" Organization: "+c.name+" ("+c.id+")"),console.log(" Org Balance: $"+p.balanceUsd.toFixed(2)),s.defaultUrl&&console.log(" Default URL: "+s.defaultUrl),s.githubRepo&&console.log(" GitHub Repo: "+s.githubRepo),console.log(" Created: "+new Date(s.createdAt).toLocaleString()),console.log(" Last Updated: "+new Date(s.updatedAt).toLocaleString()),console.log(),console.log("\u{1F4A1} View organization: runhuman orgs show "+c.id),console.log("\u{1F4A1} List org projects: runhuman orgs projects "+c.id),console.log("\u{1F4A1} Check org balance: runhuman orgs balance "+c.id),console.log()}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("switch").alias("use").description("Set default project for CLI commands").argument("<projectId>","Project ID to use as default").option("--global","Set as global default instead of local").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let n=new g,o=await n.loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),s=await new f(o).getProject(t);if(await n.set("project",t,e.global!==!1),e.json){let c=l.result({success:!0,projectId:t,projectName:s.name,scope:e.global!==!1?"global":"local"});r.output(c)}else r.success(`Default project set to: ${s.name} (${t})`),e.global!==!1?console.log(" Scope: global (all directories)"):console.log(" Scope: local (current directory only)"),console.log()}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("update").description("Update project settings").argument("<projectId>","Project ID to update").option("--name <text>","Update name").option("--default-url <url>","Update default URL").option("--github-repo <owner/repo>","Update GitHub repo").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u={name:e.name,defaultUrl:e.defaultUrl,githubRepo:e.githubRepo},c=await new f(o).updateProject(t,u);if(e.json){let p=l.result(c);r.output(p)}else r.success("Project updated successfully!")}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("transfer").description("Transfer a project to another organization").argument("<projectId>","Project ID to transfer").requiredOption("--to-org <organizationId>","Target organization ID").option("-f, --force","Skip confirmation prompt").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{if(!e.json&&!e.force){let{confirmed:c}=await Fe.prompt([{type:"confirm",name:"confirmed",message:`Transfer project ${t} to organization ${e.toOrg}? This may happen immediately if you are an admin of the target organization.`,default:!1}]);if(!c)return}let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),s=await new f(o).initiateTransfer(t,e.toOrg);e.json?r.output(l.result(s)):(r.success("Transfer initiated!"),console.log(" Transfer ID: "+s.id),console.log(" Status: "+s.status),console.log(`
222
+ \u{1F4A1} Check status: runhuman transfers list`),console.log("\u{1F4A1} Cancel: runhuman transfers cancel "+s.id),console.log())}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("delete").alias("rm").description("Delete a project permanently").argument("<projectId>","Project ID to delete").option("--force","Skip confirmation prompt").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{if(!e.json&&!e.force){let{confirmed:s}=await Fe.prompt([{type:"confirm",name:"confirmed",message:`Permanently delete project ${t} and all its data? This cannot be undone.`,default:!1}]);if(!s)return}let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color});if(await new f(o).deleteProject(t),e.json){let s=l.result({success:!0});r.output(s)}else r.success("Project deleted successfully!")}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i}T();A();C();I();import{Command as Qo}from"commander";import qe from"cli-table3";function Ve(){let i=new Qo("orgs");return i.alias("organizations"),i.description("Manage organizations"),i.command("list").alias("ls").description("List all organizations you belong to").option("--limit <number>","Number of results (default: 20)",parseInt).option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=new l({json:t.json,color:n.color}),r=new f(n),{items:u,total:s}=await r.listOrganizations({limit:t.limit||20});if(t.json){let c=l.result({organizations:u,pagination:{total:s,limit:t.limit||20,offset:0,hasMore:u.length<s}});o.output(c)}else{console.log(`
223
+ \u{1F3E2} Your Organizations (${u.length} of ${s})
224
+ `);let c=new qe({head:["Organization ID","Name","Projects","Created"].map(p=>p),colWidths:[25,30,12,15]});u.forEach(p=>{c.push([p.id,p.name,p.projectCount?.toString()||"0",new Date(p.createdAt).toLocaleDateString()])}),console.log(c.toString()),console.log(`
224
225
  \u{1F4A1} View org details: runhuman orgs show <id>`),console.log(`\u{1F4A1} Check org balance: runhuman orgs balance <id>
225
- `)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),s.command("show").alias("info").alias("get").description("Show detailed organization information").argument("<organizationId>","Organization ID to show").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),i=await new f(o).getOrganization(t);if(e.json){let c=l.result(i);r.output(c)}else console.log(`
226
+ `)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i.command("show").alias("info").alias("get").description("Show detailed organization information").argument("<organizationId>","Organization ID to show").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),s=await new f(o).getOrganization(t);if(e.json){let c=l.result(s);r.output(c)}else console.log(`
226
227
  \u{1F3E2} Organization Details
227
- `),console.log(" Organization ID: "+i.id),console.log(" Name: "+i.name),console.log(" Created: "+new Date(i.createdAt).toLocaleString()),console.log(),console.log("\u{1F4A1} List projects: runhuman orgs projects "+i.id),console.log("\u{1F4A1} Check balance: runhuman orgs balance "+i.id),console.log()}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("balance").description("Show organization billing balance").argument("<organizationId>","Organization ID").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u=new f(o),[i,c]=await Promise.all([u.getOrganization(t),u.getOrganizationBilling(t)]);if(e.json){let p=l.result({balance:c});r.output(p)}else console.log(`
228
- \u{1F4B0} Organization Balance: ${i.name}
229
- `),console.log(" Current Balance: "+c.balanceUsd),console.log(" Billing Active: "+(c.hasBilling?"Yes":"No")),console.log(),console.log(" Estimated Tests: ~"+Math.floor(c.balance)+" tests at $1.00 per test"),console.log(),c.hasBilling?console.log("\u{1F4A1} Manage billing: https://runhuman.com/dashboard/organizations/"+t+"/billing"):console.log("\u{1F4A1} Set up billing: https://runhuman.com/dashboard/organizations/"+t+"/billing"),console.log()}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("projects").description("List all projects in an organization").argument("<organizationId>","Organization ID").option("--limit <number>","Number of results (default: 50)",parseInt).option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u=new f(o),[i,{items:c,total:p}]=await Promise.all([u.getOrganization(t),u.listOrganizationProjects(t,{limit:e.limit||50})]);if(e.json){let m=l.result({organizationId:t,projects:c,total:p});r.output(m)}else{if(p===0){console.log(`
230
- \u{1F4C1} Projects in ${i.name} (0 projects)
228
+ `),console.log(" Organization ID: "+s.id),console.log(" Name: "+s.name),console.log(" Created: "+new Date(s.createdAt).toLocaleString()),console.log(),console.log("\u{1F4A1} List projects: runhuman orgs projects "+s.id),console.log("\u{1F4A1} Check balance: runhuman orgs balance "+s.id),console.log()}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("balance").description("Show organization billing balance").argument("<organizationId>","Organization ID").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u=new f(o),[s,c]=await Promise.all([u.getOrganization(t),u.getOrganizationBilling(t)]);if(e.json){let p=l.result({balance:c});r.output(p)}else console.log(`
229
+ \u{1F4B0} Organization Balance: ${s.name}
230
+ `),console.log(" Current Balance: $"+c.balanceUsd.toFixed(2)),console.log(" Billing Active: "+(c.hasBilling?"Yes":"No")),console.log(),console.log(" Estimated Tests: ~"+Math.floor(c.balance)+" tests at $1.00 per test"),console.log(),c.hasBilling?console.log("\u{1F4A1} Manage billing: https://runhuman.com/dashboard/organizations/"+t+"/billing"):console.log("\u{1F4A1} Set up billing: https://runhuman.com/dashboard/organizations/"+t+"/billing"),console.log()}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("projects").description("List all projects in an organization").argument("<organizationId>","Organization ID").option("--limit <number>","Number of results (default: 50)",parseInt).option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u=new f(o),[s,{items:c,total:p}]=await Promise.all([u.getOrganization(t),u.listOrganizationProjects(t,{limit:e.limit||50})]);if(e.json){let m=l.result({organizationId:t,projects:c,total:p});r.output(m)}else{if(p===0){console.log(`
231
+ \u{1F4C1} Projects in ${s.name} (0 projects)
231
232
  `),console.log(`No projects found in this organization.
232
233
  `),console.log("\u{1F4A1} Create a project: runhuman projects create <name> --organization "+t),console.log("\u{1F4A1} View organization: runhuman orgs show "+t),console.log();return}console.log(`
233
- \u{1F4C1} Projects in ${i.name} (${c.length} of ${p})
234
- `);let m=new Je({head:["Name","Project ID","Default URL","Created"].map(h=>h),colWidths:[25,25,30,15]});c.forEach(h=>{let b=h.defaultUrl?h.defaultUrl.length>27?h.defaultUrl.substring(0,24)+"...":h.defaultUrl:"-";m.push([h.name,h.id,b,new Date(h.createdAt).toLocaleDateString()])}),console.log(m.toString()),console.log(`
235
- \u{1F4A1} View project details: runhuman projects show <project-id>`),console.log("\u{1F4A1} Create new project: runhuman projects create <name> --organization "+t),console.log("\u{1F4A1} View organization: runhuman orgs show "+t),console.log()}}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s}k();A();C();I();import{Command as Mo}from"commander";import Lo from"inquirer";import Jo from"cli-table3";function Ke(){let s=new Mo("keys");return s.description("Manage API keys"),s.command("list").alias("ls").description("List all API keys for an organization").option("--organization <id>","Organization ID (required)").option("--show-keys","Show full API keys (default: masked)").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=t.organization;if(!o)throw new Error("Organization ID required (use --organization)");let r=new l({json:t.json,color:n.color}),u=new f(n),{items:i,total:c}=await u.listApiKeys(o);if(t.json){let p=l.result({keys:i,total:c});r.output(p)}else{if(c===0){console.log(`
234
+ \u{1F4C1} Projects in ${s.name} (${c.length} of ${p})
235
+ `);let m=new qe({head:["Name","Project ID","Default URL","Created"].map(h=>h),colWidths:[25,25,30,15]});c.forEach(h=>{let b=h.defaultUrl?h.defaultUrl.length>27?h.defaultUrl.substring(0,24)+"...":h.defaultUrl:"-";m.push([h.name,h.id,b,new Date(h.createdAt).toLocaleDateString()])}),console.log(m.toString()),console.log(`
236
+ \u{1F4A1} View project details: runhuman projects show <project-id>`),console.log("\u{1F4A1} Create new project: runhuman projects create <name> --organization "+t),console.log("\u{1F4A1} View organization: runhuman orgs show "+t),console.log()}}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i}T();A();C();I();import{Command as Xo}from"commander";import en from"inquirer";import tn from"cli-table3";function Ge(){let i=new Xo("keys");return i.description("Manage API keys"),i.command("list").alias("ls").description("List all API keys for an organization").option("--organization <id>","Organization ID (required)").option("--show-keys","Show full API keys (default: masked)").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=t.organization;if(!o)throw new Error("Organization ID required (use --organization)");let r=new l({json:t.json,color:n.color}),u=new f(n),{items:s,total:c}=await u.listApiKeys(o);if(t.json){let p=l.result({keys:s,total:c});r.output(p)}else{if(c===0){console.log(`
236
237
  \u{1F511} API Keys (0)
237
238
  `),console.log(`No API keys found for this organization.
238
239
  `),console.log('\u{1F4A1} Create a key: runhuman keys create "Key Name" --organization '+o+`
239
240
  `);return}console.log(`
240
- \u{1F511} API Keys (${i.length} of ${c})
241
- `);let p=new Jo({head:["Key ID","Name","Key","Last Used","Created"].map(m=>m),colWidths:[20,25,20,20,20]});i.forEach(m=>{let h=t.showKeys?m.key:Fe(m.key),b=m.lastUsedAt?new Date(m.lastUsedAt).toLocaleDateString():"Never";p.push([m.id,m.name,h,b,new Date(m.createdAt).toLocaleDateString()])}),console.log(p.toString()),console.log(`
241
+ \u{1F511} API Keys (${s.length} of ${c})
242
+ `);let p=new tn({head:["Key ID","Name","Key","Last Used","Created"].map(m=>m),colWidths:[20,25,20,20,20]});s.forEach(m=>{let h=t.showKeys?m.key:He(m.key),b=m.lastUsedAt?new Date(m.lastUsedAt).toLocaleDateString():"Never";p.push([m.id,m.name,h,b,new Date(m.createdAt).toLocaleDateString()])}),console.log(p.toString()),console.log(`
242
243
  \u{1F4A1} Create new key: runhuman keys create "Key Name" --organization `+o),console.log(` Show full key: runhuman keys show <keyId>
243
- `)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),s.command("create").alias("new").description("Create a new API key for an organization").argument("<name>","API key name").option("--organization <id>","Organization ID (required)").option("--copy","Copy key to clipboard").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.organization;if(!r)throw new Error("Organization ID required (use --organization)");let u=new l({json:e.json,color:o.color}),c=await new f(o).createApiKey(r,t);if(e.json){let p=l.result(c);u.output(p)}else u.success("API Key created successfully!"),console.log(`
244
+ `)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i.command("create").alias("new").description("Create a new API key for an organization").argument("<name>","API key name").option("--organization <id>","Organization ID (required)").option("--copy","Copy key to clipboard").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.organization;if(!r)throw new Error("Organization ID required (use --organization)");let u=new l({json:e.json,color:o.color}),c=await new f(o).createApiKey(r,t);if(e.json){let p=l.result(c);u.output(p)}else u.success("API Key created successfully!"),console.log(`
244
245
  Key ID: `+c.id),console.log(" Name: "+c.name),console.log(`
245
246
  API Key: `+c.key),console.log(" "+"^".repeat(c.key.length)),console.log(` \u26A0\uFE0F Save this key! It won't be shown again.
246
247
  `),console.log("\u{1F4A1} Use this key:"),console.log(" export RUNHUMAN_API_KEY="+c.key),console.log(` runhuman create https://myapp.com -d "Test"
247
248
  `),console.log("\u{1F512} Store securely:"),console.log(" - Use environment variables (recommended)"),console.log(" - Use secret management tools"),console.log(` - Never commit to git!
248
- `)}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("show").alias("info").alias("get").description("Show details of a specific API key").argument("<keyId>","Key ID to show").option("--show-key","Show full API key (default: masked)").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),i=await new f(o).getApiKey(t);if(e.json){let c=l.result(i);r.output(c)}else console.log(`
249
+ `)}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("show").alias("info").alias("get").description("Show details of a specific API key").argument("<keyId>","Key ID to show").option("--show-key","Show full API key (default: masked)").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),s=await new f(o).getApiKey(t);if(e.json){let c=l.result(s);r.output(c)}else console.log(`
249
250
  \u{1F511} API Key Details
250
- `),console.log(" Key ID: "+i.id),console.log(" Name: "+i.name),console.log(" Key: "+(e.showKey?i.key:Fe(i.key))),console.log(" Created: "+new Date(i.createdAt).toLocaleString()),i.lastUsedAt&&console.log(" Last Used: "+new Date(i.lastUsedAt).toLocaleString()),console.log()}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("delete").aliases(["rm","revoke"]).description("Delete an API key permanently").argument("<keyId>","Key ID to delete").option("--force","Skip confirmation prompt").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{if(!e.json&&!e.force){let{confirmed:i}=await Lo.prompt([{type:"confirm",name:"confirmed",message:`Permanently delete API key ${t}? This cannot be undone.`,default:!1}]);if(!i)return}let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color});if(await new f(o).deleteApiKey(t),e.json){let i=l.result({success:!0});r.output(i)}else r.success("API key deleted successfully!")}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s}function Fe(s){return s.length<=12?"****":s.substring(0,8)+"*".repeat(s.length-12)+s.substring(s.length-4)}k();A();C();I();import{Command as _o}from"commander";import Fo from"inquirer";import Ko from"cli-table3";function Ge(){let s=new _o("templates");return s.description("Manage test templates"),s.command("list").alias("ls").description("List all test templates").option("--project <id>","Filter by project (required)").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=t.project||n.project;if(!o)throw new Error("Project ID required (use --project or set default project)");let r=new l({json:t.json,color:n.color}),u=new f(n),{items:i,pagination:c}=await u.listTemplates(o);if(t.json){let p=l.result({templates:i,pagination:c});r.output(p)}else{if(c.total===0){console.log(`
251
+ `),console.log(" Key ID: "+s.id),console.log(" Name: "+s.name),console.log(" Key: "+(e.showKey?s.key:He(s.key))),console.log(" Created: "+new Date(s.createdAt).toLocaleString()),s.lastUsedAt&&console.log(" Last Used: "+new Date(s.lastUsedAt).toLocaleString()),console.log()}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("delete").aliases(["rm","revoke"]).description("Delete an API key permanently").argument("<keyId>","Key ID to delete").option("--force","Skip confirmation prompt").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{if(!e.json&&!e.force){let{confirmed:s}=await en.prompt([{type:"confirm",name:"confirmed",message:`Permanently delete API key ${t}? This cannot be undone.`,default:!1}]);if(!s)return}let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color});if(await new f(o).deleteApiKey(t),e.json){let s=l.result({success:!0});r.output(s)}else r.success("API key deleted successfully!")}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i}function He(i){return i.length<=12?"****":i.substring(0,8)+"*".repeat(i.length-12)+i.substring(i.length-4)}T();A();C();I();import{Command as on}from"commander";import nn from"inquirer";import rn from"cli-table3";function We(){let i=new on("templates");return i.description("Manage test templates"),i.command("list").alias("ls").description("List all test templates").option("--project <id>","Filter by project (required)").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=t.project||n.project;if(!o)throw new Error("Project ID required (use --project or set default project)");let r=new l({json:t.json,color:n.color}),u=new f(n),{items:s,pagination:c}=await u.listTemplates(o);if(t.json){let p=l.result({templates:s,pagination:c});r.output(p)}else{if(c.total===0){console.log(`
251
252
  \u{1F4CB} Test Templates (0)
252
253
  `),console.log(`No templates found for this project.
253
254
  `),console.log('\u{1F4A1} Create a template: runhuman templates create "Template Name" --project '+o+`
254
255
  `);return}console.log(`
255
- \u{1F4CB} Test Templates (${i.length} of ${c.total})
256
- `);let p=new Ko({head:["ID","Name","Description","Created"].map(m=>m),colWidths:[30,25,35,20]});i.forEach(m=>{let h=m.testDescription&&m.testDescription.length>30?m.testDescription.substring(0,27)+"...":m.testDescription||"-";p.push([m.id,m.name,h,new Date(m.createdAt).toLocaleDateString()])}),console.log(p.toString()),console.log(`
256
+ \u{1F4CB} Test Templates (${s.length} of ${c.total})
257
+ `);let p=new rn({head:["ID","Name","Description","Created"].map(m=>m),colWidths:[30,25,35,20]});s.forEach(m=>{let h=m.testDescription&&m.testDescription.length>30?m.testDescription.substring(0,27)+"...":m.testDescription||"-";p.push([m.id,m.name,h,new Date(m.createdAt).toLocaleDateString()])}),console.log(p.toString()),console.log(`
257
258
  \u{1F4A1} Create new template: runhuman templates create "Template Name" --project `+o),console.log(` View template: runhuman templates show <templateId>
258
- `)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),s.command("create").alias("new").description("Create a new test template").argument("<name>","Template name").option("--project <id>","Project ID (required)").option("-d, --description <text>","Template description").option("--duration <seconds>","Target test duration in seconds").option("--screen-size <size>","Default screen size (desktop/mobile/tablet)").option("--schema <path>","Path to JSON schema file").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.project||o.project;if(!r)throw new Error("Project ID required (use --project or set default project)");let u=new l({json:e.json,color:o.color}),i;if(e.schema){let{readFileSync:h}=await import("fs"),b=h(e.schema,"utf-8");i=JSON.parse(b)}let c={name:t,testDescription:e.description,targetDurationMinutes:e.duration?parseInt(e.duration):void 0,screenSize:e.screenSize,outputSchema:i},m=await new f(o).createTemplate(r,c);if(e.json){let h=l.result(m);u.output(h)}else u.success("Template created successfully!"),console.log(`
259
+ `)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i.command("create").alias("new").description("Create a new test template").argument("<name>","Template name").option("--project <id>","Project ID (required)").option("-d, --description <text>","Template description").option("--duration <seconds>","Target test duration in seconds").option("--device-class <class>","Device class (desktop/mobile)").option("--schema <path>","Path to JSON schema file").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.project||o.project;if(!r)throw new Error("Project ID required (use --project or set default project)");let u=new l({json:e.json,color:o.color}),s;if(e.schema){let{readFileSync:h}=await import("fs"),b=h(e.schema,"utf-8");s=JSON.parse(b)}let c={name:t,testDescription:e.description,targetDurationMinutes:e.duration?Math.floor(parseInt(e.duration)/60):void 0,deviceClass:e.deviceClass,outputSchema:s},m=await new f(o).createTemplate(r,c);if(e.json){let h=l.result(m);u.output(h)}else u.success("Template created successfully!"),console.log(`
259
260
  Template ID: `+m.id),console.log(" Name: "+m.name),m.testDescription&&console.log(" Description: "+m.testDescription),console.log(`
260
261
  \u{1F4A1} Use this template:`),console.log(" runhuman create https://myapp.com --template "+m.id+`
261
- `)}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("show").alias("info").alias("get").description("Show details of a specific template").argument("<templateId>","Template ID to show").option("--project <id>","Project ID (required)").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.project||o.project;if(!r)throw new Error("Project ID required (use --project or set default project)");let u=new l({json:e.json,color:o.color}),c=await new f(o).getTemplate(r,t);if(e.json){let p=l.result(c);u.output(p)}else console.log(`
262
+ `)}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("show").alias("info").alias("get").description("Show details of a specific template").argument("<templateId>","Template ID to show").option("--project <id>","Project ID (required)").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.project||o.project;if(!r)throw new Error("Project ID required (use --project or set default project)");let u=new l({json:e.json,color:o.color}),c=await new f(o).getTemplate(r,t);if(e.json){let p=l.result(c);u.output(p)}else console.log(`
262
263
  \u{1F4CB} Template Details
263
- `),console.log("ID: "+c.id),console.log("Name: "+c.name),console.log("Description: "+(c.testDescription||"-")),console.log("Project: "+c.projectId),c.targetDurationMinutes&&console.log("Duration: "+c.targetDurationMinutes+" minutes"),c.screenSize&&console.log("Screen Size: "+c.screenSize),console.log("Created: "+new Date(c.createdAt).toLocaleString()),c.outputSchema&&(console.log(`
264
+ `),console.log("ID: "+c.id),console.log("Name: "+c.name),console.log("Description: "+(c.testDescription||"-")),console.log("Project: "+c.projectId),c.targetDurationMinutes&&console.log("Duration: "+c.targetDurationMinutes+" minutes"),c.deviceClass&&console.log("Device Class: "+c.deviceClass),console.log("Created: "+new Date(c.createdAt).toLocaleString()),c.outputSchema&&(console.log(`
264
265
  Output Schema:`),console.log(JSON.stringify(c.outputSchema,null,2))),console.log(`
265
266
  \u{1F4A1} Use this template:`),console.log(" runhuman create https://myapp.com --template "+c.id+`
266
- `)}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("update").alias("edit").description("Update a template").argument("<templateId>","Template ID to update").option("--project <id>","Project ID (required)").option("--name <name>","New template name").option("-d, --description <text>","New description").option("--duration <seconds>","New target duration in seconds").option("--screen-size <size>","New default screen size").option("--schema <path>","Path to new JSON schema file").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.project||o.project;if(!r)throw new Error("Project ID required (use --project or set default project)");let u=new l({json:e.json,color:o.color}),i;if(e.schema){let{readFileSync:b}=await import("fs"),w=b(e.schema,"utf-8");i=JSON.parse(w)}let c={name:e.name,testDescription:e.description,targetDurationMinutes:e.duration?parseInt(e.duration):void 0,screenSize:e.screenSize,outputSchema:i},p=Object.fromEntries(Object.entries(c).filter(([,b])=>b!==void 0));if(Object.keys(p).length===0)throw new Error("No updates provided. Use --name, --description, --duration, --screen-size, or --schema");let h=await new f(o).updateTemplate(r,t,c);if(e.json){let b=l.result(h);u.output(b)}else u.success("Template updated successfully!"),console.log(`
267
+ `)}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("update").alias("edit").description("Update a template").argument("<templateId>","Template ID to update").option("--project <id>","Project ID (required)").option("--name <name>","New template name").option("-d, --description <text>","New description").option("--duration <seconds>","New target duration in seconds").option("--device-class <class>","New device class (desktop/mobile)").option("--schema <path>","Path to new JSON schema file").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.project||o.project;if(!r)throw new Error("Project ID required (use --project or set default project)");let u=new l({json:e.json,color:o.color}),s;if(e.schema){let{readFileSync:b}=await import("fs"),w=b(e.schema,"utf-8");s=JSON.parse(w)}let c={name:e.name,testDescription:e.description,targetDurationMinutes:e.duration?Math.floor(parseInt(e.duration)/60):void 0,deviceClass:e.deviceClass,outputSchema:s},p=Object.fromEntries(Object.entries(c).filter(([,b])=>b!==void 0));if(Object.keys(p).length===0)throw new Error("No updates provided. Use --name, --description, --duration, --device-class, or --schema");let h=await new f(o).updateTemplate(r,t,c);if(e.json){let b=l.result(h);u.output(b)}else u.success("Template updated successfully!"),console.log(`
267
268
  Template ID: `+h.id),console.log(" Name: "+h.name+`
268
- `)}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("delete").alias("rm").description("Delete a template permanently").argument("<templateId>","Template ID to delete").option("--project <id>","Project ID (required)").option("--force","Skip confirmation prompt").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{if(!e.json&&!e.force){let{confirmed:c}=await Fo.prompt([{type:"confirm",name:"confirmed",message:`Permanently delete template ${t}? This cannot be undone.`,default:!1}]);if(!c)return}let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.project||o.project;if(!r)throw new Error("Project ID required (use --project or set default project)");let u=new l({json:e.json,color:o.color});if(await new f(o).deleteTemplate(r,t),e.json){let c=l.result({success:!0});u.output(c)}else u.success("Template deleted successfully!")}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s}k();A();C();I();import{Command as Go}from"commander";import He from"cli-table3";function qe(){let s=new Go("github");return s.alias("gh"),s.description("GitHub integration commands"),s.command("link").description("Link a GitHub repository to your project").argument("<repo>","Repository in format owner/repo").option("--project <id>","Project ID (required)").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let n=new g,o=await n.loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.project||o.project;if(!r)throw new Error("Project ID required (use --project or set default project)");let u=new l({json:e.json,color:o.color});if(!t.match(/^([^/]+)\/([^/]+)$/))throw new Error("Invalid repository format. Use: owner/repo");if(await new f(o).updateProject(r,{githubRepo:t}),e.json){let p=l.result({success:!0,repository:t});u.output(p)}else u.success("GitHub repository linked successfully!"),console.log(`
269
+ `)}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("delete").alias("rm").description("Delete a template permanently").argument("<templateId>","Template ID to delete").option("--project <id>","Project ID (required)").option("--force","Skip confirmation prompt").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{if(!e.json&&!e.force){let{confirmed:c}=await nn.prompt([{type:"confirm",name:"confirmed",message:`Permanently delete template ${t}? This cannot be undone.`,default:!1}]);if(!c)return}let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.project||o.project;if(!r)throw new Error("Project ID required (use --project or set default project)");let u=new l({json:e.json,color:o.color});if(await new f(o).deleteTemplate(r,t),e.json){let c=l.result({success:!0});u.output(c)}else u.success("Template deleted successfully!")}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i}T();A();C();I();import{Command as sn}from"commander";import Be from"cli-table3";function Ye(){let i=new sn("github");return i.alias("gh"),i.description("GitHub integration commands"),i.command("link").description("Link a GitHub repository to your project").argument("<repo>","Repository in format owner/repo").option("--project <id>","Project ID (required)").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let n=new g,o=await n.loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.project||o.project;if(!r)throw new Error("Project ID required (use --project or set default project)");let u=new l({json:e.json,color:o.color});if(!t.match(/^([^/]+)\/([^/]+)$/))throw new Error("Invalid repository format. Use: owner/repo");if(await new f(o).updateProject(r,{githubRepo:t}),e.json){let p=l.result({success:!0,repository:t});u.output(p)}else u.success("GitHub repository linked successfully!"),console.log(`
269
270
  Repository: `+t),console.log(" Project: "+r),console.log(`
270
271
  \u{1F4A1} Now you can:`),console.log(" - List issues: runhuman github issues "+t),console.log(" - Test an issue: runhuman github test <issueNumber> --repo "+t),console.log(" - Bulk test: runhuman github bulk-test --repo "+t+`
271
272
  `),await n.saveProjectConfig({githubRepo:t}),console.log(`\u2713 Repository saved to project config (.runhumanrc)
272
- `)}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("repos").alias("repositories").description("List GitHub repositories accessible to an organization").option("--organization <id>","Organization ID (required)").option("--search <query>","Filter by repository name").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=t.organization;if(!o)throw new Error("Organization ID required (use --organization)");let r=new l({json:t.json,color:n.color}),i=await new f(n).listGithubRepos(o,{search:t.search});if(t.json)r.output(l.result(i));else{console.log(`
273
- \u{1F517} GitHub Repositories (${i.items.length})
274
- `);let c=new He({head:["Repository","Added"].map(p=>p),colWidths:[45,20]});i.items.forEach(p=>{c.push([p.fullName,new Date(p.createdAt).toLocaleDateString()])}),console.log(c.toString()),console.log(`
273
+ `)}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("repos").alias("repositories").description("List GitHub repositories accessible to an organization").option("--organization <id>","Organization ID (required)").option("--search <query>","Filter by repository name").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=t.organization;if(!o)throw new Error("Organization ID required (use --organization)");let r=new l({json:t.json,color:n.color}),s=await new f(n).listGithubRepos(o,{search:t.search});if(t.json)r.output(l.result(s));else{console.log(`
274
+ \u{1F517} GitHub Repositories (${s.items.length})
275
+ `);let c=new Be({head:["Repository","Added"].map(p=>p),colWidths:[45,20]});s.items.forEach(p=>{c.push([p.fullName,new Date(p.createdAt).toLocaleDateString()])}),console.log(c.toString()),console.log(`
275
276
  \u{1F4A1} Test an issue: runhuman github test <issueNumber> --repo owner/repo
276
- `)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),s.command("issues").description("List GitHub issues for a repository").argument("<repo>","Repository in format owner/repo").option("--state <state>","Filter by state (open/closed/all)","open").option("--labels <labels>","Filter by comma-separated labels").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u=t.match(/^([^/]+)\/([^/]+)$/);if(!u)throw new Error("Invalid repository format. Use: owner/repo");let[,i,c]=u,m=await new f(o).listGithubIssues(i,c,{state:e.state,labels:e.labels?.split(",")});if(e.json){let h=l.result({issues:m});r.output(h)}else{console.log(`
277
+ `)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i.command("issues").description("List GitHub issues for a repository").argument("<repo>","Repository in format owner/repo").option("--state <state>","Filter by state (open/closed/all)","open").option("--labels <labels>","Filter by comma-separated labels").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color}),u=t.match(/^([^/]+)\/([^/]+)$/);if(!u)throw new Error("Invalid repository format. Use: owner/repo");let[,s,c]=u,m=await new f(o).listGithubIssues(s,c,{state:e.state,labels:e.labels?.split(",")});if(e.json){let h=l.result({issues:m});r.output(h)}else{console.log(`
277
278
  \u{1F41B} GitHub Issues for ${t} (${m.length})
278
- `);let h=new He({head:["#","Title","State","Labels","Created"].map(b=>b),colWidths:[8,40,10,20,15]});m.forEach(b=>{let w=b.labels?.join(", ")||"-",j=w.length>18?w.substring(0,15)+"...":w;h.push(["#"+b.number,b.title.length>38?b.title.substring(0,35)+"...":b.title,b.state,j,new Date(b.createdAt).toLocaleDateString()])}),console.log(h.toString()),console.log(`
279
+ `);let h=new Be({head:["#","Title","State","Labels","Created"].map(b=>b),colWidths:[8,40,10,20,15]});m.forEach(b=>{let w=b.labels?.join(", ")||"-",j=w.length>18?w.substring(0,15)+"...":w;h.push(["#"+b.number,b.title.length>38?b.title.substring(0,35)+"...":b.title,b.state,j,new Date(b.createdAt).toLocaleDateString()])}),console.log(h.toString()),console.log(`
279
280
  \u{1F4A1} Test an issue: runhuman github test <issueNumber> --repo `+t+`
280
- `)}}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("test").description("Create a QA test job for a GitHub issue").argument("<issueNumber>","Issue number to test").option("--repo <owner/repo>","Repository (or use default from config)").option("--url <url>","URL to test (required)").option("--template <id>","Template ID to use").option("--sync","Wait for result before exiting").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.repo||o.githubRepo;if(!r)throw new Error("Repository required (use --repo or set default with: runhuman github link)");if(!e.url)throw new Error("URL required (use --url)");let u=new l({json:e.json,color:o.color}),i=r.match(/^([^/]+)\/([^/]+)$/);if(!i)throw new Error("Invalid repository format. Use: owner/repo");let[,c,p]=i,m=new f(o),h=await m.getGithubIssue(c,p,parseInt(t));if(!o.project)throw new Error("No project selected. Run: runhuman projects switch <project-id>");let b={projectId:o.project,url:e.url,description:`Test GitHub issue #${t}: ${h.title}
281
+ `)}}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("test").description("Create a QA test job for a GitHub issue").argument("<issueNumber>","Issue number to test").option("--repo <owner/repo>","Repository (or use default from config)").option("--url <url>","URL to test (required)").option("--template <id>","Template ID to use").option("--sync","Wait for result before exiting").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=e.repo||o.githubRepo;if(!r)throw new Error("Repository required (use --repo or set default with: runhuman github link)");if(!e.url)throw new Error("URL required (use --url)");let u=new l({json:e.json,color:o.color}),s=r.match(/^([^/]+)\/([^/]+)$/);if(!s)throw new Error("Invalid repository format. Use: owner/repo");let[,c,p]=s,m=new f(o),h=await m.getGithubIssue(c,p,parseInt(t));if(!o.project)throw new Error("No project selected. Run: runhuman projects switch <project-id>");let b={projectId:o.project,url:e.url,description:`Test GitHub issue #${t}: ${h.title}
281
282
 
282
283
  ${h.body}`,metadata:{githubIssue:{owner:c,repo:p,number:parseInt(t),url:h.url}},templateId:e.template},w=await m.createJob(b);if(e.json){let j=l.result(w);u.output(j)}else if(u.success("QA test job created for issue #"+t),console.log(`
283
284
  Job ID: `+w.jobId),console.log(" Issue: #"+t+" - "+h.title),console.log(" Status: "+w.status),console.log(" URL: "+e.url),console.log(`
284
285
  \u{1F4A1} Check status: runhuman status `+w.jobId+`
285
- `),e.sync){let{waitForJob:j}=await Promise.resolve().then(()=>(ee(),ae));await j(w.jobId,m,u,600)}}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),s.command("bulk-test").description("Create QA test jobs for multiple GitHub issues").option("--repo <owner/repo>","Repository (or use default from config)").option("--url <url>","URL to test (required)").option("--labels <labels>","Filter issues by comma-separated labels").option("--state <state>","Filter by state (open/closed/all)","open").option("--template <id>","Template ID to use").option("--limit <number>","Maximum number of jobs to create","10").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=t.repo||n.githubRepo;if(!o)throw new Error("Repository required (use --repo or set default with: runhuman github link)");if(!t.url)throw new Error("URL required (use --url)");let r=new l({json:t.json,color:n.color}),u=o.match(/^([^/]+)\/([^/]+)$/);if(!u)throw new Error("Invalid repository format. Use: owner/repo");let[,i,c]=u,p=new f(n),m=await p.listGithubIssues(i,c,{state:t.state,labels:t.labels?.split(",")}),h=parseInt(t.limit),b=m.slice(0,h);if(b.length===0){console.log(`No issues found matching the criteria.
286
+ `),e.sync){let{waitForJob:j}=await Promise.resolve().then(()=>(oe(),le));await j(w.jobId,m,u,600)}}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("bulk-test").description("Create QA test jobs for multiple GitHub issues").option("--repo <owner/repo>","Repository (or use default from config)").option("--url <url>","URL to test (required)").option("--labels <labels>","Filter issues by comma-separated labels").option("--state <state>","Filter by state (open/closed/all)","open").option("--template <id>","Template ID to use").option("--limit <number>","Maximum number of jobs to create","10").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=t.repo||n.githubRepo;if(!o)throw new Error("Repository required (use --repo or set default with: runhuman github link)");if(!t.url)throw new Error("URL required (use --url)");let r=new l({json:t.json,color:n.color}),u=o.match(/^([^/]+)\/([^/]+)$/);if(!u)throw new Error("Invalid repository format. Use: owner/repo");let[,s,c]=u,p=new f(n),m=await p.listGithubIssues(s,c,{state:t.state,labels:t.labels?.split(",")}),h=parseInt(t.limit),b=m.slice(0,h);if(b.length===0){console.log(`No issues found matching the criteria.
286
287
  `);return}if(!n.project)throw new Error("No project selected. Run: runhuman projects switch <project-id>");console.log(`
287
288
  \u{1F680} Creating ${b.length} test jobs...
288
- `);let w=[];for(let j of b){let x={projectId:n.project,url:t.url,description:`Test GitHub issue #${j.number}: ${j.title}
289
+ `);let w=[];for(let j of b){let k={projectId:n.project,url:t.url,description:`Test GitHub issue #${j.number}: ${j.title}
289
290
 
290
- ${j.body}`,metadata:{githubIssue:{owner:i,repo:c,number:j.number,url:j.url}},templateId:t.template};try{let U=await p.createJob(x);w.push({issue:j.number,jobId:U.jobId,status:"created"}),console.log(` \u2713 Issue #${j.number} \u2192 Job ${U.jobId}`)}catch(U){let H=d(U);w.push({issue:j.number,error:H.message,status:"failed"}),console.log(` \u2717 Issue #${j.number} \u2192 Failed: ${H.message}`)}}if(t.json){let j=l.result({jobs:w});r.output(j)}else{let j=w.filter(U=>U.status==="created").length,x=w.filter(U=>U.status==="failed").length;console.log(`
291
- \u2713 Created ${j} jobs`),x>0&&console.log(`\u2717 Failed ${x} jobs`),console.log(`
291
+ ${j.body}`,metadata:{githubIssue:{owner:s,repo:c,number:j.number,url:j.url}},templateId:t.template};try{let P=await p.createJob(k);w.push({issue:j.number,jobId:P.jobId,status:"created"}),console.log(` \u2713 Issue #${j.number} \u2192 Job ${P.jobId}`)}catch(P){let V=d(P);w.push({issue:j.number,error:V.message,status:"failed"}),console.log(` \u2717 Issue #${j.number} \u2192 Failed: ${V.message}`)}}if(t.json){let j=l.result({jobs:w});r.output(j)}else{let j=w.filter(P=>P.status==="created").length,k=w.filter(P=>P.status==="failed").length;console.log(`
292
+ \u2713 Created ${j} jobs`),k>0&&console.log(`\u2717 Failed ${k} jobs`),console.log(`
292
293
  \u{1F4A1} Check all jobs: runhuman list
293
- `)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),s}A();k();import{existsSync as Ho}from"fs";import{join as qo}from"path";import{execSync as Wo}from"child_process";import _ from"inquirer";import P from"chalk";import Ve from"ora";I();async function Be(){let s=new g,t=new l({color:!0});console.log(""),console.log(P.bold("Runhuman")+" - Human QA testing for your apps"),console.log("");let e=await We(s);if(!e.isAuthenticated){let{shouldLogin:n}=await _.prompt([{type:"confirm",name:"shouldLogin",message:"You're not logged in. Would you like to sign in?",default:!0}]);if(!n){console.log(`
294
- Run `+P.cyan("runhuman login")+` when you're ready to sign in.
295
- `);return}await Vo(s,t),Object.assign(e,await We(s))}console.log(P.green("Logged in as "+e.userEmail)+`
296
- `),e.isRunhumanProject?await Bo(s,e):await Zo(s,e)}async function We(s){let t={isAuthenticated:!1,isGitRepo:!1,isRunhumanProject:!1},e=s.loadCredentials();if(e?.accessToken)try{let o=await s.loadConfig({apiKey:e.accessToken}),u=await new f(o).getCurrentUser();t.isAuthenticated=!0,t.userEmail=u.email}catch{t.isAuthenticated=!1}try{Wo("git rev-parse --is-inside-work-tree",{stdio:"ignore"}),t.isGitRepo=!0}catch{t.isGitRepo=!1}let n=qo(process.cwd(),".runhumanrc");if(Ho(n)){t.isRunhumanProject=!0;try{let o=await s.loadConfig();t.projectConfig={defaultUrl:o.defaultUrl,githubRepo:o.githubRepo}}catch{}}return t}async function Vo(s,t){let e=await s.loadConfig(),n=e.apiUrl||"https://runhuman.com";console.log("");let o=Ve("Opening browser for authentication...").start();try{let r=await oe({apiUrl:n,autoOpenBrowser:e.autoOpenBrowser!==!1});o.stop(),s.saveCredentials({accessToken:r.token});let u=await s.loadConfig({apiKey:r.token}),c=await new f(u).getCurrentUser();s.saveUserInfo(c),t.success("Successfully logged in!"),console.log("")}catch(r){throw o.stop(),r}}async function Bo(s,t){console.log(P.dim("Runhuman project detected")),t.projectConfig?.defaultUrl&&console.log(P.dim("URL: "+t.projectConfig.defaultUrl)),console.log("");let{action:e}=await _.prompt([{type:"list",name:"action",message:"What would you like to do?",choices:[{name:"Quick test a URL",value:"quick-test"},{name:"Run a template",value:"run-template"},{name:"View recent jobs",value:"list-jobs"},new _.Separator,{name:"Exit",value:"exit"}]}]);switch(e){case"quick-test":await Ze(s,t);break;case"run-template":console.log(`
297
- Run `+P.cyan("runhuman templates")+" to see available templates."),console.log("Then run "+P.cyan("runhuman create --template <name>")+` to use one.
294
+ `)}}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i}T();A();C();I();import{Command as an}from"commander";import Ze from"cli-table3";function Qe(){let i=new an("transfers");return i.description("Manage project transfers between organizations"),i.command("list").alias("ls").description("List pending incoming and outgoing transfers").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async t=>{try{let n=await new g().loadConfig({apiKey:t.apiKey,apiUrl:t.apiUrl}),o=new l({json:t.json,color:n.color}),r=new f(n),[u,s]=await Promise.all([r.listPendingTransfers(),r.listOutgoingTransfers()]);if(t.json){let c=l.result({incoming:u.items,outgoing:s.items});o.output(c);return}if(console.log(`
295
+ \u{1F4E5} Incoming Transfers (${u.total})
296
+ `),u.items.length===0)console.log(` No pending incoming transfers.
297
+ `);else{let c=new Ze({head:["Transfer ID","Project","From","To Org","Created"],colWidths:[20,25,25,25,15]});u.items.forEach(p=>{c.push([p.id.substring(0,18),p.projectName,p.initiatedByEmail??"Unknown",p.toOrganizationName??"-",new Date(p.createdAt).toLocaleDateString()])}),console.log(c.toString()),console.log()}if(console.log(`\u{1F4E4} Outgoing Transfers (${s.total})
298
+ `),s.items.length===0)console.log(` No pending outgoing transfers.
299
+ `);else{let c=new Ze({head:["Transfer ID","Project","To Org","Status","Created"],colWidths:[20,25,25,15,15]});s.items.forEach(p=>{c.push([p.id.substring(0,18),p.projectName,p.toOrganizationName??"-",p.status,new Date(p.createdAt).toLocaleDateString()])}),console.log(c.toString()),console.log()}console.log("\u{1F4A1} Accept: runhuman transfers accept <transferId>"),console.log("\u{1F4A1} Reject: runhuman transfers reject <transferId>"),console.log("\u{1F4A1} Cancel: runhuman transfers cancel <transferId>"),console.log()}catch(e){let n=d(e);new l({json:t.json}).outputError(n.message,n.details),process.exit(n.exitCode)}}),i.command("accept").description("Accept a pending transfer").argument("<transferId>","Transfer ID to accept").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color});await new f(o).acceptTransfer(t),e.json?r.output(l.result({success:!0,transferId:t})):(r.success("Transfer accepted!"),console.log(" Transfer ID: "+t),console.log())}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("reject").description("Reject a pending transfer").argument("<transferId>","Transfer ID to reject").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color});await new f(o).rejectTransfer(t),e.json?r.output(l.result({success:!0,transferId:t})):(r.success("Transfer rejected."),console.log(" Transfer ID: "+t),console.log())}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i.command("cancel").description("Cancel a transfer you initiated").argument("<transferId>","Transfer ID to cancel").option("--json","Output as JSON").option("--api-key <key>","API key").option("--api-url <url>","API URL").action(async(t,e)=>{try{let o=await new g().loadConfig({apiKey:e.apiKey,apiUrl:e.apiUrl}),r=new l({json:e.json,color:o.color});await new f(o).cancelTransfer(t),e.json?r.output(l.result({success:!0,transferId:t})):(r.success("Transfer cancelled."),console.log(" Transfer ID: "+t),console.log())}catch(n){let o=d(n);new l({json:e.json}).outputError(o.message,o.details),process.exit(o.exitCode)}}),i}A();T();import{existsSync as cn}from"fs";import{join as ln}from"path";import{execSync as un}from"child_process";import J from"inquirer";import E from"chalk";import et from"ora";I();async function tt(){let i=new g,t=new l({color:!0});console.log(""),console.log(E.bold("Runhuman")+" - Human QA testing for your apps"),console.log("");let e=await Xe(i);if(!e.isAuthenticated){let{shouldLogin:n}=await J.prompt([{type:"confirm",name:"shouldLogin",message:"You're not logged in. Would you like to sign in?",default:!0}]);if(!n){console.log(`
300
+ Run `+E.cyan("runhuman login")+` when you're ready to sign in.
301
+ `);return}await pn(i,t),Object.assign(e,await Xe(i))}console.log(E.green("Logged in as "+e.userEmail)+`
302
+ `),e.isRunhumanProject?await mn(i,e):await dn(i,e)}async function Xe(i){let t={isAuthenticated:!1,isGitRepo:!1,isRunhumanProject:!1},e=i.loadCredentials();if(e?.accessToken)try{let o=await i.loadConfig({apiKey:e.accessToken}),u=await new f(o).getCurrentUser();t.isAuthenticated=!0,t.userEmail=u.email}catch{t.isAuthenticated=!1}try{un("git rev-parse --is-inside-work-tree",{stdio:"ignore"}),t.isGitRepo=!0}catch{t.isGitRepo=!1}let n=ln(process.cwd(),".runhumanrc");if(cn(n)){t.isRunhumanProject=!0;try{let o=await i.loadConfig();t.projectConfig={defaultUrl:o.defaultUrl,githubRepo:o.githubRepo}}catch{}}return t}async function pn(i,t){let e=await i.loadConfig(),n=e.apiUrl||"https://runhuman.com";console.log("");let o=et("Opening browser for authentication...").start();try{let r=await re({apiUrl:n,autoOpenBrowser:e.autoOpenBrowser!==!1});o.stop(),i.saveCredentials({accessToken:r.token});let u=await i.loadConfig({apiKey:r.token}),c=await new f(u).getCurrentUser();i.saveUserInfo(c),t.success("Successfully logged in!"),console.log("")}catch(r){throw o.stop(),r}}async function mn(i,t){console.log(E.dim("Runhuman project detected")),t.projectConfig?.defaultUrl&&console.log(E.dim("URL: "+t.projectConfig.defaultUrl)),console.log("");let{action:e}=await J.prompt([{type:"list",name:"action",message:"What would you like to do?",choices:[{name:"Quick test a URL",value:"quick-test"},{name:"Run a template",value:"run-template"},{name:"View recent jobs",value:"list-jobs"},new J.Separator,{name:"Exit",value:"exit"}]}]);switch(e){case"quick-test":await ot(i,t);break;case"run-template":console.log(`
303
+ Run `+E.cyan("runhuman templates")+" to see available templates."),console.log("Then run "+E.cyan("runhuman create --template <name>")+` to use one.
298
304
  `);break;case"list-jobs":console.log(`
299
- Run `+P.cyan("runhuman list")+` to see your recent jobs.
300
- `);break;case"exit":break}}async function Zo(s,t){t.isGitRepo?console.log(P.dim("Git repository detected (not yet set up with Runhuman)")):console.log(P.dim("Not in a git repository")),console.log("");let{action:e}=await _.prompt([{type:"list",name:"action",message:"What would you like to do?",choices:[{name:"Quick test a URL",value:"quick-test"},{name:"Set up this repo with Runhuman",value:"setup-repo",disabled:!t.isGitRepo},{name:"Connect a GitHub repo",value:"connect-github"},new _.Separator,{name:"Exit",value:"exit"}]}]);switch(e){case"quick-test":await Ze(s,t);break;case"setup-repo":await Qo(s);break;case"connect-github":await Yo(s);break;case"exit":break}}async function Ze(s,t){let e=t.projectConfig?.defaultUrl||"",n=await _.prompt([{type:"input",name:"url",message:"URL to test:",default:e||void 0,validate:r=>{if(!r.trim())return"URL is required";try{return new URL(r),!0}catch{return"Please enter a valid URL"}}},{type:"input",name:"description",message:"What should we test? (describe in plain English):",validate:r=>r.trim()?!0:"Description is required"}]),o=Ve("Creating test job...").start();try{let r=s.loadCredentials(),u=await s.loadConfig({apiKey:r?.accessToken});if(!u.project){o.fail("No project selected"),console.log(`
301
- Run: runhuman projects switch <project-id>`);return}let c=await new f(u).createJob({projectId:u.project,url:n.url,description:n.description});o.succeed("Test job created!"),console.log(""),console.log(" Job ID: "+P.cyan(c.jobId)),console.log(" Status: "+c.status),console.log(""),console.log("A human tester will test your app shortly."),console.log("Run "+P.cyan(`runhuman wait ${c.jobId}`)+" to wait for results."),console.log("")}catch(r){throw o.fail("Failed to create test job"),r}}async function Qo(s){console.log(""),console.log("Setting up Runhuman in the current repository..."),console.log("");let t=await _.prompt([{type:"input",name:"defaultUrl",message:"Default URL to test (optional):"}]);await s.saveProjectConfig({defaultUrl:t.defaultUrl||void 0,defaultDuration:5,defaultScreenSize:"desktop"}),console.log(""),console.log(P.green("Created .runhumanrc")),console.log(""),console.log("Next steps:"),console.log(" 1. Install the GitHub App to enable @runhuman comments"),console.log(" "+P.cyan("runhuman github connect")),console.log(""),console.log(" 2. Create your first test:"),console.log(" "+P.cyan('runhuman create https://your-app.com -d "Test login flow"')),console.log("")}async function Yo(s){let n=`${(await s.loadConfig()).apiUrl||"https://runhuman.com"}/dashboard/settings/github`;console.log(""),console.log("To connect your GitHub repos, install the Runhuman GitHub App:"),console.log(""),console.log(" "+P.cyan(n)),console.log(""),console.log("After installation, you can comment "+P.bold("@runhuman")+" on any issue"),console.log("to trigger a QA test."),console.log("")}import{readFileSync as en}from"fs";import{join as tn,dirname as on}from"path";import{fileURLToPath as nn}from"url";var rn=nn(import.meta.url),sn=on(rn),an=tn(sn,"../package.json"),cn=JSON.parse(en(an,"utf-8")),ln=cn.version,S=new Xo;S.name("runhuman").description("CLI for Runhuman - AI-orchestrated human QA testing").version(ln);S.addCommand(he());S.addCommand(be());S.addCommand(ie());S.addCommand(Pe());S.addCommand(ke());S.addCommand(xe());S.addCommand(Oe());S.addCommand(Ee());S.addCommand(De());S.addCommand(Ne());S.addCommand(ze());S.addCommand(Me());S.addCommand(Le());S.addCommand(_e());S.addCommand(Ke());S.addCommand(Ge());S.addCommand(qe());process.argv.slice(2).length?S.parse(process.argv):Be().catch(s=>{console.error(s.message),process.exit(1)});
305
+ Run `+E.cyan("runhuman list")+` to see your recent jobs.
306
+ `);break;case"exit":break}}async function dn(i,t){t.isGitRepo?console.log(E.dim("Git repository detected (not yet set up with Runhuman)")):console.log(E.dim("Not in a git repository")),console.log("");let{action:e}=await J.prompt([{type:"list",name:"action",message:"What would you like to do?",choices:[{name:"Quick test a URL",value:"quick-test"},{name:"Set up this repo with Runhuman",value:"setup-repo",disabled:!t.isGitRepo},{name:"Connect a GitHub repo",value:"connect-github"},new J.Separator,{name:"Exit",value:"exit"}]}]);switch(e){case"quick-test":await ot(i,t);break;case"setup-repo":await gn(i);break;case"connect-github":await fn(i);break;case"exit":break}}async function ot(i,t){let e=t.projectConfig?.defaultUrl||"",n=await J.prompt([{type:"input",name:"url",message:"URL to test:",default:e||void 0,validate:r=>{if(!r.trim())return"URL is required";try{return new URL(r),!0}catch{return"Please enter a valid URL"}}},{type:"input",name:"description",message:"What should we test? (describe in plain English):",validate:r=>r.trim()?!0:"Description is required"}]),o=et("Creating test job...").start();try{let r=i.loadCredentials(),u=await i.loadConfig({apiKey:r?.accessToken});if(!u.project){o.fail("No project selected"),console.log(`
307
+ Run: runhuman projects switch <project-id>`);return}let c=await new f(u).createJob({projectId:u.project,url:n.url,description:n.description});o.succeed("Test job created!"),console.log(""),console.log(" Job ID: "+E.cyan(c.jobId)),console.log(" Status: "+c.status),console.log(""),console.log("A human tester will test your app shortly."),console.log("Run "+E.cyan(`runhuman wait ${c.jobId}`)+" to wait for results."),console.log("")}catch(r){throw o.fail("Failed to create test job"),r}}async function gn(i){console.log(""),console.log("Setting up Runhuman in the current repository..."),console.log("");let t=await J.prompt([{type:"input",name:"defaultUrl",message:"Default URL to test (optional):"}]);await i.saveProjectConfig({defaultUrl:t.defaultUrl||void 0,defaultDuration:5,defaultDeviceClass:"desktop"}),console.log(""),console.log(E.green("Created .runhumanrc")),console.log(""),console.log("Next steps:"),console.log(" 1. Install the GitHub App to enable @runhuman comments"),console.log(" "+E.cyan("runhuman github connect")),console.log(""),console.log(" 2. Create your first test:"),console.log(" "+E.cyan('runhuman create https://your-app.com -d "Test login flow"')),console.log("")}async function fn(i){let n=`${(await i.loadConfig()).apiUrl||"https://runhuman.com"}/dashboard/settings/github`;console.log(""),console.log("To connect your GitHub repos, install the Runhuman GitHub App:"),console.log(""),console.log(" "+E.cyan(n)),console.log(""),console.log("After installation, you can comment "+E.bold("@runhuman")+" on any issue"),console.log("to trigger a QA test."),console.log("")}import{readFileSync as bn}from"fs";import{join as yn,dirname as wn}from"path";import{fileURLToPath as jn}from"url";var Cn=jn(import.meta.url),In=wn(Cn),Sn=yn(In,"../package.json"),An=JSON.parse(bn(Sn,"utf-8")),Tn=An.version,S=new hn;S.name("runhuman").description("CLI for Runhuman - AI-orchestrated human QA testing").version(Tn);S.addCommand(we());S.addCommand(je());S.addCommand(ce());S.addCommand(Pe());S.addCommand(xe());S.addCommand(ve());S.addCommand(Oe());S.addCommand(Me());S.addCommand(Le());S.addCommand($e());S.addCommand(_e());S.addCommand(Je());S.addCommand(Ke());S.addCommand(Ve());S.addCommand(Ge());S.addCommand(We());S.addCommand(Ye());S.addCommand(Qe());process.argv.slice(2).length?S.parse(process.argv):tt().catch(i=>{console.error(i.message),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runhuman",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "CLI for Runhuman - AI-orchestrated human QA testing",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",