@runcofactor/cli 0.10.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{api-catalog-GFGCLVS4.js → api-catalog-7HLEN7C2.js} +5 -4
- package/dist/{api-catalog-GFGCLVS4.js.map → api-catalog-7HLEN7C2.js.map} +1 -1
- package/dist/{attachment-SJC7D7FY.js → attachment-OVNQD6Z2.js} +5 -4
- package/dist/{attachment-SJC7D7FY.js.map → attachment-OVNQD6Z2.js.map} +1 -1
- package/dist/{auth-EN6NQCJY.js → auth-VUHL74FH.js} +3 -2
- package/dist/{chunk-IMPZAX6L.js → chunk-5GD47G2D.js} +37 -1
- package/dist/{chunk-IMPZAX6L.js.map → chunk-5GD47G2D.js.map} +1 -1
- package/dist/{chunk-WOHL4FTB.js → chunk-CQE46HSM.js} +5 -5
- package/dist/chunk-CQE46HSM.js.map +1 -0
- package/dist/{chunk-52IO7ACJ.js → chunk-CRHPDPRS.js} +39 -3
- package/dist/{chunk-52IO7ACJ.js.map → chunk-CRHPDPRS.js.map} +1 -1
- package/dist/{chunk-XQXVG7RA.js → chunk-EEN2TZUQ.js} +3 -3
- package/dist/{chunk-I4QLI3JO.js → chunk-EJ4U242G.js} +2 -2
- package/dist/{chunk-CLAWT7BJ.js → chunk-ENDHMYEJ.js} +3 -3
- package/dist/chunk-G4UYGRZR.js +2 -0
- package/dist/chunk-JZMJUPZP.js +92 -0
- package/dist/chunk-JZMJUPZP.js.map +1 -0
- package/dist/{chunk-GKY2KXO5.js → chunk-NL7CVG56.js} +105 -35
- package/dist/chunk-NL7CVG56.js.map +1 -0
- package/dist/{chunk-A4OFTUVV.js → chunk-PZ4LCN6K.js} +7 -4
- package/dist/chunk-PZ4LCN6K.js.map +1 -0
- package/dist/{chunk-SJJW77WN.js → chunk-QGI4UCJX.js} +69 -5
- package/dist/chunk-QGI4UCJX.js.map +1 -0
- package/dist/{chunk-4PNOV7OV.js → chunk-QQVWGWPI.js} +1023 -150
- package/dist/chunk-QQVWGWPI.js.map +1 -0
- package/dist/{chunk-N7HFALX3.js → chunk-VGTKUOYS.js} +2 -2
- package/dist/{chunk-B2VISN2V.js → chunk-YN763NWQ.js} +230 -66
- package/dist/chunk-YN763NWQ.js.map +1 -0
- package/dist/{chunk-QFDOWABX.js → chunk-Z5LUTUDN.js} +6 -3
- package/dist/chunk-Z5LUTUDN.js.map +1 -0
- package/dist/{chunk-Q4BO4Z5V.js → chunk-ZTOE3ND3.js} +4 -4
- package/dist/{credential-COLTBV6D.js → credential-LO2SEEHU.js} +24 -20
- package/dist/credential-LO2SEEHU.js.map +1 -0
- package/dist/{credential-template-EEPYFG7R.js → credential-template-ZN7W7734.js} +30 -28
- package/dist/credential-template-ZN7W7734.js.map +1 -0
- package/dist/{debug-workflow-KOVH5GOP.js → debug-workflow-R3RYYAXK.js} +5 -4
- package/dist/{debug-workflow-KOVH5GOP.js.map → debug-workflow-R3RYYAXK.js.map} +1 -1
- package/dist/{docs-3SSORHB5.js → docs-DIAFBDXQ.js} +5 -4
- package/dist/{docs-3SSORHB5.js.map → docs-DIAFBDXQ.js.map} +1 -1
- package/dist/{doctor-OTSIWV6G.js → doctor-NZPUSCRE.js} +9 -5
- package/dist/doctor-NZPUSCRE.js.map +1 -0
- package/dist/environment-RQVU4P5M.js +221 -0
- package/dist/environment-RQVU4P5M.js.map +1 -0
- package/dist/{feature-flag-T2LRZME3.js → feature-flag-XG26RURR.js} +72 -10
- package/dist/feature-flag-XG26RURR.js.map +1 -0
- package/dist/index.js +57 -48
- package/dist/index.js.map +1 -1
- package/dist/{init-TGWRECT2.js → init-EDNLKGPT.js} +5 -4
- package/dist/{init-TGWRECT2.js.map → init-EDNLKGPT.js.map} +1 -1
- package/dist/{install-DXSNWZKO.js → install-FYZ3HNZK.js} +7 -7
- package/dist/{issues-XIZOPX6T.js → issues-NNRVTJ4L.js} +5 -4
- package/dist/{issues-XIZOPX6T.js.map → issues-NNRVTJ4L.js.map} +1 -1
- package/dist/{knobs-NBINZIUB.js → knobs-A2BOBH22.js} +5 -4
- package/dist/{knobs-NBINZIUB.js.map → knobs-A2BOBH22.js.map} +1 -1
- package/dist/{list-3TDHK637.js → list-F33VZ4BJ.js} +5 -4
- package/dist/{list-3TDHK637.js.map → list-F33VZ4BJ.js.map} +1 -1
- package/dist/{local-HICVD6PU.js → local-DQDTM3XA.js} +7 -6
- package/dist/{local-HICVD6PU.js.map → local-DQDTM3XA.js.map} +1 -1
- package/dist/{login-UOIUXVUK.js → login-BUMVIB36.js} +5 -4
- package/dist/{login-UOIUXVUK.js.map → login-BUMVIB36.js.map} +1 -1
- package/dist/{mcp-54IJEOUA.js → mcp-B5Y5CDMQ.js} +23 -24
- package/dist/mcp-B5Y5CDMQ.js.map +1 -0
- package/dist/{property-UXLOLPTD.js → property-NJ4SRXQG.js} +76 -4
- package/dist/property-NJ4SRXQG.js.map +1 -0
- package/dist/{psql-BYUUNLGG.js → psql-VBZFCMNR.js} +3 -2
- package/dist/{psql-BYUUNLGG.js.map → psql-VBZFCMNR.js.map} +1 -1
- package/dist/{record-4TR2UIIS.js → record-WAO36O7G.js} +16 -17
- package/dist/record-WAO36O7G.js.map +1 -0
- package/dist/{redis-35VBUYW7.js → redis-DHZXHL4S.js} +3 -2
- package/dist/{redis-35VBUYW7.js.map → redis-DHZXHL4S.js.map} +1 -1
- package/dist/{release-OOLTUBUT.js → release-STJKUKTE.js} +5 -4
- package/dist/{release-OOLTUBUT.js.map → release-STJKUKTE.js.map} +1 -1
- package/dist/{sandbox-XGSUU6G7.js → sandbox-DWSGLY7B.js} +9 -8
- package/dist/{sandbox-XGSUU6G7.js.map → sandbox-DWSGLY7B.js.map} +1 -1
- package/dist/{scenarios-GWLJEGHA.js → scenarios-HCIDY725.js} +5 -4
- package/dist/{scenarios-GWLJEGHA.js.map → scenarios-HCIDY725.js.map} +1 -1
- package/dist/{session-MYFNZPRP.js → session-Y5RHU54D.js} +76 -8
- package/dist/session-Y5RHU54D.js.map +1 -0
- package/dist/{skill-KM34LDMO.js → skill-23WAHUOB.js} +217 -67
- package/dist/skill-23WAHUOB.js.map +1 -0
- package/dist/skills/debug-run/SKILL.md +33 -22
- package/dist/skills/debug-run/history/1.2.0.md +262 -0
- package/dist/skills/debug-run/history/1.3.0.md +273 -0
- package/dist/skills/debug-run/version.json +1 -1
- package/dist/skills/optimize-cache/SKILL.md +206 -0
- package/dist/{spec-RA3CFEKG.js → spec-LM5XHOQ5.js} +54 -25
- package/dist/spec-LM5XHOQ5.js.map +1 -0
- package/dist/{src-LB4HBTJQ.js → src-22RI5VP2.js} +19 -11
- package/dist/src-22RI5VP2.js.map +1 -0
- package/dist/src-BGDRMOKC.js +5748 -0
- package/dist/src-BGDRMOKC.js.map +1 -0
- package/dist/{src-N3TPKGTY.js → src-NCJPUAE6.js} +3 -2
- package/dist/{src-UVDX5UP6.js → src-Y3K7UJEF.js} +4 -2
- package/dist/{start-PSEQSQA3.js → start-SWY55CZX.js} +5 -4
- package/dist/{start-PSEQSQA3.js.map → start-SWY55CZX.js.map} +1 -1
- package/dist/{tag-YY6YAABQ.js → tag-YSU2XXPI.js} +6 -5
- package/dist/{task-IQC3YR5K.js → task-NLBKLD7D.js} +5 -4
- package/dist/{task-IQC3YR5K.js.map → task-NLBKLD7D.js.map} +1 -1
- package/dist/{test-suite-DZNJFXDW.js → test-suite-QCPWZ2LS.js} +9 -6
- package/dist/{test-suite-DZNJFXDW.js.map → test-suite-QCPWZ2LS.js.map} +1 -1
- package/dist/{trace-HXIW7U2D.js → trace-A3ZY6K26.js} +6 -4
- package/dist/{triage-ORG45R5W.js → triage-TT4BMDBU.js} +6 -5
- package/dist/triage-TT4BMDBU.js.map +1 -0
- package/dist/{upgrade-L2VYMP2V.js → upgrade-6ZUFETKX.js} +3 -3
- package/dist/{workflow-XYFH5LTP.js → workflow-2CX3ZNOQ.js} +241 -237
- package/dist/workflow-2CX3ZNOQ.js.map +1 -0
- package/dist/{workflow-cache-NQJQFWMV.js → workflow-cache-GXNE6SU2.js} +140 -7
- package/dist/workflow-cache-GXNE6SU2.js.map +1 -0
- package/dist/{workflow-debug-BGD4UIXU.js → workflow-debug-PRX3DWGD.js} +8 -7
- package/dist/{workflow-debug-BGD4UIXU.js.map → workflow-debug-PRX3DWGD.js.map} +1 -1
- package/dist/{workflow-proposals-MTUDX46O.js → workflow-proposals-BW327WGL.js} +5 -4
- package/dist/{workflow-proposals-MTUDX46O.js.map → workflow-proposals-BW327WGL.js.map} +1 -1
- package/package.json +2 -1
- package/dist/chunk-4PNOV7OV.js.map +0 -1
- package/dist/chunk-A4OFTUVV.js.map +0 -1
- package/dist/chunk-B2VISN2V.js.map +0 -1
- package/dist/chunk-GKY2KXO5.js.map +0 -1
- package/dist/chunk-JICSYFRJ.js +0 -46
- package/dist/chunk-JICSYFRJ.js.map +0 -1
- package/dist/chunk-QFDOWABX.js.map +0 -1
- package/dist/chunk-SJJW77WN.js.map +0 -1
- package/dist/chunk-WOHL4FTB.js.map +0 -1
- package/dist/credential-COLTBV6D.js.map +0 -1
- package/dist/credential-template-EEPYFG7R.js.map +0 -1
- package/dist/doctor-OTSIWV6G.js.map +0 -1
- package/dist/feature-flag-T2LRZME3.js.map +0 -1
- package/dist/mcp-54IJEOUA.js.map +0 -1
- package/dist/property-UXLOLPTD.js.map +0 -1
- package/dist/record-4TR2UIIS.js.map +0 -1
- package/dist/session-MYFNZPRP.js.map +0 -1
- package/dist/skill-KM34LDMO.js.map +0 -1
- package/dist/spec-RA3CFEKG.js.map +0 -1
- package/dist/src-LB4HBTJQ.js.map +0 -1
- package/dist/workflow-XYFH5LTP.js.map +0 -1
- package/dist/workflow-cache-NQJQFWMV.js.map +0 -1
- /package/dist/{auth-EN6NQCJY.js.map → auth-VUHL74FH.js.map} +0 -0
- /package/dist/{chunk-XQXVG7RA.js.map → chunk-EEN2TZUQ.js.map} +0 -0
- /package/dist/{chunk-I4QLI3JO.js.map → chunk-EJ4U242G.js.map} +0 -0
- /package/dist/{chunk-CLAWT7BJ.js.map → chunk-ENDHMYEJ.js.map} +0 -0
- /package/dist/{src-N3TPKGTY.js.map → chunk-G4UYGRZR.js.map} +0 -0
- /package/dist/{chunk-N7HFALX3.js.map → chunk-VGTKUOYS.js.map} +0 -0
- /package/dist/{chunk-Q4BO4Z5V.js.map → chunk-ZTOE3ND3.js.map} +0 -0
- /package/dist/{install-DXSNWZKO.js.map → install-FYZ3HNZK.js.map} +0 -0
- /package/dist/{src-UVDX5UP6.js.map → src-NCJPUAE6.js.map} +0 -0
- /package/dist/{tag-YY6YAABQ.js.map → src-Y3K7UJEF.js.map} +0 -0
- /package/dist/{trace-HXIW7U2D.js.map → tag-YSU2XXPI.js.map} +0 -0
- /package/dist/{triage-ORG45R5W.js.map → trace-A3ZY6K26.js.map} +0 -0
- /package/dist/{upgrade-L2VYMP2V.js.map → upgrade-6ZUFETKX.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/property.ts","../src/property-skill.ts"],"sourcesContent":["/**\n * CLI Property Management\n *\n * List properties and their linked GitHub repos.\n */\n\nimport process from 'node:process';\nimport { resolveConfig, hasFlag, getArgValue } from './auth.js';\nimport { fetchProperties, apiRequest, getApplicationArg } from './cli-helpers.js';\nimport { runPropertySkill } from './property-skill.js';\n\nfunction pad(s: string, n: number): string {\n return s.padEnd(n);\n}\n\nfunction printHelp(): void {\n console.log(\n [\n 'canary application: Manage applications (alias: canary property)',\n '',\n 'Sub-commands:',\n ' list List all applications',\n ' create [options] Create a new application',\n ' update <name|id> [options] Update application settings',\n ' repo link [options] Link a GitHub repo to an application',\n ' repo update [options] Update an existing repo link',\n ' repo unlink [options] Unlink a GitHub repo from an application',\n ' skill <action> [options] Manage the application\\'s app skill (run `canary application skill help` for details)',\n '',\n 'Create options:',\n ' --name <name> Application name (required)',\n ' --base-url <url> Application base URL (required)',\n ' --description <text> Optional description',\n ' --agent-context <text> Optional agent context (max 8000 chars)',\n ' --env-var <NAME[:sensitive]> Declare a per-environment variable (repeatable); values set per-environment, injected as $var.ENV.<NAME>',\n ' --login-path </path> Relative login page path appended to the environment URL (e.g. /login)',\n '',\n 'Update options:',\n ' --login-path </path> Set the relative login page path (empty string clears it)',\n ' --description <text> Set the description',\n ' --agent-context <text> Set the agent context',\n '',\n 'Repo link/update/unlink options:',\n ' --application <app_xxx|uuid> Application ID (required; alias: --property)',\n ' --repo <owner/name> Repo full name (required for link/unlink)',\n ' --repo-id <uuid> Repo link UUID (required for update)',\n ' --role <frontend|backend|...> Conventional role (free-form)',\n ' --root-dir <path> Monorepo subdirectory hint',\n ' --agent-hint <text> Free-form hint for the planner agent',\n '',\n 'Common options:',\n ' --json Output as JSON',\n ].join('\\n')\n );\n}\n\ntype GitHubRepo = {\n id: string;\n repoFullName: string;\n repoName: string;\n defaultBranch: string;\n rootDir: string | null;\n role: string | null;\n};\n\nasync function handleList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const json = hasFlag(argv, '--json');\n const properties = await fetchProperties(apiUrl, token);\n\n if (json) {\n console.log(JSON.stringify(properties, null, 2));\n return;\n }\n\n if (properties.length === 0) {\n console.log('No applications found.');\n return;\n }\n\n console.log(`${pad('Name', 30)} ${pad('Base URL', 40)} ID`);\n for (const p of properties) {\n console.log(`${pad(p.name, 30)} ${pad(p.baseUrl, 40)} ${p.id}`);\n }\n\n // Show linked repos for each property\n console.log('');\n for (const p of properties) {\n const reposRes = await apiRequest<{ ok: boolean; items: GitHubRepo[] }>(\n apiUrl, token, 'GET', `/org/properties/${p.id}/github-repos`\n );\n const repos = reposRes.ok ? (reposRes.items ?? []) : [];\n if (repos.length > 0) {\n console.log(`${p.name} repos:`);\n for (const r of repos) {\n const dir = r.rootDir && r.rootDir !== '/' ? ` (${r.rootDir})` : '';\n const role = r.role ? ` [${r.role}]` : '';\n console.log(` ${r.repoFullName}:${r.defaultBranch}${role}${dir}`);\n }\n }\n }\n}\n\n/**\n * Parse repeatable `--env-var NAME[:sensitive]` flags into env-var definitions.\n * Examples: `--env-var API_URL`, `--env-var API_TOKEN:sensitive`.\n */\nfunction parseEnvVarDefinitions(\n argv: string[]\n): Array<{ name: string; sensitive?: boolean }> {\n const defs: Array<{ name: string; sensitive?: boolean }> = [];\n for (let i = 0; i < argv.length; i++) {\n if (argv[i] !== '--env-var') continue;\n const raw = argv[i + 1];\n if (!raw || raw.startsWith('-')) continue;\n const [name, modifier] = raw.split(':');\n if (!name) continue;\n // Accept `NAME` or `NAME:sensitive`; ignore-with-no-effect any other suffix.\n defs.push({ name, ...(modifier === 'sensitive' ? { sensitive: true } : {}) });\n }\n return defs;\n}\n\nasync function handleCreate(argv: string[], apiUrl: string, token: string): Promise<void> {\n const json = hasFlag(argv, '--json');\n const name = getArgValue(argv, '--name');\n const baseUrl = getArgValue(argv, '--base-url');\n const description = getArgValue(argv, '--description');\n const agentContext = getArgValue(argv, '--agent-context');\n const loginPath = getArgValue(argv, '--login-path');\n const envVarDefinitions = parseEnvVarDefinitions(argv);\n\n if (!name || !baseUrl) {\n console.error('Error: --name and --base-url are required.');\n console.error('Usage: canary application create --name <name> --base-url <url>');\n process.exit(1);\n }\n\n const body: Record<string, unknown> = { name, baseUrl };\n if (description !== undefined) body.description = description;\n if (agentContext !== undefined) body.agentContext = agentContext;\n if (loginPath !== undefined) body.loginPath = loginPath;\n if (envVarDefinitions.length > 0) body.envVarDefinitions = envVarDefinitions;\n\n const result = await apiRequest<{ ok: boolean; id?: string; error?: string }>(\n apiUrl,\n token,\n 'POST',\n '/org/properties',\n body\n );\n\n if (!result.ok) {\n if (json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n }\n process.exit(1);\n }\n\n if (json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n console.log(`Created application \"${name}\" (${result.id})`);\n}\n\nasync function handleUpdate(argv: string[], apiUrl: string, token: string): Promise<void> {\n const json = hasFlag(argv, '--json');\n const appArg = argv.find((a) => !a.startsWith('-')) ?? getApplicationArg(argv);\n const loginPath = getArgValue(argv, '--login-path');\n const description = getArgValue(argv, '--description');\n const agentContext = getArgValue(argv, '--agent-context');\n\n if (!appArg) {\n console.error('Error: Missing application name or ID.');\n console.error('Usage: canary application update <name|id> [--login-path </path>] [--description <text>]');\n process.exit(1);\n }\n if (loginPath === undefined && description === undefined && agentContext === undefined) {\n console.error(\n 'Error: No fields to update. Provide at least one of: --login-path, --description, --agent-context'\n );\n process.exit(1);\n }\n\n const properties = await fetchProperties(apiUrl, token);\n const property = properties.find(\n (p) => p.id === appArg || p.name.toLowerCase() === appArg.toLowerCase()\n );\n if (!property) {\n console.error(`Error: Application \"${appArg}\" not found.`);\n if (properties.length > 0) {\n console.error('Available applications:');\n for (const p of properties) console.error(` - ${p.name} (${p.id})`);\n }\n process.exit(1);\n }\n\n const body: Record<string, unknown> = {};\n // Empty string clears the login path (sessions start at the environment URL).\n if (loginPath !== undefined) body.loginPath = loginPath;\n if (description !== undefined) body.description = description;\n if (agentContext !== undefined) body.agentContext = agentContext;\n\n const result = await apiRequest<{ ok: boolean; error?: string }>(\n apiUrl,\n token,\n 'PUT',\n `/org/properties/${property.id}`,\n body\n );\n\n if (!result.ok) {\n if (json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n }\n process.exit(1);\n }\n\n if (json) {\n console.log(JSON.stringify({ ok: true, applicationId: property.id, updated: body }, null, 2));\n return;\n }\n\n console.log(`Updated application \"${property.name}\" (${property.id}):`);\n if (loginPath !== undefined) {\n console.log(` loginPath: -> ${loginPath || '(cleared — sessions start at the environment URL)'}`);\n }\n if (description !== undefined) console.log(' description: updated');\n if (agentContext !== undefined) console.log(' agentContext: updated');\n}\n\nasync function handleRepoLink(argv: string[], apiUrl: string, token: string): Promise<void> {\n const json = hasFlag(argv, '--json');\n const propertyId = getApplicationArg(argv);\n const repo = getArgValue(argv, '--repo');\n const role = getArgValue(argv, '--role');\n const rootDir = getArgValue(argv, '--root-dir');\n const agentHint = getArgValue(argv, '--agent-hint');\n\n if (!propertyId || !repo) {\n console.error('Error: --application and --repo are required.');\n process.exit(1);\n }\n\n const body: Record<string, unknown> = { repoFullName: repo };\n if (role !== undefined) body.role = role;\n if (rootDir !== undefined) body.rootDir = rootDir;\n if (agentHint !== undefined) body.agentHint = agentHint;\n\n const result = await apiRequest<{ ok: boolean; id?: string; error?: string }>(\n apiUrl,\n token,\n 'POST',\n `/org/properties/${propertyId}/github-repos`,\n body\n );\n\n if (!result.ok) {\n if (json) console.log(JSON.stringify(result, null, 2));\n else console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n\n if (json) console.log(JSON.stringify(result, null, 2));\n else console.log(`Linked ${repo} to application ${propertyId} (${result.id})`);\n}\n\nasync function handleRepoUpdate(argv: string[], apiUrl: string, token: string): Promise<void> {\n const json = hasFlag(argv, '--json');\n const propertyId = getApplicationArg(argv);\n const repoId = getArgValue(argv, '--repo-id');\n const role = getArgValue(argv, '--role');\n const rootDir = getArgValue(argv, '--root-dir');\n const agentHint = getArgValue(argv, '--agent-hint');\n\n if (!propertyId || !repoId) {\n console.error('Error: --application and --repo-id are required.');\n process.exit(1);\n }\n\n const body: Record<string, unknown> = {};\n if (role !== undefined) body.role = role;\n if (rootDir !== undefined) body.rootDir = rootDir;\n if (agentHint !== undefined) body.agentHint = agentHint;\n\n const result = await apiRequest<{ ok: boolean; id?: string; error?: string }>(\n apiUrl,\n token,\n 'PATCH',\n `/org/properties/${propertyId}/github-repos/${repoId}`,\n body\n );\n\n if (!result.ok) {\n if (json) console.log(JSON.stringify(result, null, 2));\n else console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n\n if (json) console.log(JSON.stringify(result, null, 2));\n else console.log(`Updated repo link ${repoId}`);\n}\n\nasync function handleRepoUnlink(argv: string[], apiUrl: string, token: string): Promise<void> {\n const json = hasFlag(argv, '--json');\n const propertyId = getApplicationArg(argv);\n const repo = getArgValue(argv, '--repo');\n\n if (!propertyId || !repo) {\n console.error('Error: --application and --repo are required.');\n process.exit(1);\n }\n\n const result = await apiRequest<{ ok: boolean; error?: string }>(\n apiUrl,\n token,\n 'DELETE',\n `/org/properties/${propertyId}/github-repos/${encodeURIComponent(repo)}`\n );\n\n if (!result.ok) {\n if (json) console.log(JSON.stringify(result, null, 2));\n else console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n\n if (json) console.log(JSON.stringify(result, null, 2));\n else console.log(`Unlinked ${repo} from application ${propertyId}`);\n}\n\nasync function handleRepo(argv: string[], apiUrl: string, token: string): Promise<void> {\n const [action, ...rest] = argv;\n switch (action) {\n case 'link':\n await handleRepoLink(rest, apiUrl, token);\n break;\n case 'update':\n await handleRepoUpdate(rest, apiUrl, token);\n break;\n case 'unlink':\n await handleRepoUnlink(rest, apiUrl, token);\n break;\n default:\n console.error(`Unknown repo action: ${action ?? '(none)'}`);\n printHelp();\n process.exit(1);\n }\n}\n\nexport async function runProperty(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === 'help' || hasFlag(argv, '--help', '-h')) {\n printHelp();\n return;\n }\n\n // `skill guide` and `skill help` are doc-only; skip auth resolution so\n // unauthenticated agents can discover the methodology before logging in.\n if (subCommand === 'skill') {\n const skillAction = rest[0];\n if (!skillAction || skillAction === 'help' || skillAction === 'guide') {\n await runPropertySkill(rest, '', '');\n return;\n }\n }\n\n const { apiUrl, token } = await resolveConfig(argv);\n\n const globalFlags = new Set(['--env', '--api-url', '--token']);\n const args = rest.filter((arg, i) => {\n if (globalFlags.has(arg)) return false;\n if (i > 0 && globalFlags.has(rest[i - 1])) return false;\n return true;\n });\n\n switch (subCommand) {\n case 'list':\n await handleList(args, apiUrl, token);\n break;\n case 'create':\n await handleCreate(args, apiUrl, token);\n break;\n case 'update':\n await handleUpdate(args, apiUrl, token);\n break;\n case 'repo':\n await handleRepo(args, apiUrl, token);\n break;\n case 'skill':\n await runPropertySkill(args, apiUrl, token);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printHelp();\n process.exit(1);\n }\n}\n","/**\n * CLI: `canary property skill` — manage a property's app skill\n *\n * App skill = the per-property knowledge base injected into the cloud workflow\n * browser agent's system prompt. CLI is a thin client over the existing\n * /org/properties/:id/context endpoints. Source defaults to 'cli' so authored\n * items are distinguishable from browser-bootstrap or human-manual edits.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport process from 'node:process';\nimport { getArgValue, hasFlag } from './auth.js';\nimport { apiRequest, getApplicationArg } from './cli-helpers.js';\n\nconst HERE = dirname(fileURLToPath(import.meta.url));\nconst GUIDE_PATH = join(HERE, 'property-skill-guide.md');\n\nconst SECTIONS = [\n 'general',\n 'technology',\n 'product',\n 'ui',\n 'tenancy',\n 'auth',\n 'roles_permissions',\n 'navigation',\n 'feature_gating',\n 'environments',\n 'data_lifecycle',\n 'async_realtime',\n 'localization',\n 'feedback_errors',\n 'idiosyncrasies',\n] as const;\ntype Section = (typeof SECTIONS)[number];\n\ntype ContextItem = {\n id: string;\n propertyId: string;\n section: Section;\n itemKey: string;\n itemLabel: string;\n content: string;\n version: number;\n source: 'bootstrap' | 'workflow' | 'manual' | 'cli';\n sourceId: string | null;\n createdBy: string | null;\n createdAt: string;\n};\n\ntype ListResponse = {\n ok: boolean;\n error?: string;\n data?: { items: ContextItem[]; grouped: Record<string, ContextItem[]> };\n};\n\nfunction printSkillHelp(): void {\n console.log(\n [\n 'canary application skill: Manage an application\\'s app skill (per-application knowledge for QA browser agents). Alias: canary property skill. (--property accepted as an alias for --application.)',\n '',\n 'Sub-commands:',\n ' guide Print the full authoring methodology (start here)',\n ' list [--application <id>] [--section S] [--format json|table]',\n ' get --application <id> --section S --key K [--version N] [--format json|md]',\n ' set --application <id> --section S --key K --label L --content @file|\"text\" [--source-id <repo@sha>]',\n ' delete --application <id> --section S --key K',\n ' history --application <id> --section S --key K [--format json|table]',\n ' export --application <id> [--format md|json]',\n ' import --application <id> --file <bundle.json> [--source-id <repo@sha>]',\n '',\n 'New to app skills? Run `canary application skill guide` for the authoring methodology.',\n '',\n 'Sections:',\n ' ' + SECTIONS.join(', '),\n '',\n 'Notes:',\n ' --content @path reads content from a file (preferred for multi-line markdown)',\n ' --content \"text\" literal content string',\n ' Source defaults to \"cli\". Provide --source-id <repo@sha> for provenance.',\n '',\n 'Bundle.json shape for import:',\n ' { \"items\": [ { \"section\": S, \"itemKey\": K, \"itemLabel\": L, \"content\": \"...\" }, ... ] }',\n ].join('\\n')\n );\n}\n\nfunction readContent(value: string): string {\n if (value.startsWith('@')) {\n const path = value.slice(1);\n return readFileSync(path, 'utf8');\n }\n return value;\n}\n\nfunction isSection(s: string | undefined): s is Section {\n return !!s && (SECTIONS as readonly string[]).includes(s);\n}\n\nasync function handleList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationArg(argv);\n const section = getArgValue(argv, '--section');\n const format = getArgValue(argv, '--format') ?? (hasFlag(argv, '--json') ? 'json' : 'table');\n\n if (!propertyId) {\n console.error('Error: --application is required (alias: --property).');\n process.exit(1);\n }\n\n const result = await apiRequest<ListResponse>(\n apiUrl,\n token,\n 'GET',\n `/org/properties/${propertyId}/context`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n\n let items = result.data?.items ?? [];\n if (section) items = items.filter((i) => i.section === section);\n\n if (format === 'json') {\n console.log(JSON.stringify(items, null, 2));\n return;\n }\n\n if (items.length === 0) {\n console.log('(no items)');\n return;\n }\n\n const grouped = new Map<string, ContextItem[]>();\n for (const item of items) {\n const arr = grouped.get(item.section) ?? [];\n arr.push(item);\n grouped.set(item.section, arr);\n }\n\n for (const sec of SECTIONS) {\n const arr = grouped.get(sec);\n if (!arr || arr.length === 0) continue;\n console.log(`\\n[${sec}]`);\n for (const item of arr) {\n const provenance = item.source === 'cli' && item.sourceId ? ` (${item.sourceId})` : item.source !== 'cli' ? ` (${item.source})` : '';\n console.log(` ${item.itemKey} — ${item.itemLabel}${provenance}`);\n }\n }\n}\n\nasync function handleGet(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationArg(argv);\n const section = getArgValue(argv, '--section');\n const itemKey = getArgValue(argv, '--key');\n const versionArg = getArgValue(argv, '--version');\n const format = getArgValue(argv, '--format') ?? 'md';\n\n if (!propertyId || !section || !itemKey) {\n console.error('Error: --application, --section, --key are required.');\n process.exit(1);\n }\n if (!isSection(section)) {\n console.error(`Error: invalid section \"${section}\". One of: ${SECTIONS.join(', ')}`);\n process.exit(1);\n }\n\n // Current value comes from list; specific version from history.\n if (versionArg) {\n const v = Number(versionArg);\n const result = await apiRequest<{ ok: boolean; error?: string; data?: ContextItem[] }>(\n apiUrl,\n token,\n 'GET',\n `/org/properties/${propertyId}/context/history?section=${section}&itemKey=${encodeURIComponent(itemKey)}`\n );\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n const item = (result.data ?? []).find((i) => i.version === v);\n if (!item) {\n console.error(`Error: no version ${v} for ${section}/${itemKey}`);\n process.exit(1);\n }\n printItem(item, format);\n return;\n }\n\n const result = await apiRequest<ListResponse>(\n apiUrl,\n token,\n 'GET',\n `/org/properties/${propertyId}/context`\n );\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n const item = (result.data?.items ?? []).find(\n (i) => i.section === section && i.itemKey === itemKey\n );\n if (!item) {\n console.error(`Error: no item ${section}/${itemKey}`);\n process.exit(1);\n }\n printItem(item, format);\n}\n\nfunction printItem(item: ContextItem, format: string): void {\n if (format === 'json') {\n console.log(JSON.stringify(item, null, 2));\n return;\n }\n console.log(`# ${item.itemLabel}`);\n console.log(`section: ${item.section}`);\n console.log(`key: ${item.itemKey}`);\n console.log(`version: ${item.version}`);\n console.log(`source: ${item.source}${item.sourceId ? ` (${item.sourceId})` : ''}`);\n console.log('');\n console.log(item.content);\n}\n\nasync function handleSet(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationArg(argv);\n const section = getArgValue(argv, '--section');\n const itemKey = getArgValue(argv, '--key');\n const itemLabel = getArgValue(argv, '--label');\n const contentArg = getArgValue(argv, '--content');\n const sourceId = getArgValue(argv, '--source-id');\n\n if (!propertyId || !section || !itemKey || !itemLabel || contentArg === undefined) {\n console.error('Error: --application, --section, --key, --label, --content are required.');\n process.exit(1);\n }\n if (!isSection(section)) {\n console.error(`Error: invalid section \"${section}\". One of: ${SECTIONS.join(', ')}`);\n process.exit(1);\n }\n\n const content = readContent(contentArg);\n\n const body: Record<string, unknown> = {\n section,\n itemKey,\n itemLabel,\n content,\n source: 'cli',\n };\n if (sourceId !== undefined) body.sourceId = sourceId;\n\n const result = await apiRequest<{ ok: boolean; error?: string; data?: ContextItem }>(\n apiUrl,\n token,\n 'PUT',\n `/org/properties/${propertyId}/context/items`,\n body\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n\n console.log(`Set [${section}] ${itemKey} (v${result.data?.version ?? '?'})`);\n}\n\nasync function handleDelete(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationArg(argv);\n const section = getArgValue(argv, '--section');\n const itemKey = getArgValue(argv, '--key');\n\n if (!propertyId || !section || !itemKey) {\n console.error('Error: --application, --section, --key are required.');\n process.exit(1);\n }\n if (!isSection(section)) {\n console.error(`Error: invalid section \"${section}\". One of: ${SECTIONS.join(', ')}`);\n process.exit(1);\n }\n\n const result = await apiRequest<{ ok: boolean; error?: string }>(\n apiUrl,\n token,\n 'DELETE',\n `/org/properties/${propertyId}/context/items`,\n { section, itemKey }\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n\n console.log(`Deleted [${section}] ${itemKey}`);\n}\n\nasync function handleHistory(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationArg(argv);\n const section = getArgValue(argv, '--section');\n const itemKey = getArgValue(argv, '--key');\n const format = getArgValue(argv, '--format') ?? 'table';\n\n if (!propertyId || !section || !itemKey) {\n console.error('Error: --application, --section, --key are required.');\n process.exit(1);\n }\n if (!isSection(section)) {\n console.error(`Error: invalid section \"${section}\". One of: ${SECTIONS.join(', ')}`);\n process.exit(1);\n }\n\n const result = await apiRequest<{ ok: boolean; error?: string; data?: ContextItem[] }>(\n apiUrl,\n token,\n 'GET',\n `/org/properties/${propertyId}/context/history?section=${section}&itemKey=${encodeURIComponent(itemKey)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n\n const versions = result.data ?? [];\n if (format === 'json') {\n console.log(JSON.stringify(versions, null, 2));\n return;\n }\n if (versions.length === 0) {\n console.log('(no history)');\n return;\n }\n for (const v of versions) {\n const provenance = v.sourceId ? ` (${v.sourceId})` : '';\n console.log(`v${v.version} ${v.source}${provenance} ${v.createdAt}`);\n }\n}\n\nasync function handleExport(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationArg(argv);\n const format = getArgValue(argv, '--format') ?? 'md';\n\n if (!propertyId) {\n console.error('Error: --application is required (alias: --property).');\n process.exit(1);\n }\n\n const result = await apiRequest<ListResponse>(\n apiUrl,\n token,\n 'GET',\n `/org/properties/${propertyId}/context`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'Unknown error'}`);\n process.exit(1);\n }\n\n const items = result.data?.items ?? [];\n if (format === 'json') {\n console.log(JSON.stringify({ items }, null, 2));\n return;\n }\n\n const grouped = new Map<string, ContextItem[]>();\n for (const item of items) {\n const arr = grouped.get(item.section) ?? [];\n arr.push(item);\n grouped.set(item.section, arr);\n }\n for (const sec of SECTIONS) {\n const arr = grouped.get(sec);\n if (!arr || arr.length === 0) continue;\n console.log(`## ${sec}`);\n console.log('');\n for (const item of arr) {\n console.log(`### ${item.itemLabel} (\\`${item.itemKey}\\`)`);\n console.log('');\n console.log(item.content);\n console.log('');\n }\n }\n}\n\ntype BundleItem = { section: string; itemKey: string; itemLabel: string; content: string };\ntype Bundle = { items: BundleItem[] };\n\nasync function handleImport(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationArg(argv);\n const file = getArgValue(argv, '--file');\n const sourceId = getArgValue(argv, '--source-id');\n\n if (!propertyId || !file) {\n console.error('Error: --application and --file are required.');\n process.exit(1);\n }\n\n let bundle: Bundle;\n try {\n bundle = JSON.parse(readFileSync(file, 'utf8')) as Bundle;\n } catch (err) {\n console.error(`Error parsing ${file}: ${(err as Error).message}`);\n process.exit(1);\n return;\n }\n\n if (!bundle.items || !Array.isArray(bundle.items)) {\n console.error('Error: bundle.json must have an \"items\" array.');\n process.exit(1);\n }\n\n let ok = 0;\n let fail = 0;\n for (const item of bundle.items) {\n if (!isSection(item.section)) {\n console.error(` ✗ [${item.section}] ${item.itemKey}: invalid section`);\n fail++;\n continue;\n }\n const body: Record<string, unknown> = {\n section: item.section,\n itemKey: item.itemKey,\n itemLabel: item.itemLabel,\n content: item.content,\n source: 'cli',\n };\n if (sourceId) body.sourceId = sourceId;\n\n const result = await apiRequest<{ ok: boolean; error?: string; data?: ContextItem }>(\n apiUrl,\n token,\n 'PUT',\n `/org/properties/${propertyId}/context/items`,\n body\n );\n\n if (result.ok) {\n console.log(` ✓ [${item.section}] ${item.itemKey} (v${result.data?.version ?? '?'})`);\n ok++;\n } else {\n console.error(` ✗ [${item.section}] ${item.itemKey}: ${result.error ?? 'Unknown error'}`);\n fail++;\n }\n }\n\n console.log(`\\nImported ${ok}/${ok + fail} items${fail ? ` (${fail} failed)` : ''}.`);\n if (fail > 0) process.exit(1);\n}\n\nfunction handleGuide(): void {\n try {\n const guide = readFileSync(GUIDE_PATH, 'utf8');\n process.stdout.write(guide);\n if (!guide.endsWith('\\n')) process.stdout.write('\\n');\n } catch (err) {\n console.error(`Error: could not read authoring guide at ${GUIDE_PATH}`);\n console.error((err as Error).message);\n process.exit(1);\n }\n}\n\nexport async function runPropertySkill(argv: string[], apiUrl: string, token: string): Promise<void> {\n const [action, ...rest] = argv;\n\n if (!action || action === 'help' || hasFlag(argv, '--help', '-h')) {\n printSkillHelp();\n return;\n }\n\n switch (action) {\n case 'guide':\n handleGuide();\n return;\n case 'list':\n await handleList(rest, apiUrl, token);\n break;\n case 'get':\n await handleGet(rest, apiUrl, token);\n break;\n case 'set':\n await handleSet(rest, apiUrl, token);\n break;\n case 'delete':\n await handleDelete(rest, apiUrl, token);\n break;\n case 'history':\n await handleHistory(rest, apiUrl, token);\n break;\n case 'export':\n await handleExport(rest, apiUrl, token);\n break;\n case 'import':\n await handleImport(rest, apiUrl, token);\n break;\n default:\n console.error(`Unknown skill action: ${action}`);\n printSkillHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["process","result","item","handleList","process"]}
|
|
@@ -4,7 +4,8 @@ import {
|
|
|
4
4
|
} from "./chunk-3CZU7XCS.js";
|
|
5
5
|
import {
|
|
6
6
|
resolveConfig
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-PZ4LCN6K.js";
|
|
8
|
+
import "./chunk-JZMJUPZP.js";
|
|
8
9
|
import "./chunk-VKVL7WBN.js";
|
|
9
10
|
|
|
10
11
|
// src/psql.ts
|
|
@@ -112,4 +113,4 @@ Time: ${json.durationMs}ms`);
|
|
|
112
113
|
export {
|
|
113
114
|
runPsql
|
|
114
115
|
};
|
|
115
|
-
//# sourceMappingURL=psql-
|
|
116
|
+
//# sourceMappingURL=psql-VBZFCMNR.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/psql.ts"],"sourcesContent":["/**\n * CLI PSQL Passthrough\n *\n * Allows superadmins to execute read-only SQL queries against the production database.\n */\n\nimport process from \"node:process\";\nimport { resolveConfig } from \"./auth.js\";\nimport { fetchOrExit } from \"./api-fetch.js\";\n\nconst MAX_QUERY_SIZE = 10_000; // 10KB - reasonable for interactive use\n\ntype PsqlResponse = {\n ok: boolean;\n data?: Record<string, unknown>[];\n rowCount?: number;\n truncated?: boolean;\n durationMs?: number;\n error?: string;\n};\n\nfunction getArgValue(argv: string[], key: string): string | undefined {\n const index = argv.indexOf(key);\n if (index === -1 || index >= argv.length - 1) return undefined;\n return argv[index + 1];\n}\n\nfunction hasFlag(argv: string[], ...flags: string[]): boolean {\n return flags.some((flag) => argv.includes(flag));\n}\n\n/**\n * Formats query results as a psql-style table.\n */\nfunction formatTable(data: Record<string, unknown>[]): string {\n if (data.length === 0) return \"(0 rows)\";\n\n const columns = Object.keys(data[0]);\n\n // Calculate column widths\n const widths = columns.map((col) =>\n Math.max(col.length, ...data.map((row) => String(row[col] ?? \"\").length))\n );\n\n // Build header\n const header = columns.map((col, i) => col.padEnd(widths[i])).join(\" | \");\n const separator = widths.map((w) => \"-\".repeat(w)).join(\"-+-\");\n\n // Build rows\n const rows = data.map((row) =>\n columns.map((col, i) => String(row[col] ?? \"\").padEnd(widths[i])).join(\" | \")\n );\n\n return [header, separator, ...rows, `(${data.length} rows)`].join(\"\\n\");\n}\n\nexport async function runPsql(argv: string[]): Promise<void> {\n const { apiUrl, token } = await resolveConfig(argv);\n\n const jsonOutput = hasFlag(argv, \"--json\");\n\n // Get query: either --query value or remaining args joined\n let query = getArgValue(argv, \"--query\");\n if (!query) {\n // Filter out flags and their values\n const flagsWithValues = [\"--api-url\", \"--token\", \"--query\", \"--env\"];\n const queryParts: string[] = [];\n for (let i = 0; i < argv.length; i++) {\n if (flagsWithValues.includes(argv[i])) {\n i++; // Skip flag value\n continue;\n }\n if (argv[i].startsWith(\"--\")) continue;\n queryParts.push(argv[i]);\n }\n query = queryParts.join(\" \");\n }\n\n if (!query) {\n console.error(\"Error: No query provided.\");\n console.error(\"\");\n console.error(\"Usage: canary psql <query> [--json]\");\n console.error(' canary psql --query \"SELECT * FROM users LIMIT 10\"');\n console.error(\"\");\n console.error(\"Examples:\");\n console.error(\" canary psql SELECT id, status FROM jobs LIMIT 5\");\n console.error(' canary psql \"SELECT * FROM jobs WHERE status = \\'running\\'\" --json');\n process.exit(1);\n }\n\n if (query.length > MAX_QUERY_SIZE) {\n console.error(`Error: Query too large (${query.length} chars, max ${MAX_QUERY_SIZE})`);\n console.error(\"For large queries, consider using psql directly with appropriate credentials.\");\n process.exit(1);\n }\n\n try {\n const res = await fetchOrExit(`${apiUrl}/superadmin/psql`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n token,\n body: JSON.stringify({ query }),\n });\n\n // Handle HTTP errors before parsing JSON\n if (!res.ok) {\n const text = await res.text();\n\n if (res.status === 404) {\n console.error(\"Error: Endpoint not found. The psql feature may not be deployed to this environment.\");\n process.exit(1);\n }\n\n // Try to parse error as JSON, fallback to raw text\n try {\n const errorJson = JSON.parse(text) as { error?: string };\n console.error(`Error: ${errorJson.error ?? text}`);\n } catch {\n console.error(`Error (${res.status}): ${text || res.statusText}`);\n }\n process.exit(1);\n }\n\n const json = (await res.json()) as PsqlResponse;\n\n if (!json.ok) {\n console.error(`Error: ${json.error}`);\n process.exit(1);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(json.data, null, 2));\n } else {\n console.log(formatTable(json.data ?? []));\n if (json.truncated) {\n console.log(`\\nNote: Results truncated to ${json.rowCount} rows`);\n }\n console.log(`\\nTime: ${json.durationMs}ms`);\n }\n } catch (err) {\n console.error(`Failed to execute query: ${err}`);\n process.exit(1);\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/psql.ts"],"sourcesContent":["/**\n * CLI PSQL Passthrough\n *\n * Allows superadmins to execute read-only SQL queries against the production database.\n */\n\nimport process from \"node:process\";\nimport { resolveConfig } from \"./auth.js\";\nimport { fetchOrExit } from \"./api-fetch.js\";\n\nconst MAX_QUERY_SIZE = 10_000; // 10KB - reasonable for interactive use\n\ntype PsqlResponse = {\n ok: boolean;\n data?: Record<string, unknown>[];\n rowCount?: number;\n truncated?: boolean;\n durationMs?: number;\n error?: string;\n};\n\nfunction getArgValue(argv: string[], key: string): string | undefined {\n const index = argv.indexOf(key);\n if (index === -1 || index >= argv.length - 1) return undefined;\n return argv[index + 1];\n}\n\nfunction hasFlag(argv: string[], ...flags: string[]): boolean {\n return flags.some((flag) => argv.includes(flag));\n}\n\n/**\n * Formats query results as a psql-style table.\n */\nfunction formatTable(data: Record<string, unknown>[]): string {\n if (data.length === 0) return \"(0 rows)\";\n\n const columns = Object.keys(data[0]);\n\n // Calculate column widths\n const widths = columns.map((col) =>\n Math.max(col.length, ...data.map((row) => String(row[col] ?? \"\").length))\n );\n\n // Build header\n const header = columns.map((col, i) => col.padEnd(widths[i])).join(\" | \");\n const separator = widths.map((w) => \"-\".repeat(w)).join(\"-+-\");\n\n // Build rows\n const rows = data.map((row) =>\n columns.map((col, i) => String(row[col] ?? \"\").padEnd(widths[i])).join(\" | \")\n );\n\n return [header, separator, ...rows, `(${data.length} rows)`].join(\"\\n\");\n}\n\nexport async function runPsql(argv: string[]): Promise<void> {\n const { apiUrl, token } = await resolveConfig(argv);\n\n const jsonOutput = hasFlag(argv, \"--json\");\n\n // Get query: either --query value or remaining args joined\n let query = getArgValue(argv, \"--query\");\n if (!query) {\n // Filter out flags and their values\n const flagsWithValues = [\"--api-url\", \"--token\", \"--query\", \"--env\"];\n const queryParts: string[] = [];\n for (let i = 0; i < argv.length; i++) {\n if (flagsWithValues.includes(argv[i])) {\n i++; // Skip flag value\n continue;\n }\n if (argv[i].startsWith(\"--\")) continue;\n queryParts.push(argv[i]);\n }\n query = queryParts.join(\" \");\n }\n\n if (!query) {\n console.error(\"Error: No query provided.\");\n console.error(\"\");\n console.error(\"Usage: canary psql <query> [--json]\");\n console.error(' canary psql --query \"SELECT * FROM users LIMIT 10\"');\n console.error(\"\");\n console.error(\"Examples:\");\n console.error(\" canary psql SELECT id, status FROM jobs LIMIT 5\");\n console.error(' canary psql \"SELECT * FROM jobs WHERE status = \\'running\\'\" --json');\n process.exit(1);\n }\n\n if (query.length > MAX_QUERY_SIZE) {\n console.error(`Error: Query too large (${query.length} chars, max ${MAX_QUERY_SIZE})`);\n console.error(\"For large queries, consider using psql directly with appropriate credentials.\");\n process.exit(1);\n }\n\n try {\n const res = await fetchOrExit(`${apiUrl}/superadmin/psql`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n token,\n body: JSON.stringify({ query }),\n });\n\n // Handle HTTP errors before parsing JSON\n if (!res.ok) {\n const text = await res.text();\n\n if (res.status === 404) {\n console.error(\"Error: Endpoint not found. The psql feature may not be deployed to this environment.\");\n process.exit(1);\n }\n\n // Try to parse error as JSON, fallback to raw text\n try {\n const errorJson = JSON.parse(text) as { error?: string };\n console.error(`Error: ${errorJson.error ?? text}`);\n } catch {\n console.error(`Error (${res.status}): ${text || res.statusText}`);\n }\n process.exit(1);\n }\n\n const json = (await res.json()) as PsqlResponse;\n\n if (!json.ok) {\n console.error(`Error: ${json.error}`);\n process.exit(1);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(json.data, null, 2));\n } else {\n console.log(formatTable(json.data ?? []));\n if (json.truncated) {\n console.log(`\\nNote: Results truncated to ${json.rowCount} rows`);\n }\n console.log(`\\nTime: ${json.durationMs}ms`);\n }\n } catch (err) {\n console.error(`Failed to execute query: ${err}`);\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
|
+
import "./chunk-G4UYGRZR.js";
|
|
2
3
|
import {
|
|
3
4
|
INTERACTION_CAPTURE_SCRIPT
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-5GD47G2D.js";
|
|
5
6
|
import {
|
|
6
7
|
apiRequest,
|
|
7
8
|
downloadStorageState,
|
|
8
9
|
selectCredential
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-SJJW77WN.js";
|
|
10
|
+
} from "./chunk-CQE46HSM.js";
|
|
11
11
|
import "./chunk-3CZU7XCS.js";
|
|
12
12
|
import {
|
|
13
13
|
getArgValue,
|
|
14
14
|
hasFlag,
|
|
15
15
|
resolveConfig
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-PZ4LCN6K.js";
|
|
17
|
+
import "./chunk-JZMJUPZP.js";
|
|
17
18
|
import {
|
|
18
19
|
getCanaryTmpDir
|
|
19
20
|
} from "./chunk-JWHYXEA2.js";
|
|
21
|
+
import "./chunk-QGI4UCJX.js";
|
|
20
22
|
import "./chunk-VKVL7WBN.js";
|
|
21
23
|
|
|
22
24
|
// src/record.ts
|
|
@@ -70,24 +72,21 @@ async function runRecord(argv) {
|
|
|
70
72
|
console.warn("Could not download storage state, continuing without it.");
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
);
|
|
81
|
-
loginUrl = detail.credential?.loginUrl ?? void 0;
|
|
82
|
-
}
|
|
75
|
+
const detail = await apiRequest(
|
|
76
|
+
config.apiUrl,
|
|
77
|
+
config.token,
|
|
78
|
+
"GET",
|
|
79
|
+
`/org/properties/${propertyId}/credentials/${credential.id}`
|
|
80
|
+
);
|
|
81
|
+
const loginUrl = detail.credential?.loginUrl ?? void 0;
|
|
83
82
|
const navigateUrl = startUrl ?? loginUrl;
|
|
84
83
|
if (!navigateUrl) {
|
|
85
84
|
console.warn(
|
|
86
|
-
"No start URL provided and no
|
|
85
|
+
"No start URL provided and the application has no environment URL. Browser will open to about:blank."
|
|
87
86
|
);
|
|
88
87
|
}
|
|
89
88
|
console.log("Launching browser...");
|
|
90
|
-
const { PlaywrightClient, consoleLogger, captureElementAtPoint } = await import("./src-
|
|
89
|
+
const { PlaywrightClient, consoleLogger, captureElementAtPoint } = await import("./src-NCJPUAE6.js");
|
|
91
90
|
const client = new PlaywrightClient({ logger: consoleLogger });
|
|
92
91
|
await client.connect({
|
|
93
92
|
browserMode: "headed",
|
|
@@ -230,4 +229,4 @@ Output directory: ${outDir}`);
|
|
|
230
229
|
export {
|
|
231
230
|
runRecord
|
|
232
231
|
};
|
|
233
|
-
//# sourceMappingURL=record-
|
|
232
|
+
//# sourceMappingURL=record-WAO36O7G.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/record.ts"],"sourcesContent":["/**\n * `canary record` — Record browser interactions for flow creation.\n *\n * Launches a headed browser, injects an in-page capture script,\n * and records user interactions (clicks, inputs, navigation) enriched\n * with accessibility snapshots and element info. On stop, bundles\n * everything as JSONL + video and uploads to the API.\n *\n * @module record\n */\n\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { getCanaryTmpDir } from '@chatsdet/tmp';\nimport process from 'node:process';\nimport { resolveConfig, getArgValue, hasFlag } from './auth.js';\nimport { apiRequest, selectCredential, downloadStorageState } from './cli-helpers.js';\n\nimport { INTERACTION_CAPTURE_SCRIPT } from './record-interaction-script.js';\nimport type { CapturedInteractionEvent } from './session/types.js';\n\n/** Recording event — uses the shared CapturedInteractionEvent type. */\ntype RecordingEvent = CapturedInteractionEvent;\n\n/** Click event narrowing helper for enrichment. */\ntype RecordingClickEvent = Extract<CapturedInteractionEvent, { type: 'click' }>;\n\ninterface CredentialDetail {\n id: string;\n name: string;\n loginUrl?: string;\n storageStateS3Key?: string | null;\n}\n\nexport async function runRecord(argv: string[]): Promise<void> {\n if (hasFlag(argv, '--help', '-h')) {\n console.log(\n [\n 'Usage: canary record [options]',\n '',\n 'Record browser interactions for flow creation.',\n '',\n 'Options:',\n ' --credential <id> Credential ID (skip interactive selection)',\n ' --url <startUrl> URL to navigate to after launch',\n ' --output <dir> Local output directory (default: temp dir)',\n ' --env <env> Environment (local, dev, prod)',\n ' --no-upload Save locally only, skip API upload',\n '',\n 'Press Ctrl+C to stop recording.',\n ].join('\\n')\n );\n return;\n }\n\n const config = await resolveConfig(argv);\n const credentialArg = getArgValue(argv, '--credential');\n const startUrl = getArgValue(argv, '--url');\n const outputDir = getArgValue(argv, '--output');\n const skipUpload = hasFlag(argv, '--no-upload');\n\n // 1. Fetch and select credential\n console.log('Fetching credentials...');\n const credential = await selectCredential(config.apiUrl, config.token, credentialArg);\n if (!credential) {\n process.exit(1);\n }\n\n console.log(`Using credential: ${credential.name}`);\n\n const propertyId = credential.propertyId;\n\n // 3. Download storage state if available\n let storageStatePath: string | undefined;\n if (credential.storageStateS3Key) {\n console.log('Downloading storage state...');\n storageStatePath = await downloadStorageState({\n apiUrl: config.apiUrl,\n token: config.token,\n propertyId: credential.propertyId,\n credentialId: credential.id,\n });\n if (storageStatePath) {\n console.log('Storage state loaded.');\n } else {\n console.warn('Could not download storage state, continuing without it.');\n }\n }\n\n // 4. Get credential detail — its loginUrl is the resolved login start URL\n // (environment URL + the application's relative login path).\n const detail = await apiRequest<{ ok: boolean; credential?: CredentialDetail }>(\n config.apiUrl,\n config.token,\n 'GET',\n `/org/properties/${propertyId}/credentials/${credential.id}`\n );\n const loginUrl = detail.credential?.loginUrl ?? undefined;\n\n // 5. Determine start URL\n const navigateUrl = startUrl ?? loginUrl;\n if (!navigateUrl) {\n console.warn(\n 'No start URL provided and the application has no environment URL. Browser will open to about:blank.'\n );\n }\n\n // 6. Launch browser\n console.log('Launching browser...');\n\n // Lazy-load playwright-dependent modules\n const { PlaywrightClient, consoleLogger, captureElementAtPoint } =\n await import('@chatsdet/browser-core');\n\n const client = new PlaywrightClient({ logger: consoleLogger });\n await client.connect({\n browserMode: 'headed',\n storageStatePath,\n recordVideo: true,\n });\n\n const page = await client.getPageForReplay();\n if (!page) {\n console.error('Failed to get browser page.');\n await client.disconnect();\n process.exit(1);\n }\n\n // 7. Inject interaction capture script\n await page.addInitScript(INTERACTION_CAPTURE_SCRIPT);\n await page.evaluate(INTERACTION_CAPTURE_SCRIPT);\n\n // 8. Navigate\n if (navigateUrl) {\n console.log(`Navigating to ${navigateUrl}`);\n await page.goto(navigateUrl, { waitUntil: 'domcontentloaded', timeout: 30_000 }).catch(() => {\n console.warn('Navigation timed out or failed, continuing anyway.');\n });\n }\n\n const events: RecordingEvent[] = [];\n let running = true;\n\n // Emit initial-url event so we know the starting page\n const currentUrl = page.url();\n const initialUrlEvent: RecordingEvent = {\n type: 'initial-url',\n ts: Date.now(),\n url: currentUrl,\n };\n try {\n const snapshot = await page.ariaSnapshot({ mode: 'ai' });\n (initialUrlEvent as { snapshot?: string }).snapshot = snapshot;\n } catch {\n // Snapshot may fail\n }\n events.push(initialUrlEvent);\n process.stdout.write(` [${events.length}] initial-url → ${currentUrl}\\n`);\n\n console.log('\\nRecording started. Interact with the browser.');\n console.log('Press Ctrl+C to stop recording.\\n');\n\n // 9. Poll loop — collect events from the page\n const pollInterval = setInterval(async () => {\n if (!running) return;\n try {\n const raw = await page.evaluate(() => {\n const evts =\n (window as unknown as { __canaryRecordedEvents?: unknown[] }).__canaryRecordedEvents ??\n [];\n (window as unknown as { __canaryRecordedEvents: unknown[] }).__canaryRecordedEvents = [];\n return evts;\n });\n\n if (!Array.isArray(raw) || raw.length === 0) return;\n\n for (const evt of raw as RecordingEvent[]) {\n // Enrich click events with element info and periodic snapshots\n if (evt.type === 'click') {\n const clickEvt = evt as RecordingClickEvent;\n try {\n const info = await captureElementAtPoint(page, clickEvt.x, clickEvt.y);\n if (info) {\n clickEvt.elementInfo = info as unknown as Record<string, unknown>;\n }\n } catch {\n // Element may have disappeared\n }\n\n // Snapshot every click for full page context\n try {\n const snapshot = await page.ariaSnapshot({ mode: 'ai' });\n clickEvt.snapshot = snapshot;\n } catch {\n // Snapshot may fail during navigation\n }\n }\n\n // Enrich navigation events with snapshot\n if (evt.type === 'navigation') {\n try {\n const snapshot = await page.ariaSnapshot({ mode: 'ai' });\n (evt as { snapshot?: string }).snapshot = snapshot;\n } catch {\n // Snapshot may fail during navigation\n }\n }\n\n events.push(evt);\n const label =\n evt.type === 'click'\n ? `click (${(evt as RecordingClickEvent).tagName})`\n : evt.type === 'input'\n ? `input`\n : evt.type === 'change'\n ? `change (${(evt as { tagName: string }).tagName})`\n : evt.type === 'navigation'\n ? `navigation → ${(evt as { url: string }).url}`\n : evt.type === 'initial-url'\n ? `initial-url → ${(evt as { url: string }).url}`\n : `keydown: ${(evt as { key: string }).key}`;\n process.stdout.write(` [${events.length}] ${label}\\n`);\n }\n } catch {\n // Page may have been closed\n }\n }, 500);\n\n // 10. Handle Ctrl+C\n const cleanup = async () => {\n if (!running) return;\n running = false;\n clearInterval(pollInterval);\n\n console.log(`\\nRecording stopped. ${events.length} events captured.`);\n\n // Save video\n console.log('Saving video...');\n const videoResult = await client.saveVideo();\n await client.disconnect();\n\n // Clean up temp storage state\n if (storageStatePath) {\n await fs.unlink(storageStatePath).catch(() => {});\n }\n\n // Prepare output directory\n const outDir = outputDir ?? path.join(getCanaryTmpDir(), `canary-recording-${Date.now()}`);\n await fs.mkdir(outDir, { recursive: true });\n\n // Write events JSONL\n const eventsPath = path.join(outDir, 'events.jsonl');\n const lines = events.map((e) => JSON.stringify(e)).join('\\n');\n await fs.writeFile(eventsPath, lines, 'utf-8');\n console.log(`Events saved: ${eventsPath}`);\n\n // Copy video if available\n let videoPath: string | undefined;\n if (videoResult?.videoPath) {\n videoPath = path.join(outDir, 'video.webm');\n await fs.copyFile(videoResult.videoPath, videoPath);\n console.log(`Video saved: ${videoPath}`);\n }\n\n // Upload to API\n if (!skipUpload && events.length > 0) {\n console.log('Uploading recording...');\n try {\n const formData = new FormData();\n formData.append('propertyId', propertyId);\n formData.append('credentialId', credential.id);\n\n const eventsBlob = new Blob([lines], { type: 'application/x-ndjson' });\n formData.append('events', eventsBlob, 'events.jsonl');\n\n if (videoPath) {\n const videoBuffer = await fs.readFile(videoPath);\n const videoBlob = new Blob([videoBuffer], { type: 'video/webm' });\n formData.append('video', videoBlob, 'video.webm');\n }\n\n const res = await fetch(`${config.apiUrl}/org/recordings/upload`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${config.token}` },\n body: formData,\n });\n\n const json = (await res.json()) as {\n ok: boolean;\n recordingId?: string;\n error?: string;\n };\n\n if (json.ok) {\n console.log(`Recording uploaded. ID: ${json.recordingId}`);\n } else {\n console.error(`Upload failed: ${json.error ?? 'Unknown error'}`);\n }\n } catch (err) {\n console.error('Upload failed:', err instanceof Error ? err.message : err);\n }\n }\n\n console.log(`\\nOutput directory: ${outDir}`);\n process.exit(0);\n };\n\n process.on('SIGINT', () => void cleanup());\n process.on('SIGTERM', () => void cleanup());\n\n // Also stop if the page is closed\n page.on('close', () => void cleanup());\n}\n"],"mappings":"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","names":[]}
|
|
@@ -4,7 +4,8 @@ import {
|
|
|
4
4
|
} from "./chunk-3CZU7XCS.js";
|
|
5
5
|
import {
|
|
6
6
|
resolveConfig
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-PZ4LCN6K.js";
|
|
8
|
+
import "./chunk-JZMJUPZP.js";
|
|
8
9
|
import "./chunk-VKVL7WBN.js";
|
|
9
10
|
|
|
10
11
|
// src/redis.ts
|
|
@@ -113,4 +114,4 @@ Time: ${json_response.durationMs}ms`);
|
|
|
113
114
|
export {
|
|
114
115
|
runRedis
|
|
115
116
|
};
|
|
116
|
-
//# sourceMappingURL=redis-
|
|
117
|
+
//# sourceMappingURL=redis-DHZXHL4S.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/redis.ts"],"sourcesContent":["/**\n * CLI Redis Passthrough\n *\n * Allows superadmins to execute read-only Redis commands against the production cache.\n */\n\nimport process from \"node:process\";\nimport { resolveConfig } from \"./auth.js\";\nimport { fetchOrExit } from \"./api-fetch.js\";\n\nconst MAX_COMMAND_SIZE = 10_000; // 10KB - reasonable for interactive use\n\ntype RedisResponse = {\n ok: boolean;\n data?: unknown;\n durationMs?: number;\n error?: string;\n code?: \"DISABLED\" | \"BLOCKED\";\n};\n\nfunction getArgValue(argv: string[], key: string): string | undefined {\n const index = argv.indexOf(key);\n if (index === -1 || index >= argv.length - 1) return undefined;\n return argv[index + 1];\n}\n\nfunction hasFlag(argv: string[], ...flags: string[]): boolean {\n return flags.some((flag) => argv.includes(flag));\n}\n\n/**\n * Formats Redis response for display.\n */\nfunction formatOutput(data: unknown): string {\n if (data === null) {\n return \"(nil)\";\n }\n\n if (typeof data === \"string\") {\n return data;\n }\n\n if (typeof data === \"number\") {\n return `(integer) ${data}`;\n }\n\n if (Array.isArray(data)) {\n if (data.length === 0) {\n return \"(empty array)\";\n }\n return data\n .map((item, index) => `${index + 1}) ${formatOutput(item)}`)\n .join(\"\\n\");\n }\n\n if (typeof data === \"object\") {\n return JSON.stringify(data, null, 2);\n }\n\n return String(data);\n}\n\nexport async function runRedis(argv: string[]): Promise<void> {\n const { apiUrl, token } = await resolveConfig(argv);\n\n const jsonOutput = hasFlag(argv, \"--json\");\n\n // Get command: remaining args after filtering flags\n const flagsWithValues = [\"--api-url\", \"--token\", \"--env\"];\n const commandParts: string[] = [];\n for (let i = 0; i < argv.length; i++) {\n if (flagsWithValues.includes(argv[i])) {\n i++; // Skip flag value\n continue;\n }\n if (argv[i].startsWith(\"--\")) continue;\n commandParts.push(argv[i]);\n }\n const command = commandParts.join(\" \");\n\n if (!command) {\n console.error(\"Error: No command provided.\");\n console.error(\"\");\n console.error(\"Usage: canary redis <command> [--json]\");\n console.error(' canary redis KEYS \"job:*\"');\n console.error(\"\");\n console.error(\"Examples:\");\n console.error(\" canary redis PING\");\n console.error(\" canary redis INFO\");\n console.error(' canary redis KEYS \"job:*\"');\n console.error(' canary redis HGETALL \"job:123:status\"');\n console.error(' canary redis GET \"some:key\" --json');\n process.exit(1);\n }\n\n if (command.length > MAX_COMMAND_SIZE) {\n console.error(`Error: Command too large (${command.length} chars, max ${MAX_COMMAND_SIZE})`);\n process.exit(1);\n }\n\n try {\n const res = await fetchOrExit(`${apiUrl}/superadmin/redis`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n token,\n body: JSON.stringify({ command }),\n });\n\n // Handle HTTP errors before parsing JSON\n if (!res.ok) {\n const text = await res.text();\n\n if (res.status === 404) {\n console.error(\"Error: Endpoint not found. The redis feature may not be deployed to this environment.\");\n process.exit(1);\n }\n\n // Try to parse error as JSON, fallback to raw text\n try {\n const errorJson = JSON.parse(text) as { error?: string };\n console.error(`Error: ${errorJson.error ?? text}`);\n } catch {\n console.error(`Error (${res.status}): ${text || res.statusText}`);\n }\n process.exit(1);\n }\n\n const json_response = (await res.json()) as RedisResponse;\n\n if (!json_response.ok) {\n console.error(`Error: ${json_response.error}`);\n if (json_response.code === \"BLOCKED\") {\n console.error(\"The Redis debugging feature has been disabled due to this blocked command.\");\n }\n process.exit(1);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(json_response.data, null, 2));\n } else {\n console.log(formatOutput(json_response.data));\n console.log(`\\nTime: ${json_response.durationMs}ms`);\n }\n } catch (err) {\n console.error(`Failed to execute command: ${err}`);\n process.exit(1);\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/redis.ts"],"sourcesContent":["/**\n * CLI Redis Passthrough\n *\n * Allows superadmins to execute read-only Redis commands against the production cache.\n */\n\nimport process from \"node:process\";\nimport { resolveConfig } from \"./auth.js\";\nimport { fetchOrExit } from \"./api-fetch.js\";\n\nconst MAX_COMMAND_SIZE = 10_000; // 10KB - reasonable for interactive use\n\ntype RedisResponse = {\n ok: boolean;\n data?: unknown;\n durationMs?: number;\n error?: string;\n code?: \"DISABLED\" | \"BLOCKED\";\n};\n\nfunction getArgValue(argv: string[], key: string): string | undefined {\n const index = argv.indexOf(key);\n if (index === -1 || index >= argv.length - 1) return undefined;\n return argv[index + 1];\n}\n\nfunction hasFlag(argv: string[], ...flags: string[]): boolean {\n return flags.some((flag) => argv.includes(flag));\n}\n\n/**\n * Formats Redis response for display.\n */\nfunction formatOutput(data: unknown): string {\n if (data === null) {\n return \"(nil)\";\n }\n\n if (typeof data === \"string\") {\n return data;\n }\n\n if (typeof data === \"number\") {\n return `(integer) ${data}`;\n }\n\n if (Array.isArray(data)) {\n if (data.length === 0) {\n return \"(empty array)\";\n }\n return data\n .map((item, index) => `${index + 1}) ${formatOutput(item)}`)\n .join(\"\\n\");\n }\n\n if (typeof data === \"object\") {\n return JSON.stringify(data, null, 2);\n }\n\n return String(data);\n}\n\nexport async function runRedis(argv: string[]): Promise<void> {\n const { apiUrl, token } = await resolveConfig(argv);\n\n const jsonOutput = hasFlag(argv, \"--json\");\n\n // Get command: remaining args after filtering flags\n const flagsWithValues = [\"--api-url\", \"--token\", \"--env\"];\n const commandParts: string[] = [];\n for (let i = 0; i < argv.length; i++) {\n if (flagsWithValues.includes(argv[i])) {\n i++; // Skip flag value\n continue;\n }\n if (argv[i].startsWith(\"--\")) continue;\n commandParts.push(argv[i]);\n }\n const command = commandParts.join(\" \");\n\n if (!command) {\n console.error(\"Error: No command provided.\");\n console.error(\"\");\n console.error(\"Usage: canary redis <command> [--json]\");\n console.error(' canary redis KEYS \"job:*\"');\n console.error(\"\");\n console.error(\"Examples:\");\n console.error(\" canary redis PING\");\n console.error(\" canary redis INFO\");\n console.error(' canary redis KEYS \"job:*\"');\n console.error(' canary redis HGETALL \"job:123:status\"');\n console.error(' canary redis GET \"some:key\" --json');\n process.exit(1);\n }\n\n if (command.length > MAX_COMMAND_SIZE) {\n console.error(`Error: Command too large (${command.length} chars, max ${MAX_COMMAND_SIZE})`);\n process.exit(1);\n }\n\n try {\n const res = await fetchOrExit(`${apiUrl}/superadmin/redis`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n token,\n body: JSON.stringify({ command }),\n });\n\n // Handle HTTP errors before parsing JSON\n if (!res.ok) {\n const text = await res.text();\n\n if (res.status === 404) {\n console.error(\"Error: Endpoint not found. The redis feature may not be deployed to this environment.\");\n process.exit(1);\n }\n\n // Try to parse error as JSON, fallback to raw text\n try {\n const errorJson = JSON.parse(text) as { error?: string };\n console.error(`Error: ${errorJson.error ?? text}`);\n } catch {\n console.error(`Error (${res.status}): ${text || res.statusText}`);\n }\n process.exit(1);\n }\n\n const json_response = (await res.json()) as RedisResponse;\n\n if (!json_response.ok) {\n console.error(`Error: ${json_response.error}`);\n if (json_response.code === \"BLOCKED\") {\n console.error(\"The Redis debugging feature has been disabled due to this blocked command.\");\n }\n process.exit(1);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(json_response.data, null, 2));\n } else {\n console.log(formatOutput(json_response.data));\n console.log(`\\nTime: ${json_response.durationMs}ms`);\n }\n } catch (err) {\n console.error(`Failed to execute command: ${err}`);\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
getApplicationIdArg
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-SJJW77WN.js";
|
|
4
|
+
} from "./chunk-CQE46HSM.js";
|
|
6
5
|
import "./chunk-3CZU7XCS.js";
|
|
7
6
|
import {
|
|
8
7
|
getArgValue,
|
|
9
8
|
hasFlag,
|
|
10
9
|
resolveConfig
|
|
11
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PZ4LCN6K.js";
|
|
11
|
+
import "./chunk-JZMJUPZP.js";
|
|
12
12
|
import "./chunk-JWHYXEA2.js";
|
|
13
|
+
import "./chunk-QGI4UCJX.js";
|
|
13
14
|
import "./chunk-VKVL7WBN.js";
|
|
14
15
|
|
|
15
16
|
// src/release.ts
|
|
@@ -351,4 +352,4 @@ async function runRelease(argv) {
|
|
|
351
352
|
export {
|
|
352
353
|
runRelease
|
|
353
354
|
};
|
|
354
|
-
//# sourceMappingURL=release-
|
|
355
|
+
//# sourceMappingURL=release-STJKUKTE.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/release.ts"],"sourcesContent":["/**\n * CLI Release QA Management\n *\n * Trigger, poll, and check status of Release QA runs from CI/CD pipelines.\n * Used by the scheduled-release GitHub Actions workflow to gate deployments.\n */\n\nimport process from \"node:process\";\nimport { resolveConfig, getArgValue, hasFlag } from \"./auth.js\";\nimport { getApplicationIdArg } from \"./cli-helpers.js\";\n\ntype TriggerResponse = {\n ok: boolean;\n releaseRunId?: string;\n jobId?: string;\n error?: string;\n};\n\ntype RunStatusResponse = {\n ok: boolean;\n run?: {\n id: string;\n status: string;\n triggerSource: string;\n cutoffReason: string | null;\n fromSha: string | null;\n toSha: string | null;\n commitsAnalyzed: number;\n testersSpawned: number;\n testersCompleted: number;\n testersFailed: number;\n issuesFound: number;\n regressionTestsTotal: number;\n regressionTestsPassed: number;\n regressionTestsFailed: number;\n startedAt: string | null;\n finishedAt: string | null;\n createdAt: string;\n // Multi-repo: one entry per participating repo. Empty array for\n // single-repo/legacy runs; consumers fall back to top-level fromSha/toSha.\n repos?: Array<{\n repoFullName: string;\n fromSha: string;\n toSha: string;\n }>;\n };\n error?: string;\n};\n\n/** Terminal statuses that stop polling */\nconst TERMINAL_STATUSES = new Set([\n \"completed\",\n \"completed_with_errors\",\n \"failed\",\n \"canceled\",\n \"timeout\",\n]);\n\nasync function handleTrigger(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationIdArg(argv);\n if (!propertyId) {\n console.error(\"Error: Missing --application-id <uuid> (alias: --property-id).\");\n console.error(\n \"Usage: canary release trigger --application-id <uuid> [--credential-ids <uuid,...>] [--skip-regressions]\"\n );\n process.exit(1);\n }\n\n const skipRegressions = hasFlag(argv, \"--skip-regressions\");\n const credentialIdsRaw = getArgValue(argv, \"--credential-ids\");\n const body: Record<string, unknown> = { propertyId, runRegressions: !skipRegressions };\n if (credentialIdsRaw) {\n body.credentialIds = credentialIdsRaw.split(\",\").map((id) => id.trim());\n }\n\n if (skipRegressions) {\n console.warn(\n \"WARNING: --skip-regressions is set. The regression suite will NOT run if there are no new commits. Gate is degraded.\"\n );\n }\n\n const res = await fetch(`${apiUrl}/api/v1/release-qa/trigger`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Check your API token.\");\n process.exit(1);\n }\n\n const json = (await res.json()) as TriggerResponse;\n\n if (!json.ok) {\n console.error(`Error: ${json.error}`);\n process.exit(1);\n }\n\n console.log(`Release QA run triggered`);\n console.log(` Run ID: ${json.releaseRunId}`);\n console.log(` Job ID: ${json.jobId}`);\n}\n\nasync function fetchRunStatus(\n apiUrl: string,\n token: string,\n runId: string\n): Promise<RunStatusResponse> {\n const res = await fetch(`${apiUrl}/api/v1/release-qa/runs/${encodeURIComponent(runId)}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Check your API token.\");\n process.exit(1);\n }\n\n return (await res.json()) as RunStatusResponse;\n}\n\nasync function handleStatus(argv: string[], apiUrl: string, token: string): Promise<void> {\n const runId = argv[0];\n if (!runId || runId.startsWith(\"--\")) {\n console.error(\"Error: Missing run ID.\");\n console.error(\"Usage: canary release status <run-id>\");\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, \"--json\");\n const json = await fetchRunStatus(apiUrl, token, runId);\n\n if (!json.ok) {\n console.error(`Error: ${json.error}`);\n process.exit(1);\n }\n\n const run = json.run!;\n\n if (jsonOutput) {\n console.log(JSON.stringify(run, null, 2));\n return;\n }\n\n console.log(`Release QA Run: ${run.id}`);\n console.log(` Status: ${run.status}`);\n console.log(` Trigger: ${run.triggerSource}`);\n if (run.repos && run.repos.length > 0) {\n console.log(` Repositories:`);\n for (const r of run.repos) {\n const range =\n r.fromSha === r.toSha\n ? \"(no changes)\"\n : `${r.fromSha.slice(0, 7)}..${r.toSha.slice(0, 7)}`;\n console.log(` - ${r.repoFullName} ${range}`);\n }\n }\n console.log(` Commits analyzed: ${run.commitsAnalyzed}`);\n console.log(` Testers: ${run.testersCompleted}/${run.testersSpawned} completed, ${run.testersFailed} failed`);\n console.log(` Issues found: ${run.issuesFound}`);\n console.log(` Regression tests: ${run.regressionTestsPassed}/${run.regressionTestsTotal} passed, ${run.regressionTestsFailed} failed`);\n if (run.startedAt) console.log(` Started: ${run.startedAt}`);\n if (run.finishedAt) console.log(` Finished: ${run.finishedAt}`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function handleRun(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationIdArg(argv);\n if (!propertyId) {\n console.error(\"Error: Missing --application-id <uuid> (alias: --property-id).\");\n console.error(\n \"Usage: canary release run --application-id <uuid> [--timeout 3600] [--poll-interval 30] [--skip-regressions]\"\n );\n process.exit(1);\n }\n\n const timeoutSec = parseInt(getArgValue(argv, \"--timeout\") ?? \"3600\", 10);\n const pollIntervalSec = parseInt(getArgValue(argv, \"--poll-interval\") ?? \"30\", 10);\n const skipRegressions = hasFlag(argv, \"--skip-regressions\");\n\n const credentialIdsRaw = getArgValue(argv, \"--credential-ids\");\n const body: Record<string, unknown> = { propertyId, runRegressions: !skipRegressions };\n if (credentialIdsRaw) {\n body.credentialIds = credentialIdsRaw.split(\",\").map((id) => id.trim());\n }\n\n if (skipRegressions) {\n console.warn(\n \"WARNING: --skip-regressions is set. The regression suite will NOT run if there are no new commits. Deploy gate is degraded.\"\n );\n }\n\n // Trigger\n console.log(\"Triggering Release QA run...\");\n const triggerRes = await fetch(`${apiUrl}/api/v1/release-qa/trigger`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (triggerRes.status === 401) {\n console.error(\"Error: Unauthorized. Check your API token.\");\n process.exit(1);\n }\n\n const triggerJson = (await triggerRes.json()) as TriggerResponse;\n\n if (!triggerJson.ok) {\n console.error(`Error triggering run: ${triggerJson.error}`);\n process.exit(1);\n }\n\n const runId = triggerJson.releaseRunId!;\n console.log(`Run started: ${runId}`);\n\n // Poll\n const deadline = Date.now() + timeoutSec * 1000;\n let lastStatus = \"\";\n\n while (Date.now() < deadline) {\n await sleep(pollIntervalSec * 1000);\n\n let statusJson: RunStatusResponse;\n try {\n statusJson = await fetchRunStatus(apiUrl, token, runId);\n } catch (err) {\n console.error(`Warning: Failed to fetch status, retrying... (${err})`);\n continue;\n }\n\n if (!statusJson.ok) {\n console.error(`Error: ${statusJson.error}`);\n process.exit(1);\n }\n\n const run = statusJson.run!;\n const statusLine = `[${run.status}] testers: ${run.testersCompleted}/${run.testersSpawned}, regressions: ${run.regressionTestsPassed}/${run.regressionTestsTotal} passed`;\n\n if (run.status !== lastStatus) {\n console.log(statusLine);\n lastStatus = run.status;\n } else {\n // Print progress on same status change in metrics\n console.log(statusLine);\n }\n\n if (TERMINAL_STATUSES.has(run.status)) {\n console.log(\"\");\n console.log(`Run finished: ${run.status}`);\n console.log(` Testers: ${run.testersCompleted}/${run.testersSpawned} completed, ${run.testersFailed} failed`);\n console.log(` Regressions: ${run.regressionTestsPassed}/${run.regressionTestsTotal} passed, ${run.regressionTestsFailed} failed`);\n console.log(` Issues found: ${run.issuesFound}`);\n\n // Gate deployment on: (a) terminal status, (b) any regression failures,\n // (c) empty regression suite (unless explicitly opted out).\n // Non-regression signals (failed testers, issues, build errors) are\n // visible in the UI but intentionally do not gate the deploy.\n if (run.status === \"failed\" || run.status === \"canceled\" || run.status === \"timeout\") {\n console.error(`\\nRelease QA FAILED (${run.status})`);\n process.exit(1);\n }\n\n if (run.status === \"completed_with_errors\") {\n const suffix = run.cutoffReason ? `: ${run.cutoffReason}` : \"\";\n console.error(`\\nRelease QA FAILED (completed_with_errors${suffix})`);\n process.exit(1);\n }\n\n if (run.regressionTestsTotal === 0 && !skipRegressions) {\n console.error(\n \"\\nRelease QA FAILED (no regression tests executed — expected suite to run). \" +\n \"If this was intentional, re-run with --skip-regressions.\"\n );\n process.exit(1);\n }\n\n if (run.regressionTestsFailed === 0) {\n console.log(\n `\\nRelease QA PASSED (${run.regressionTestsPassed}/${run.regressionTestsTotal} regressions passed)`\n );\n process.exit(0);\n }\n\n console.error(`\\nRelease QA FAILED (${run.regressionTestsFailed} regression test(s) failed)`);\n process.exit(1);\n }\n }\n\n console.error(`\\nTimeout: Release QA did not complete within ${timeoutSec}s`);\n process.exit(1);\n}\n\n// ---------------------------------------------------------------------------\n// Deployment marking\n// ---------------------------------------------------------------------------\n\ntype MarkDeployResponse = {\n ok: boolean;\n deploymentId?: string;\n commitSha?: string;\n tasksTriggered?: number;\n error?: string;\n};\n\ntype LatestDeployResponse = {\n ok: boolean;\n deployment?: {\n id: string;\n commitSha: string;\n commitMessage: string | null;\n deployedBy: string;\n triggerSource: string;\n tasksTriggered: number;\n createdAt: string;\n } | null;\n error?: string;\n};\n\nasync function handleMarkDeploy(argv: string[], apiUrl: string, token: string): Promise<void> {\n const commitSha = getArgValue(argv, \"--commit\");\n const propertyId = getApplicationIdArg(argv);\n const commitMessage = getArgValue(argv, \"--message\");\n\n if (!commitSha) {\n console.error(\"Error: Missing --commit <sha>.\");\n console.error(\"Usage: canary release mark-deploy --commit <sha> --application-id <uuid> [--message \\\"...\\\"]\");\n process.exit(1);\n }\n if (!propertyId) {\n console.error(\"Error: Missing --application-id <uuid> (alias: --property-id).\");\n console.error(\"Usage: canary release mark-deploy --commit <sha> --application-id <uuid> [--message \\\"...\\\"]\");\n process.exit(1);\n }\n\n const body: Record<string, unknown> = { propertyId, commitSha };\n if (commitMessage) body.commitMessage = commitMessage;\n\n const res = await fetch(`${apiUrl}/api/v1/deployments/mark`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Check your API token.\");\n process.exit(1);\n }\n\n const json = (await res.json()) as MarkDeployResponse;\n\n if (!json.ok) {\n console.error(`Error: ${json.error}`);\n process.exit(1);\n }\n\n console.log(\"Deployment marked\");\n console.log(` Deployment ID: ${json.deploymentId}`);\n console.log(` Commit: ${json.commitSha}`);\n console.log(` Tasks triggered: ${json.tasksTriggered}`);\n}\n\nasync function handleLatestDeploy(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationIdArg(argv);\n if (!propertyId) {\n console.error(\"Error: Missing --application-id <uuid> (alias: --property-id).\");\n console.error(\"Usage: canary release latest-deploy --application-id <uuid> [--json]\");\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, \"--json\");\n\n const res = await fetch(\n `${apiUrl}/api/v1/deployments/latest?propertyId=${encodeURIComponent(propertyId)}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Check your API token.\");\n process.exit(1);\n }\n\n const data = (await res.json()) as LatestDeployResponse;\n\n if (!data.ok) {\n console.error(`Error: ${data.error}`);\n process.exit(1);\n }\n\n if (!data.deployment) {\n console.log(\"No deployments found for this application.\");\n return;\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(data.deployment, null, 2));\n return;\n }\n\n console.log(`Latest deployment:`);\n console.log(` ID: ${data.deployment.id}`);\n console.log(` Commit: ${data.deployment.commitSha}`);\n if (data.deployment.commitMessage) {\n console.log(` Message: ${data.deployment.commitMessage}`);\n }\n console.log(` Deployed by: ${data.deployment.deployedBy}`);\n console.log(` Source: ${data.deployment.triggerSource}`);\n console.log(` Tasks triggered: ${data.deployment.tasksTriggered}`);\n console.log(` Created: ${data.deployment.createdAt}`);\n}\n\n// ---------------------------------------------------------------------------\n// Help & routing\n// ---------------------------------------------------------------------------\n\nfunction printReleaseHelp(): void {\n console.log(\n [\n \"Usage: canary release <sub-command> [options]\",\n \"\",\n \"Sub-commands:\",\n \" trigger --application-id <uuid> [--credential-ids <uuid,...>]\",\n \" Trigger a Release QA run\",\n \" status <run-id> [--json] Check run status\",\n \" run --application-id <uuid> [options] Trigger and poll until complete\",\n \" mark-deploy --commit <sha> --application-id <uuid> [--message \\\"...\\\"]\",\n \" Mark a commit as deployed\",\n \" latest-deploy --application-id <uuid> [--json]\",\n \" Show latest deployment for an application\",\n \"\",\n \"Run options:\",\n \" --timeout <seconds> Max wait time (default: 3600)\",\n \" --poll-interval <secs> Poll frequency (default: 30)\",\n \" --credential-ids <ids> Comma-separated credential UUIDs\",\n \"\",\n \"Options:\",\n \" --env <env> Target environment (prod, dev, local)\",\n \" --api-url <url> API URL override\",\n \" --token <key> API token override (or set CANARY_API_TOKEN)\",\n ].join(\"\\n\")\n );\n}\n\nexport async function runRelease(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === \"help\" || hasFlag(argv, \"--help\", \"-h\")) {\n printReleaseHelp();\n return;\n }\n\n const { apiUrl, token } = await resolveConfig(argv);\n\n switch (subCommand) {\n case \"trigger\":\n await handleTrigger(rest, apiUrl, token);\n break;\n case \"status\":\n await handleStatus(rest, apiUrl, token);\n break;\n case \"run\":\n await handleRun(rest, apiUrl, token);\n break;\n case \"mark-deploy\":\n await handleMarkDeploy(rest, apiUrl, token);\n break;\n case \"latest-deploy\":\n await handleLatestDeploy(rest, apiUrl, token);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printReleaseHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/release.ts"],"sourcesContent":["/**\n * CLI Release QA Management\n *\n * Trigger, poll, and check status of Release QA runs from CI/CD pipelines.\n * Used by the scheduled-release GitHub Actions workflow to gate deployments.\n */\n\nimport process from \"node:process\";\nimport { resolveConfig, getArgValue, hasFlag } from \"./auth.js\";\nimport { getApplicationIdArg } from \"./cli-helpers.js\";\n\ntype TriggerResponse = {\n ok: boolean;\n releaseRunId?: string;\n jobId?: string;\n error?: string;\n};\n\ntype RunStatusResponse = {\n ok: boolean;\n run?: {\n id: string;\n status: string;\n triggerSource: string;\n cutoffReason: string | null;\n fromSha: string | null;\n toSha: string | null;\n commitsAnalyzed: number;\n testersSpawned: number;\n testersCompleted: number;\n testersFailed: number;\n issuesFound: number;\n regressionTestsTotal: number;\n regressionTestsPassed: number;\n regressionTestsFailed: number;\n startedAt: string | null;\n finishedAt: string | null;\n createdAt: string;\n // Multi-repo: one entry per participating repo. Empty array for\n // single-repo/legacy runs; consumers fall back to top-level fromSha/toSha.\n repos?: Array<{\n repoFullName: string;\n fromSha: string;\n toSha: string;\n }>;\n };\n error?: string;\n};\n\n/** Terminal statuses that stop polling */\nconst TERMINAL_STATUSES = new Set([\n \"completed\",\n \"completed_with_errors\",\n \"failed\",\n \"canceled\",\n \"timeout\",\n]);\n\nasync function handleTrigger(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationIdArg(argv);\n if (!propertyId) {\n console.error(\"Error: Missing --application-id <uuid> (alias: --property-id).\");\n console.error(\n \"Usage: canary release trigger --application-id <uuid> [--credential-ids <uuid,...>] [--skip-regressions]\"\n );\n process.exit(1);\n }\n\n const skipRegressions = hasFlag(argv, \"--skip-regressions\");\n const credentialIdsRaw = getArgValue(argv, \"--credential-ids\");\n const body: Record<string, unknown> = { propertyId, runRegressions: !skipRegressions };\n if (credentialIdsRaw) {\n body.credentialIds = credentialIdsRaw.split(\",\").map((id) => id.trim());\n }\n\n if (skipRegressions) {\n console.warn(\n \"WARNING: --skip-regressions is set. The regression suite will NOT run if there are no new commits. Gate is degraded.\"\n );\n }\n\n const res = await fetch(`${apiUrl}/api/v1/release-qa/trigger`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Check your API token.\");\n process.exit(1);\n }\n\n const json = (await res.json()) as TriggerResponse;\n\n if (!json.ok) {\n console.error(`Error: ${json.error}`);\n process.exit(1);\n }\n\n console.log(`Release QA run triggered`);\n console.log(` Run ID: ${json.releaseRunId}`);\n console.log(` Job ID: ${json.jobId}`);\n}\n\nasync function fetchRunStatus(\n apiUrl: string,\n token: string,\n runId: string\n): Promise<RunStatusResponse> {\n const res = await fetch(`${apiUrl}/api/v1/release-qa/runs/${encodeURIComponent(runId)}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Check your API token.\");\n process.exit(1);\n }\n\n return (await res.json()) as RunStatusResponse;\n}\n\nasync function handleStatus(argv: string[], apiUrl: string, token: string): Promise<void> {\n const runId = argv[0];\n if (!runId || runId.startsWith(\"--\")) {\n console.error(\"Error: Missing run ID.\");\n console.error(\"Usage: canary release status <run-id>\");\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, \"--json\");\n const json = await fetchRunStatus(apiUrl, token, runId);\n\n if (!json.ok) {\n console.error(`Error: ${json.error}`);\n process.exit(1);\n }\n\n const run = json.run!;\n\n if (jsonOutput) {\n console.log(JSON.stringify(run, null, 2));\n return;\n }\n\n console.log(`Release QA Run: ${run.id}`);\n console.log(` Status: ${run.status}`);\n console.log(` Trigger: ${run.triggerSource}`);\n if (run.repos && run.repos.length > 0) {\n console.log(` Repositories:`);\n for (const r of run.repos) {\n const range =\n r.fromSha === r.toSha\n ? \"(no changes)\"\n : `${r.fromSha.slice(0, 7)}..${r.toSha.slice(0, 7)}`;\n console.log(` - ${r.repoFullName} ${range}`);\n }\n }\n console.log(` Commits analyzed: ${run.commitsAnalyzed}`);\n console.log(` Testers: ${run.testersCompleted}/${run.testersSpawned} completed, ${run.testersFailed} failed`);\n console.log(` Issues found: ${run.issuesFound}`);\n console.log(` Regression tests: ${run.regressionTestsPassed}/${run.regressionTestsTotal} passed, ${run.regressionTestsFailed} failed`);\n if (run.startedAt) console.log(` Started: ${run.startedAt}`);\n if (run.finishedAt) console.log(` Finished: ${run.finishedAt}`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function handleRun(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationIdArg(argv);\n if (!propertyId) {\n console.error(\"Error: Missing --application-id <uuid> (alias: --property-id).\");\n console.error(\n \"Usage: canary release run --application-id <uuid> [--timeout 3600] [--poll-interval 30] [--skip-regressions]\"\n );\n process.exit(1);\n }\n\n const timeoutSec = parseInt(getArgValue(argv, \"--timeout\") ?? \"3600\", 10);\n const pollIntervalSec = parseInt(getArgValue(argv, \"--poll-interval\") ?? \"30\", 10);\n const skipRegressions = hasFlag(argv, \"--skip-regressions\");\n\n const credentialIdsRaw = getArgValue(argv, \"--credential-ids\");\n const body: Record<string, unknown> = { propertyId, runRegressions: !skipRegressions };\n if (credentialIdsRaw) {\n body.credentialIds = credentialIdsRaw.split(\",\").map((id) => id.trim());\n }\n\n if (skipRegressions) {\n console.warn(\n \"WARNING: --skip-regressions is set. The regression suite will NOT run if there are no new commits. Deploy gate is degraded.\"\n );\n }\n\n // Trigger\n console.log(\"Triggering Release QA run...\");\n const triggerRes = await fetch(`${apiUrl}/api/v1/release-qa/trigger`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (triggerRes.status === 401) {\n console.error(\"Error: Unauthorized. Check your API token.\");\n process.exit(1);\n }\n\n const triggerJson = (await triggerRes.json()) as TriggerResponse;\n\n if (!triggerJson.ok) {\n console.error(`Error triggering run: ${triggerJson.error}`);\n process.exit(1);\n }\n\n const runId = triggerJson.releaseRunId!;\n console.log(`Run started: ${runId}`);\n\n // Poll\n const deadline = Date.now() + timeoutSec * 1000;\n let lastStatus = \"\";\n\n while (Date.now() < deadline) {\n await sleep(pollIntervalSec * 1000);\n\n let statusJson: RunStatusResponse;\n try {\n statusJson = await fetchRunStatus(apiUrl, token, runId);\n } catch (err) {\n console.error(`Warning: Failed to fetch status, retrying... (${err})`);\n continue;\n }\n\n if (!statusJson.ok) {\n console.error(`Error: ${statusJson.error}`);\n process.exit(1);\n }\n\n const run = statusJson.run!;\n const statusLine = `[${run.status}] testers: ${run.testersCompleted}/${run.testersSpawned}, regressions: ${run.regressionTestsPassed}/${run.regressionTestsTotal} passed`;\n\n if (run.status !== lastStatus) {\n console.log(statusLine);\n lastStatus = run.status;\n } else {\n // Print progress on same status change in metrics\n console.log(statusLine);\n }\n\n if (TERMINAL_STATUSES.has(run.status)) {\n console.log(\"\");\n console.log(`Run finished: ${run.status}`);\n console.log(` Testers: ${run.testersCompleted}/${run.testersSpawned} completed, ${run.testersFailed} failed`);\n console.log(` Regressions: ${run.regressionTestsPassed}/${run.regressionTestsTotal} passed, ${run.regressionTestsFailed} failed`);\n console.log(` Issues found: ${run.issuesFound}`);\n\n // Gate deployment on: (a) terminal status, (b) any regression failures,\n // (c) empty regression suite (unless explicitly opted out).\n // Non-regression signals (failed testers, issues, build errors) are\n // visible in the UI but intentionally do not gate the deploy.\n if (run.status === \"failed\" || run.status === \"canceled\" || run.status === \"timeout\") {\n console.error(`\\nRelease QA FAILED (${run.status})`);\n process.exit(1);\n }\n\n if (run.status === \"completed_with_errors\") {\n const suffix = run.cutoffReason ? `: ${run.cutoffReason}` : \"\";\n console.error(`\\nRelease QA FAILED (completed_with_errors${suffix})`);\n process.exit(1);\n }\n\n if (run.regressionTestsTotal === 0 && !skipRegressions) {\n console.error(\n \"\\nRelease QA FAILED (no regression tests executed — expected suite to run). \" +\n \"If this was intentional, re-run with --skip-regressions.\"\n );\n process.exit(1);\n }\n\n if (run.regressionTestsFailed === 0) {\n console.log(\n `\\nRelease QA PASSED (${run.regressionTestsPassed}/${run.regressionTestsTotal} regressions passed)`\n );\n process.exit(0);\n }\n\n console.error(`\\nRelease QA FAILED (${run.regressionTestsFailed} regression test(s) failed)`);\n process.exit(1);\n }\n }\n\n console.error(`\\nTimeout: Release QA did not complete within ${timeoutSec}s`);\n process.exit(1);\n}\n\n// ---------------------------------------------------------------------------\n// Deployment marking\n// ---------------------------------------------------------------------------\n\ntype MarkDeployResponse = {\n ok: boolean;\n deploymentId?: string;\n commitSha?: string;\n tasksTriggered?: number;\n error?: string;\n};\n\ntype LatestDeployResponse = {\n ok: boolean;\n deployment?: {\n id: string;\n commitSha: string;\n commitMessage: string | null;\n deployedBy: string;\n triggerSource: string;\n tasksTriggered: number;\n createdAt: string;\n } | null;\n error?: string;\n};\n\nasync function handleMarkDeploy(argv: string[], apiUrl: string, token: string): Promise<void> {\n const commitSha = getArgValue(argv, \"--commit\");\n const propertyId = getApplicationIdArg(argv);\n const commitMessage = getArgValue(argv, \"--message\");\n\n if (!commitSha) {\n console.error(\"Error: Missing --commit <sha>.\");\n console.error(\"Usage: canary release mark-deploy --commit <sha> --application-id <uuid> [--message \\\"...\\\"]\");\n process.exit(1);\n }\n if (!propertyId) {\n console.error(\"Error: Missing --application-id <uuid> (alias: --property-id).\");\n console.error(\"Usage: canary release mark-deploy --commit <sha> --application-id <uuid> [--message \\\"...\\\"]\");\n process.exit(1);\n }\n\n const body: Record<string, unknown> = { propertyId, commitSha };\n if (commitMessage) body.commitMessage = commitMessage;\n\n const res = await fetch(`${apiUrl}/api/v1/deployments/mark`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Check your API token.\");\n process.exit(1);\n }\n\n const json = (await res.json()) as MarkDeployResponse;\n\n if (!json.ok) {\n console.error(`Error: ${json.error}`);\n process.exit(1);\n }\n\n console.log(\"Deployment marked\");\n console.log(` Deployment ID: ${json.deploymentId}`);\n console.log(` Commit: ${json.commitSha}`);\n console.log(` Tasks triggered: ${json.tasksTriggered}`);\n}\n\nasync function handleLatestDeploy(argv: string[], apiUrl: string, token: string): Promise<void> {\n const propertyId = getApplicationIdArg(argv);\n if (!propertyId) {\n console.error(\"Error: Missing --application-id <uuid> (alias: --property-id).\");\n console.error(\"Usage: canary release latest-deploy --application-id <uuid> [--json]\");\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, \"--json\");\n\n const res = await fetch(\n `${apiUrl}/api/v1/deployments/latest?propertyId=${encodeURIComponent(propertyId)}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Check your API token.\");\n process.exit(1);\n }\n\n const data = (await res.json()) as LatestDeployResponse;\n\n if (!data.ok) {\n console.error(`Error: ${data.error}`);\n process.exit(1);\n }\n\n if (!data.deployment) {\n console.log(\"No deployments found for this application.\");\n return;\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(data.deployment, null, 2));\n return;\n }\n\n console.log(`Latest deployment:`);\n console.log(` ID: ${data.deployment.id}`);\n console.log(` Commit: ${data.deployment.commitSha}`);\n if (data.deployment.commitMessage) {\n console.log(` Message: ${data.deployment.commitMessage}`);\n }\n console.log(` Deployed by: ${data.deployment.deployedBy}`);\n console.log(` Source: ${data.deployment.triggerSource}`);\n console.log(` Tasks triggered: ${data.deployment.tasksTriggered}`);\n console.log(` Created: ${data.deployment.createdAt}`);\n}\n\n// ---------------------------------------------------------------------------\n// Help & routing\n// ---------------------------------------------------------------------------\n\nfunction printReleaseHelp(): void {\n console.log(\n [\n \"Usage: canary release <sub-command> [options]\",\n \"\",\n \"Sub-commands:\",\n \" trigger --application-id <uuid> [--credential-ids <uuid,...>]\",\n \" Trigger a Release QA run\",\n \" status <run-id> [--json] Check run status\",\n \" run --application-id <uuid> [options] Trigger and poll until complete\",\n \" mark-deploy --commit <sha> --application-id <uuid> [--message \\\"...\\\"]\",\n \" Mark a commit as deployed\",\n \" latest-deploy --application-id <uuid> [--json]\",\n \" Show latest deployment for an application\",\n \"\",\n \"Run options:\",\n \" --timeout <seconds> Max wait time (default: 3600)\",\n \" --poll-interval <secs> Poll frequency (default: 30)\",\n \" --credential-ids <ids> Comma-separated credential UUIDs\",\n \"\",\n \"Options:\",\n \" --env <env> Target environment (prod, dev, local)\",\n \" --api-url <url> API URL override\",\n \" --token <key> API token override (or set CANARY_API_TOKEN)\",\n ].join(\"\\n\")\n );\n}\n\nexport async function runRelease(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === \"help\" || hasFlag(argv, \"--help\", \"-h\")) {\n printReleaseHelp();\n return;\n }\n\n const { apiUrl, token } = await resolveConfig(argv);\n\n switch (subCommand) {\n case \"trigger\":\n await handleTrigger(rest, apiUrl, token);\n break;\n case \"status\":\n await handleStatus(rest, apiUrl, token);\n break;\n case \"run\":\n await handleRun(rest, apiUrl, token);\n break;\n case \"mark-deploy\":\n await handleMarkDeploy(rest, apiUrl, token);\n break;\n case \"latest-deploy\":\n await handleLatestDeploy(rest, apiUrl, token);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printReleaseHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -6,12 +6,7 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
apiRequest,
|
|
8
8
|
selectProperty
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import {
|
|
11
|
-
INSTANCE_SIZES,
|
|
12
|
-
INSTANCE_SIZE_SPEC,
|
|
13
|
-
parseInstanceSize
|
|
14
|
-
} from "./chunk-SJJW77WN.js";
|
|
9
|
+
} from "./chunk-CQE46HSM.js";
|
|
15
10
|
import {
|
|
16
11
|
apiFetch,
|
|
17
12
|
exitOnFailure,
|
|
@@ -21,8 +16,14 @@ import {
|
|
|
21
16
|
getArgValue,
|
|
22
17
|
hasFlag,
|
|
23
18
|
resolveConfig
|
|
24
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-PZ4LCN6K.js";
|
|
20
|
+
import "./chunk-JZMJUPZP.js";
|
|
25
21
|
import "./chunk-JWHYXEA2.js";
|
|
22
|
+
import {
|
|
23
|
+
INSTANCE_SIZES,
|
|
24
|
+
INSTANCE_SIZE_SPEC,
|
|
25
|
+
parseInstanceSize
|
|
26
|
+
} from "./chunk-QGI4UCJX.js";
|
|
26
27
|
import "./chunk-VKVL7WBN.js";
|
|
27
28
|
|
|
28
29
|
// src/sandbox.ts
|
|
@@ -2043,4 +2044,4 @@ export {
|
|
|
2043
2044
|
parseDockerPs,
|
|
2044
2045
|
runSandbox
|
|
2045
2046
|
};
|
|
2046
|
-
//# sourceMappingURL=sandbox-
|
|
2047
|
+
//# sourceMappingURL=sandbox-DWSGLY7B.js.map
|