@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.
Files changed (148) hide show
  1. package/dist/{api-catalog-GFGCLVS4.js → api-catalog-7HLEN7C2.js} +5 -4
  2. package/dist/{api-catalog-GFGCLVS4.js.map → api-catalog-7HLEN7C2.js.map} +1 -1
  3. package/dist/{attachment-SJC7D7FY.js → attachment-OVNQD6Z2.js} +5 -4
  4. package/dist/{attachment-SJC7D7FY.js.map → attachment-OVNQD6Z2.js.map} +1 -1
  5. package/dist/{auth-EN6NQCJY.js → auth-VUHL74FH.js} +3 -2
  6. package/dist/{chunk-IMPZAX6L.js → chunk-5GD47G2D.js} +37 -1
  7. package/dist/{chunk-IMPZAX6L.js.map → chunk-5GD47G2D.js.map} +1 -1
  8. package/dist/{chunk-WOHL4FTB.js → chunk-CQE46HSM.js} +5 -5
  9. package/dist/chunk-CQE46HSM.js.map +1 -0
  10. package/dist/{chunk-52IO7ACJ.js → chunk-CRHPDPRS.js} +39 -3
  11. package/dist/{chunk-52IO7ACJ.js.map → chunk-CRHPDPRS.js.map} +1 -1
  12. package/dist/{chunk-XQXVG7RA.js → chunk-EEN2TZUQ.js} +3 -3
  13. package/dist/{chunk-I4QLI3JO.js → chunk-EJ4U242G.js} +2 -2
  14. package/dist/{chunk-CLAWT7BJ.js → chunk-ENDHMYEJ.js} +3 -3
  15. package/dist/chunk-G4UYGRZR.js +2 -0
  16. package/dist/chunk-JZMJUPZP.js +92 -0
  17. package/dist/chunk-JZMJUPZP.js.map +1 -0
  18. package/dist/{chunk-GKY2KXO5.js → chunk-NL7CVG56.js} +105 -35
  19. package/dist/chunk-NL7CVG56.js.map +1 -0
  20. package/dist/{chunk-A4OFTUVV.js → chunk-PZ4LCN6K.js} +7 -4
  21. package/dist/chunk-PZ4LCN6K.js.map +1 -0
  22. package/dist/{chunk-SJJW77WN.js → chunk-QGI4UCJX.js} +69 -5
  23. package/dist/chunk-QGI4UCJX.js.map +1 -0
  24. package/dist/{chunk-4PNOV7OV.js → chunk-QQVWGWPI.js} +1023 -150
  25. package/dist/chunk-QQVWGWPI.js.map +1 -0
  26. package/dist/{chunk-N7HFALX3.js → chunk-VGTKUOYS.js} +2 -2
  27. package/dist/{chunk-B2VISN2V.js → chunk-YN763NWQ.js} +230 -66
  28. package/dist/chunk-YN763NWQ.js.map +1 -0
  29. package/dist/{chunk-QFDOWABX.js → chunk-Z5LUTUDN.js} +6 -3
  30. package/dist/chunk-Z5LUTUDN.js.map +1 -0
  31. package/dist/{chunk-Q4BO4Z5V.js → chunk-ZTOE3ND3.js} +4 -4
  32. package/dist/{credential-COLTBV6D.js → credential-LO2SEEHU.js} +24 -20
  33. package/dist/credential-LO2SEEHU.js.map +1 -0
  34. package/dist/{credential-template-EEPYFG7R.js → credential-template-ZN7W7734.js} +30 -28
  35. package/dist/credential-template-ZN7W7734.js.map +1 -0
  36. package/dist/{debug-workflow-KOVH5GOP.js → debug-workflow-R3RYYAXK.js} +5 -4
  37. package/dist/{debug-workflow-KOVH5GOP.js.map → debug-workflow-R3RYYAXK.js.map} +1 -1
  38. package/dist/{docs-3SSORHB5.js → docs-DIAFBDXQ.js} +5 -4
  39. package/dist/{docs-3SSORHB5.js.map → docs-DIAFBDXQ.js.map} +1 -1
  40. package/dist/{doctor-OTSIWV6G.js → doctor-NZPUSCRE.js} +9 -5
  41. package/dist/doctor-NZPUSCRE.js.map +1 -0
  42. package/dist/environment-RQVU4P5M.js +221 -0
  43. package/dist/environment-RQVU4P5M.js.map +1 -0
  44. package/dist/{feature-flag-T2LRZME3.js → feature-flag-XG26RURR.js} +72 -10
  45. package/dist/feature-flag-XG26RURR.js.map +1 -0
  46. package/dist/index.js +57 -48
  47. package/dist/index.js.map +1 -1
  48. package/dist/{init-TGWRECT2.js → init-EDNLKGPT.js} +5 -4
  49. package/dist/{init-TGWRECT2.js.map → init-EDNLKGPT.js.map} +1 -1
  50. package/dist/{install-DXSNWZKO.js → install-FYZ3HNZK.js} +7 -7
  51. package/dist/{issues-XIZOPX6T.js → issues-NNRVTJ4L.js} +5 -4
  52. package/dist/{issues-XIZOPX6T.js.map → issues-NNRVTJ4L.js.map} +1 -1
  53. package/dist/{knobs-NBINZIUB.js → knobs-A2BOBH22.js} +5 -4
  54. package/dist/{knobs-NBINZIUB.js.map → knobs-A2BOBH22.js.map} +1 -1
  55. package/dist/{list-3TDHK637.js → list-F33VZ4BJ.js} +5 -4
  56. package/dist/{list-3TDHK637.js.map → list-F33VZ4BJ.js.map} +1 -1
  57. package/dist/{local-HICVD6PU.js → local-DQDTM3XA.js} +7 -6
  58. package/dist/{local-HICVD6PU.js.map → local-DQDTM3XA.js.map} +1 -1
  59. package/dist/{login-UOIUXVUK.js → login-BUMVIB36.js} +5 -4
  60. package/dist/{login-UOIUXVUK.js.map → login-BUMVIB36.js.map} +1 -1
  61. package/dist/{mcp-54IJEOUA.js → mcp-B5Y5CDMQ.js} +23 -24
  62. package/dist/mcp-B5Y5CDMQ.js.map +1 -0
  63. package/dist/{property-UXLOLPTD.js → property-NJ4SRXQG.js} +76 -4
  64. package/dist/property-NJ4SRXQG.js.map +1 -0
  65. package/dist/{psql-BYUUNLGG.js → psql-VBZFCMNR.js} +3 -2
  66. package/dist/{psql-BYUUNLGG.js.map → psql-VBZFCMNR.js.map} +1 -1
  67. package/dist/{record-4TR2UIIS.js → record-WAO36O7G.js} +16 -17
  68. package/dist/record-WAO36O7G.js.map +1 -0
  69. package/dist/{redis-35VBUYW7.js → redis-DHZXHL4S.js} +3 -2
  70. package/dist/{redis-35VBUYW7.js.map → redis-DHZXHL4S.js.map} +1 -1
  71. package/dist/{release-OOLTUBUT.js → release-STJKUKTE.js} +5 -4
  72. package/dist/{release-OOLTUBUT.js.map → release-STJKUKTE.js.map} +1 -1
  73. package/dist/{sandbox-XGSUU6G7.js → sandbox-DWSGLY7B.js} +9 -8
  74. package/dist/{sandbox-XGSUU6G7.js.map → sandbox-DWSGLY7B.js.map} +1 -1
  75. package/dist/{scenarios-GWLJEGHA.js → scenarios-HCIDY725.js} +5 -4
  76. package/dist/{scenarios-GWLJEGHA.js.map → scenarios-HCIDY725.js.map} +1 -1
  77. package/dist/{session-MYFNZPRP.js → session-Y5RHU54D.js} +76 -8
  78. package/dist/session-Y5RHU54D.js.map +1 -0
  79. package/dist/{skill-KM34LDMO.js → skill-23WAHUOB.js} +217 -67
  80. package/dist/skill-23WAHUOB.js.map +1 -0
  81. package/dist/skills/debug-run/SKILL.md +33 -22
  82. package/dist/skills/debug-run/history/1.2.0.md +262 -0
  83. package/dist/skills/debug-run/history/1.3.0.md +273 -0
  84. package/dist/skills/debug-run/version.json +1 -1
  85. package/dist/skills/optimize-cache/SKILL.md +206 -0
  86. package/dist/{spec-RA3CFEKG.js → spec-LM5XHOQ5.js} +54 -25
  87. package/dist/spec-LM5XHOQ5.js.map +1 -0
  88. package/dist/{src-LB4HBTJQ.js → src-22RI5VP2.js} +19 -11
  89. package/dist/src-22RI5VP2.js.map +1 -0
  90. package/dist/src-BGDRMOKC.js +5748 -0
  91. package/dist/src-BGDRMOKC.js.map +1 -0
  92. package/dist/{src-N3TPKGTY.js → src-NCJPUAE6.js} +3 -2
  93. package/dist/{src-UVDX5UP6.js → src-Y3K7UJEF.js} +4 -2
  94. package/dist/{start-PSEQSQA3.js → start-SWY55CZX.js} +5 -4
  95. package/dist/{start-PSEQSQA3.js.map → start-SWY55CZX.js.map} +1 -1
  96. package/dist/{tag-YY6YAABQ.js → tag-YSU2XXPI.js} +6 -5
  97. package/dist/{task-IQC3YR5K.js → task-NLBKLD7D.js} +5 -4
  98. package/dist/{task-IQC3YR5K.js.map → task-NLBKLD7D.js.map} +1 -1
  99. package/dist/{test-suite-DZNJFXDW.js → test-suite-QCPWZ2LS.js} +9 -6
  100. package/dist/{test-suite-DZNJFXDW.js.map → test-suite-QCPWZ2LS.js.map} +1 -1
  101. package/dist/{trace-HXIW7U2D.js → trace-A3ZY6K26.js} +6 -4
  102. package/dist/{triage-ORG45R5W.js → triage-TT4BMDBU.js} +6 -5
  103. package/dist/triage-TT4BMDBU.js.map +1 -0
  104. package/dist/{upgrade-L2VYMP2V.js → upgrade-6ZUFETKX.js} +3 -3
  105. package/dist/{workflow-XYFH5LTP.js → workflow-2CX3ZNOQ.js} +241 -237
  106. package/dist/workflow-2CX3ZNOQ.js.map +1 -0
  107. package/dist/{workflow-cache-NQJQFWMV.js → workflow-cache-GXNE6SU2.js} +140 -7
  108. package/dist/workflow-cache-GXNE6SU2.js.map +1 -0
  109. package/dist/{workflow-debug-BGD4UIXU.js → workflow-debug-PRX3DWGD.js} +8 -7
  110. package/dist/{workflow-debug-BGD4UIXU.js.map → workflow-debug-PRX3DWGD.js.map} +1 -1
  111. package/dist/{workflow-proposals-MTUDX46O.js → workflow-proposals-BW327WGL.js} +5 -4
  112. package/dist/{workflow-proposals-MTUDX46O.js.map → workflow-proposals-BW327WGL.js.map} +1 -1
  113. package/package.json +2 -1
  114. package/dist/chunk-4PNOV7OV.js.map +0 -1
  115. package/dist/chunk-A4OFTUVV.js.map +0 -1
  116. package/dist/chunk-B2VISN2V.js.map +0 -1
  117. package/dist/chunk-GKY2KXO5.js.map +0 -1
  118. package/dist/chunk-JICSYFRJ.js +0 -46
  119. package/dist/chunk-JICSYFRJ.js.map +0 -1
  120. package/dist/chunk-QFDOWABX.js.map +0 -1
  121. package/dist/chunk-SJJW77WN.js.map +0 -1
  122. package/dist/chunk-WOHL4FTB.js.map +0 -1
  123. package/dist/credential-COLTBV6D.js.map +0 -1
  124. package/dist/credential-template-EEPYFG7R.js.map +0 -1
  125. package/dist/doctor-OTSIWV6G.js.map +0 -1
  126. package/dist/feature-flag-T2LRZME3.js.map +0 -1
  127. package/dist/mcp-54IJEOUA.js.map +0 -1
  128. package/dist/property-UXLOLPTD.js.map +0 -1
  129. package/dist/record-4TR2UIIS.js.map +0 -1
  130. package/dist/session-MYFNZPRP.js.map +0 -1
  131. package/dist/skill-KM34LDMO.js.map +0 -1
  132. package/dist/spec-RA3CFEKG.js.map +0 -1
  133. package/dist/src-LB4HBTJQ.js.map +0 -1
  134. package/dist/workflow-XYFH5LTP.js.map +0 -1
  135. package/dist/workflow-cache-NQJQFWMV.js.map +0 -1
  136. /package/dist/{auth-EN6NQCJY.js.map → auth-VUHL74FH.js.map} +0 -0
  137. /package/dist/{chunk-XQXVG7RA.js.map → chunk-EEN2TZUQ.js.map} +0 -0
  138. /package/dist/{chunk-I4QLI3JO.js.map → chunk-EJ4U242G.js.map} +0 -0
  139. /package/dist/{chunk-CLAWT7BJ.js.map → chunk-ENDHMYEJ.js.map} +0 -0
  140. /package/dist/{src-N3TPKGTY.js.map → chunk-G4UYGRZR.js.map} +0 -0
  141. /package/dist/{chunk-N7HFALX3.js.map → chunk-VGTKUOYS.js.map} +0 -0
  142. /package/dist/{chunk-Q4BO4Z5V.js.map → chunk-ZTOE3ND3.js.map} +0 -0
  143. /package/dist/{install-DXSNWZKO.js.map → install-FYZ3HNZK.js.map} +0 -0
  144. /package/dist/{src-UVDX5UP6.js.map → src-NCJPUAE6.js.map} +0 -0
  145. /package/dist/{tag-YY6YAABQ.js.map → src-Y3K7UJEF.js.map} +0 -0
  146. /package/dist/{trace-HXIW7U2D.js.map → tag-YSU2XXPI.js.map} +0 -0
  147. /package/dist/{triage-ORG45R5W.js.map → trace-A3ZY6K26.js.map} +0 -0
  148. /package/dist/{upgrade-L2VYMP2V.js.map → upgrade-6ZUFETKX.js.map} +0 -0
@@ -1,17 +1,18 @@
1
1
  import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
2
2
  import {
3
3
  apiRequest
4
- } from "./chunk-WOHL4FTB.js";
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-A4OFTUVV.js";
10
+ } from "./chunk-PZ4LCN6K.js";
11
+ import "./chunk-JZMJUPZP.js";
12
12
  import {
13
13
  getSubDir
14
14
  } from "./chunk-JWHYXEA2.js";
15
+ import "./chunk-QGI4UCJX.js";
15
16
  import "./chunk-VKVL7WBN.js";
16
17
 
17
18
  // src/docs.ts
@@ -363,4 +364,4 @@ async function runDocs(argv) {
363
364
  export {
364
365
  runDocs
365
366
  };
366
- //# sourceMappingURL=docs-3SSORHB5.js.map
367
+ //# sourceMappingURL=docs-DIAFBDXQ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/docs.ts"],"sourcesContent":["/**\n * CLI Documentation Management\n *\n * Allows agents and superadmins to list, pull, edit, and push documentation pages.\n * Supports both global (public/superadmin) and org-scoped (--org) modes.\n */\n\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport path from 'node:path';\nimport { getSubDir } from '@chatsdet/tmp';\nimport process from 'node:process';\nimport { resolveConfig, getArgValue, hasFlag } from './auth.js';\nimport { apiRequest } from './cli-helpers.js';\n\ntype DocsPageListItem = {\n slug: string;\n title: string;\n description: string | null;\n updatedAt: string;\n publishedBy: string | null;\n};\n\ntype DocsVersionItem = {\n version: number;\n title: string;\n checksum: string;\n message: string | null;\n createdBy: string;\n createdAt: string;\n};\n\ntype DocsApiResponse = {\n ok: boolean;\n error?: string;\n data?: {\n slug?: string;\n title?: string;\n pages?: DocsPageListItem[];\n content?: string;\n versions?: DocsVersionItem[];\n };\n};\n\nconst DEFAULT_PULL_DIR = getSubDir('docs');\n\n/**\n * Parse the optional data-driven sidebar-placement flags. Only present flags\n * are included, so `push`/`create` without them leaves existing values intact.\n */\nfunction parseNavFields(argv: string[]): {\n navSection?: string;\n navGroup?: string;\n navOrder?: number;\n} {\n const out: { navSection?: string; navGroup?: string; navOrder?: number } = {};\n const section = getArgValue(argv, '--section');\n const group = getArgValue(argv, '--group');\n const order = getArgValue(argv, '--order');\n if (section != null) out.navSection = section;\n if (group != null) out.navGroup = group;\n if (order != null) {\n const n = Number.parseInt(order, 10);\n if (Number.isNaN(n)) {\n console.error('Error: --order must be an integer.');\n process.exit(1);\n }\n out.navOrder = n;\n }\n return out;\n}\n\n/** Return the base path prefix for read endpoints based on --org flag */\nfunction readPrefix(orgMode: boolean): string {\n return orgMode ? '/docs' : '/public/docs';\n}\n\n/** Return the base path prefix for write endpoints based on --org flag */\nfunction writePrefix(orgMode: boolean): string {\n return orgMode ? '/docs' : '/superadmin/docs';\n}\n\nasync function handleList(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const jsonOutput = hasFlag(argv, '--json');\n const result = await apiRequest<DocsApiResponse>(apiUrl, token, 'GET', `${readPrefix(orgMode)}/pages`);\n const pages: DocsPageListItem[] = result.data?.pages ?? [];\n\n if (jsonOutput) {\n console.log(JSON.stringify(pages, null, 2));\n return;\n }\n\n if (pages.length === 0) {\n console.log('No documentation pages found.');\n return;\n }\n\n // Default: markdown table for easy consumption by agents and humans\n const slugWidth = Math.max(4, ...pages.map((p) => p.slug.length));\n const titleWidth = Math.max(5, ...pages.map((p) => p.title.length));\n const header = `| ${'Slug'.padEnd(slugWidth)} | ${'Title'.padEnd(titleWidth)} | Updated | Published By |`;\n const sep = `| ${'-'.repeat(slugWidth)} | ${'-'.repeat(titleWidth)} | ---------- | ------------ |`;\n console.log(header);\n console.log(sep);\n for (const page of pages) {\n const date = new Date(page.updatedAt).toISOString().slice(0, 10);\n const by = page.publishedBy ?? '';\n console.log(`| ${page.slug.padEnd(slugWidth)} | ${page.title.padEnd(titleWidth)} | ${date} | ${by.padEnd(12)} |`);\n }\n}\n\nasync function fetchDocContent(slug: string, apiUrl: string, token: string, orgMode: boolean): Promise<string> {\n if (orgMode) {\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'GET',\n `/docs/pages/content?slug=${encodeURIComponent(slug)}`\n );\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n return result.data?.content ?? '';\n }\n\n const res = await fetch(`${apiUrl}/public/docs/pages/raw?slug=${encodeURIComponent(slug)}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.status === 404) {\n console.error(`Error: Page not found: ${slug}`);\n process.exit(1);\n }\n\n if (!res.ok) {\n console.error(`Error: ${res.statusText}`);\n process.exit(1);\n }\n\n return res.text();\n}\n\nasync function handleGet(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs get <slug>');\n process.exit(1);\n }\n\n const content = await fetchDocContent(slug, apiUrl, token, orgMode);\n console.log(content);\n}\n\nasync function handlePull(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs pull <slug> [--output <path>]');\n process.exit(1);\n }\n\n const outputPath = getArgValue(argv, '--output') ?? path.join(DEFAULT_PULL_DIR, `${slug}.md`);\n const content = await fetchDocContent(slug, apiUrl, token, orgMode);\n\n await mkdir(path.dirname(outputPath), { recursive: true });\n await writeFile(outputPath, content, 'utf8');\n console.log(`Pulled ${slug} → ${outputPath}`);\n}\n\nasync function handlePush(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs push <slug> --file <path> [--message <text>]');\n process.exit(1);\n }\n\n const filePath = getArgValue(argv, '--file');\n if (!filePath) {\n console.error('Error: Missing --file <path>.');\n process.exit(1);\n }\n\n const message = getArgValue(argv, '--message') ?? undefined;\n const createdBy = getArgValue(argv, '--created-by') ?? undefined;\n\n let content: string;\n try {\n content = await readFile(filePath, 'utf8');\n } catch {\n console.error(`Error: Could not read file: ${filePath}`);\n process.exit(1);\n }\n\n // Strip `export const meta = { ... };` block so raw JS isn't stored as doc content\n content = content.replace(/^\\s*export\\s+const\\s+meta\\s*=\\s*\\{[^}]*\\};\\s*/, '');\n\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'PUT',\n `${writePrefix(orgMode)}/pages?slug=${encodeURIComponent(slug)}`,\n { content, message, createdBy, ...parseNavFields(argv) }\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Published new version of ${slug}`);\n}\n\nasync function handleHistory(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs history <slug>');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n\n const res = await fetch(`${apiUrl}${readPrefix(orgMode)}/pages/versions?slug=${encodeURIComponent(slug)}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: res.statusText }));\n console.error(`Error: ${(body as { error?: string }).error ?? res.statusText}`);\n process.exit(1);\n }\n\n const body = (await res.json()) as DocsApiResponse;\n const versions = body.data?.versions ?? [];\n\n if (jsonOutput) {\n console.log(JSON.stringify(versions, null, 2));\n return;\n }\n\n if (versions.length === 0) {\n console.log(`No versions found for ${slug}.`);\n return;\n }\n\n for (const v of versions) {\n const date = new Date(v.createdAt).toISOString().slice(0, 19).replace('T', ' ');\n const msg = v.message ? ` — ${v.message}` : '';\n console.log(` v${v.version} ${date} ${v.createdBy}${msg}`);\n }\n}\n\nasync function handleCreate(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs create <slug> --file <path> --title <text>');\n process.exit(1);\n }\n\n const filePath = getArgValue(argv, '--file');\n const title = getArgValue(argv, '--title');\n\n if (!filePath) {\n console.error('Error: Missing --file <path>.');\n process.exit(1);\n }\n if (!title) {\n console.error('Error: Missing --title <text>.');\n process.exit(1);\n }\n\n const description = getArgValue(argv, '--description') ?? undefined;\n const message = getArgValue(argv, '--message') ?? undefined;\n\n let content: string;\n try {\n content = await readFile(filePath, 'utf8');\n } catch {\n console.error(`Error: Could not read file: ${filePath}`);\n process.exit(1);\n }\n\n // Strip `export const meta = { ... };` block so raw JS isn't stored as doc content\n content = content.replace(/^\\s*export\\s+const\\s+meta\\s*=\\s*\\{[^}]*\\};\\s*/, '');\n\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'POST',\n `${writePrefix(orgMode)}/pages`,\n {\n slug,\n title,\n description,\n content,\n message,\n ...parseNavFields(argv),\n }\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Created page: ${slug}`);\n}\n\ntype DocsSearchResult = {\n path: string;\n title: string;\n description: string | null;\n excerpt: string;\n};\n\ntype DocsSearchResponse = {\n ok: boolean;\n error?: string;\n data?: { results: DocsSearchResult[] };\n};\n\nasync function handleSearch(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const query = argv.filter((a) => !a.startsWith('--')).join(' ').trim();\n if (!query) {\n console.error('Error: Missing search query.');\n console.error('Usage: canary docs search <query> [--limit <n>] [--json]');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n const limitArg = getArgValue(argv, '--limit');\n const params = new URLSearchParams({ q: query });\n if (limitArg) params.set('limit', limitArg);\n\n const searchPath = orgMode ? '/docs/search' : '/public/docs/search';\n const res = await fetch(`${apiUrl}${searchPath}?${params.toString()}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: res.statusText }));\n console.error(`Error: ${(body as { error?: string }).error ?? res.statusText}`);\n process.exit(1);\n }\n\n const body = (await res.json()) as DocsSearchResponse;\n const results = body.data?.results ?? [];\n\n if (jsonOutput) {\n console.log(JSON.stringify(results, null, 2));\n return;\n }\n\n if (results.length === 0) {\n console.log('No results found.');\n return;\n }\n\n for (const r of results) {\n const desc = r.description ? ` ${r.description}` : '';\n const excerpt = r.excerpt\n ? ` ${r.excerpt.replace(/<\\/?mark>/g, '').replace(/\\n/g, ' ').slice(0, 120)}`\n : '';\n console.log(` ${r.path ?? r.title}`);\n if (r.title) console.log(` ${r.title}${desc}`);\n if (excerpt) console.log(` ${excerpt}`);\n console.log();\n }\n}\n\nasync function handleDelete(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs delete <slug>');\n process.exit(1);\n }\n\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'DELETE',\n `${writePrefix(orgMode)}/pages?slug=${encodeURIComponent(slug)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Deleted page: ${slug}`);\n}\n\nfunction printDocsHelp(): void {\n console.log(\n [\n 'Usage: canary docs <sub-command> [options]',\n '',\n 'Sub-commands:',\n ' list List all doc pages',\n ' get <slug> Print content to stdout',\n ' search <query> Full-text search docs',\n ' pull <slug> [--output <path>] Download to local file',\n ' push <slug> --file <path> [--message] Publish new version',\n ' history <slug> Show version history',\n ' create <slug> --file <path> --title ... Create new page',\n ' delete <slug> Soft-delete a page',\n '',\n 'Options:',\n ' --org Use org-scoped endpoints (requires auth)',\n ' --file <path> Path to markdown file',\n ' --title <text> Page title (create only)',\n ' --description <text> Page description (create only)',\n ' --section <text> Sidebar section (data-driven nav; create/push)',\n ' --group <text> Sidebar sub-group within the section (create/push)',\n ' --order <n> Sort order within the section/group (create/push)',\n ' --message <text> Version commit message',\n ' --limit <n> Max results for search (default: 8, max: 20)',\n ' --output <path> Output path for pull (default: <tmpdir>/canary/docs/<slug>.md)',\n ' --json Output as JSON (list, history, search)',\n ' --env <env> Target environment (prod, dev)',\n ' --api-url <url> API URL override',\n ' --token <key> API token override',\n ].join('\\n')\n );\n}\n\nexport async function runDocs(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === 'help' || hasFlag(argv, '--help', '-h')) {\n printDocsHelp();\n return;\n }\n\n const { apiUrl, token } = await resolveConfig(argv);\n const orgMode = hasFlag(rest, '--org');\n\n switch (subCommand) {\n case 'list':\n await handleList(rest, apiUrl, token, orgMode);\n break;\n case 'get':\n await handleGet(rest, apiUrl, token, orgMode);\n break;\n case 'search':\n await handleSearch(rest, apiUrl, token, orgMode);\n break;\n case 'pull':\n await handlePull(rest, apiUrl, token, orgMode);\n break;\n case 'push':\n await handlePush(rest, apiUrl, token, orgMode);\n break;\n case 'history':\n await handleHistory(rest, apiUrl, token, orgMode);\n break;\n case 'create':\n await handleCreate(rest, apiUrl, token, orgMode);\n break;\n case 'delete':\n await handleDelete(rest, apiUrl, token, orgMode);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printDocsHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["body"]}
1
+ {"version":3,"sources":["../src/docs.ts"],"sourcesContent":["/**\n * CLI Documentation Management\n *\n * Allows agents and superadmins to list, pull, edit, and push documentation pages.\n * Supports both global (public/superadmin) and org-scoped (--org) modes.\n */\n\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport path from 'node:path';\nimport { getSubDir } from '@chatsdet/tmp';\nimport process from 'node:process';\nimport { resolveConfig, getArgValue, hasFlag } from './auth.js';\nimport { apiRequest } from './cli-helpers.js';\n\ntype DocsPageListItem = {\n slug: string;\n title: string;\n description: string | null;\n updatedAt: string;\n publishedBy: string | null;\n};\n\ntype DocsVersionItem = {\n version: number;\n title: string;\n checksum: string;\n message: string | null;\n createdBy: string;\n createdAt: string;\n};\n\ntype DocsApiResponse = {\n ok: boolean;\n error?: string;\n data?: {\n slug?: string;\n title?: string;\n pages?: DocsPageListItem[];\n content?: string;\n versions?: DocsVersionItem[];\n };\n};\n\nconst DEFAULT_PULL_DIR = getSubDir('docs');\n\n/**\n * Parse the optional data-driven sidebar-placement flags. Only present flags\n * are included, so `push`/`create` without them leaves existing values intact.\n */\nfunction parseNavFields(argv: string[]): {\n navSection?: string;\n navGroup?: string;\n navOrder?: number;\n} {\n const out: { navSection?: string; navGroup?: string; navOrder?: number } = {};\n const section = getArgValue(argv, '--section');\n const group = getArgValue(argv, '--group');\n const order = getArgValue(argv, '--order');\n if (section != null) out.navSection = section;\n if (group != null) out.navGroup = group;\n if (order != null) {\n const n = Number.parseInt(order, 10);\n if (Number.isNaN(n)) {\n console.error('Error: --order must be an integer.');\n process.exit(1);\n }\n out.navOrder = n;\n }\n return out;\n}\n\n/** Return the base path prefix for read endpoints based on --org flag */\nfunction readPrefix(orgMode: boolean): string {\n return orgMode ? '/docs' : '/public/docs';\n}\n\n/** Return the base path prefix for write endpoints based on --org flag */\nfunction writePrefix(orgMode: boolean): string {\n return orgMode ? '/docs' : '/superadmin/docs';\n}\n\nasync function handleList(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const jsonOutput = hasFlag(argv, '--json');\n const result = await apiRequest<DocsApiResponse>(apiUrl, token, 'GET', `${readPrefix(orgMode)}/pages`);\n const pages: DocsPageListItem[] = result.data?.pages ?? [];\n\n if (jsonOutput) {\n console.log(JSON.stringify(pages, null, 2));\n return;\n }\n\n if (pages.length === 0) {\n console.log('No documentation pages found.');\n return;\n }\n\n // Default: markdown table for easy consumption by agents and humans\n const slugWidth = Math.max(4, ...pages.map((p) => p.slug.length));\n const titleWidth = Math.max(5, ...pages.map((p) => p.title.length));\n const header = `| ${'Slug'.padEnd(slugWidth)} | ${'Title'.padEnd(titleWidth)} | Updated | Published By |`;\n const sep = `| ${'-'.repeat(slugWidth)} | ${'-'.repeat(titleWidth)} | ---------- | ------------ |`;\n console.log(header);\n console.log(sep);\n for (const page of pages) {\n const date = new Date(page.updatedAt).toISOString().slice(0, 10);\n const by = page.publishedBy ?? '';\n console.log(`| ${page.slug.padEnd(slugWidth)} | ${page.title.padEnd(titleWidth)} | ${date} | ${by.padEnd(12)} |`);\n }\n}\n\nasync function fetchDocContent(slug: string, apiUrl: string, token: string, orgMode: boolean): Promise<string> {\n if (orgMode) {\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'GET',\n `/docs/pages/content?slug=${encodeURIComponent(slug)}`\n );\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n return result.data?.content ?? '';\n }\n\n const res = await fetch(`${apiUrl}/public/docs/pages/raw?slug=${encodeURIComponent(slug)}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.status === 404) {\n console.error(`Error: Page not found: ${slug}`);\n process.exit(1);\n }\n\n if (!res.ok) {\n console.error(`Error: ${res.statusText}`);\n process.exit(1);\n }\n\n return res.text();\n}\n\nasync function handleGet(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs get <slug>');\n process.exit(1);\n }\n\n const content = await fetchDocContent(slug, apiUrl, token, orgMode);\n console.log(content);\n}\n\nasync function handlePull(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs pull <slug> [--output <path>]');\n process.exit(1);\n }\n\n const outputPath = getArgValue(argv, '--output') ?? path.join(DEFAULT_PULL_DIR, `${slug}.md`);\n const content = await fetchDocContent(slug, apiUrl, token, orgMode);\n\n await mkdir(path.dirname(outputPath), { recursive: true });\n await writeFile(outputPath, content, 'utf8');\n console.log(`Pulled ${slug} → ${outputPath}`);\n}\n\nasync function handlePush(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs push <slug> --file <path> [--message <text>]');\n process.exit(1);\n }\n\n const filePath = getArgValue(argv, '--file');\n if (!filePath) {\n console.error('Error: Missing --file <path>.');\n process.exit(1);\n }\n\n const message = getArgValue(argv, '--message') ?? undefined;\n const createdBy = getArgValue(argv, '--created-by') ?? undefined;\n\n let content: string;\n try {\n content = await readFile(filePath, 'utf8');\n } catch {\n console.error(`Error: Could not read file: ${filePath}`);\n process.exit(1);\n }\n\n // Strip `export const meta = { ... };` block so raw JS isn't stored as doc content\n content = content.replace(/^\\s*export\\s+const\\s+meta\\s*=\\s*\\{[^}]*\\};\\s*/, '');\n\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'PUT',\n `${writePrefix(orgMode)}/pages?slug=${encodeURIComponent(slug)}`,\n { content, message, createdBy, ...parseNavFields(argv) }\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Published new version of ${slug}`);\n}\n\nasync function handleHistory(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs history <slug>');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n\n const res = await fetch(`${apiUrl}${readPrefix(orgMode)}/pages/versions?slug=${encodeURIComponent(slug)}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: res.statusText }));\n console.error(`Error: ${(body as { error?: string }).error ?? res.statusText}`);\n process.exit(1);\n }\n\n const body = (await res.json()) as DocsApiResponse;\n const versions = body.data?.versions ?? [];\n\n if (jsonOutput) {\n console.log(JSON.stringify(versions, null, 2));\n return;\n }\n\n if (versions.length === 0) {\n console.log(`No versions found for ${slug}.`);\n return;\n }\n\n for (const v of versions) {\n const date = new Date(v.createdAt).toISOString().slice(0, 19).replace('T', ' ');\n const msg = v.message ? ` — ${v.message}` : '';\n console.log(` v${v.version} ${date} ${v.createdBy}${msg}`);\n }\n}\n\nasync function handleCreate(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs create <slug> --file <path> --title <text>');\n process.exit(1);\n }\n\n const filePath = getArgValue(argv, '--file');\n const title = getArgValue(argv, '--title');\n\n if (!filePath) {\n console.error('Error: Missing --file <path>.');\n process.exit(1);\n }\n if (!title) {\n console.error('Error: Missing --title <text>.');\n process.exit(1);\n }\n\n const description = getArgValue(argv, '--description') ?? undefined;\n const message = getArgValue(argv, '--message') ?? undefined;\n\n let content: string;\n try {\n content = await readFile(filePath, 'utf8');\n } catch {\n console.error(`Error: Could not read file: ${filePath}`);\n process.exit(1);\n }\n\n // Strip `export const meta = { ... };` block so raw JS isn't stored as doc content\n content = content.replace(/^\\s*export\\s+const\\s+meta\\s*=\\s*\\{[^}]*\\};\\s*/, '');\n\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'POST',\n `${writePrefix(orgMode)}/pages`,\n {\n slug,\n title,\n description,\n content,\n message,\n ...parseNavFields(argv),\n }\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Created page: ${slug}`);\n}\n\ntype DocsSearchResult = {\n path: string;\n title: string;\n description: string | null;\n excerpt: string;\n};\n\ntype DocsSearchResponse = {\n ok: boolean;\n error?: string;\n data?: { results: DocsSearchResult[] };\n};\n\nasync function handleSearch(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const query = argv.filter((a) => !a.startsWith('--')).join(' ').trim();\n if (!query) {\n console.error('Error: Missing search query.');\n console.error('Usage: canary docs search <query> [--limit <n>] [--json]');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n const limitArg = getArgValue(argv, '--limit');\n const params = new URLSearchParams({ q: query });\n if (limitArg) params.set('limit', limitArg);\n\n const searchPath = orgMode ? '/docs/search' : '/public/docs/search';\n const res = await fetch(`${apiUrl}${searchPath}?${params.toString()}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: res.statusText }));\n console.error(`Error: ${(body as { error?: string }).error ?? res.statusText}`);\n process.exit(1);\n }\n\n const body = (await res.json()) as DocsSearchResponse;\n const results = body.data?.results ?? [];\n\n if (jsonOutput) {\n console.log(JSON.stringify(results, null, 2));\n return;\n }\n\n if (results.length === 0) {\n console.log('No results found.');\n return;\n }\n\n for (const r of results) {\n const desc = r.description ? ` ${r.description}` : '';\n const excerpt = r.excerpt\n ? ` ${r.excerpt.replace(/<\\/?mark>/g, '').replace(/\\n/g, ' ').slice(0, 120)}`\n : '';\n console.log(` ${r.path ?? r.title}`);\n if (r.title) console.log(` ${r.title}${desc}`);\n if (excerpt) console.log(` ${excerpt}`);\n console.log();\n }\n}\n\nasync function handleDelete(argv: string[], apiUrl: string, token: string, orgMode: boolean): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs delete <slug>');\n process.exit(1);\n }\n\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'DELETE',\n `${writePrefix(orgMode)}/pages?slug=${encodeURIComponent(slug)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Deleted page: ${slug}`);\n}\n\nfunction printDocsHelp(): void {\n console.log(\n [\n 'Usage: canary docs <sub-command> [options]',\n '',\n 'Sub-commands:',\n ' list List all doc pages',\n ' get <slug> Print content to stdout',\n ' search <query> Full-text search docs',\n ' pull <slug> [--output <path>] Download to local file',\n ' push <slug> --file <path> [--message] Publish new version',\n ' history <slug> Show version history',\n ' create <slug> --file <path> --title ... Create new page',\n ' delete <slug> Soft-delete a page',\n '',\n 'Options:',\n ' --org Use org-scoped endpoints (requires auth)',\n ' --file <path> Path to markdown file',\n ' --title <text> Page title (create only)',\n ' --description <text> Page description (create only)',\n ' --section <text> Sidebar section (data-driven nav; create/push)',\n ' --group <text> Sidebar sub-group within the section (create/push)',\n ' --order <n> Sort order within the section/group (create/push)',\n ' --message <text> Version commit message',\n ' --limit <n> Max results for search (default: 8, max: 20)',\n ' --output <path> Output path for pull (default: <tmpdir>/canary/docs/<slug>.md)',\n ' --json Output as JSON (list, history, search)',\n ' --env <env> Target environment (prod, dev)',\n ' --api-url <url> API URL override',\n ' --token <key> API token override',\n ].join('\\n')\n );\n}\n\nexport async function runDocs(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === 'help' || hasFlag(argv, '--help', '-h')) {\n printDocsHelp();\n return;\n }\n\n const { apiUrl, token } = await resolveConfig(argv);\n const orgMode = hasFlag(rest, '--org');\n\n switch (subCommand) {\n case 'list':\n await handleList(rest, apiUrl, token, orgMode);\n break;\n case 'get':\n await handleGet(rest, apiUrl, token, orgMode);\n break;\n case 'search':\n await handleSearch(rest, apiUrl, token, orgMode);\n break;\n case 'pull':\n await handlePull(rest, apiUrl, token, orgMode);\n break;\n case 'push':\n await handlePush(rest, apiUrl, token, orgMode);\n break;\n case 'history':\n await handleHistory(rest, apiUrl, token, orgMode);\n break;\n case 'create':\n await handleCreate(rest, apiUrl, token, orgMode);\n break;\n case 'delete':\n await handleDelete(rest, apiUrl, token, orgMode);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printDocsHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["body"]}
@@ -8,7 +8,10 @@ import {
8
8
  envToProfile,
9
9
  getArgValue,
10
10
  readStoredAuth
11
- } from "./chunk-A4OFTUVV.js";
11
+ } from "./chunk-PZ4LCN6K.js";
12
+ import {
13
+ readBrandEnv
14
+ } from "./chunk-JZMJUPZP.js";
12
15
  import "./chunk-VKVL7WBN.js";
13
16
 
14
17
  // src/doctor.ts
@@ -34,16 +37,17 @@ function truncateId(id) {
34
37
  async function runAuthDoctor(argv) {
35
38
  const env = getArgValue(argv, "--env");
36
39
  const profile = env ? envToProfile(env) : void 0;
37
- const apiUrlOverride = getArgValue(argv, "--api-url") ?? process.env.CANARY_API_URL;
40
+ const apiUrlOverride = getArgValue(argv, "--api-url") ?? readBrandEnv("CANARY_API_URL");
38
41
  const stored = await readStoredAuth(profile);
39
- const token = process.env.CANARY_API_TOKEN ?? stored?.token;
42
+ const envToken = readBrandEnv("CANARY_API_TOKEN");
43
+ const token = envToken ?? stored?.token;
40
44
  const apiUrl = apiUrlOverride ?? (env && ENV_URLS[env]?.api) ?? stored?.apiUrl ?? "https://api.trycanary.ai";
41
45
  console.log("\u2500\u2500 canary auth doctor \u2500\u2500");
42
46
  console.log(`node: ${process.version}`);
43
47
  console.log(`platform: ${process.platform}`);
44
48
  console.log(`api url: ${apiUrl}`);
45
49
  console.log(`profile: ${profile ?? "(default)"}`);
46
- console.log(`token source: ${process.env.CANARY_API_TOKEN ? "CANARY_API_TOKEN env" : stored?.token ? "auth.json" : "NONE"}`);
50
+ console.log(`token source: ${envToken ? "API token env var" : stored?.token ? "auth.json" : "NONE"}`);
47
51
  console.log(
48
52
  `NODE_EXTRA_CA_CERTS: ${process.env.NODE_EXTRA_CA_CERTS ?? "(not set)"}`
49
53
  );
@@ -129,4 +133,4 @@ async function runAuthDoctor(argv) {
129
133
  export {
130
134
  runAuthDoctor
131
135
  };
132
- //# sourceMappingURL=doctor-OTSIWV6G.js.map
136
+ //# sourceMappingURL=doctor-NZPUSCRE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/doctor.ts"],"sourcesContent":["/**\n * `canary auth doctor` — print everything a user or IT admin needs to see\n * when the CLI is misbehaving against a corporate proxy (Zscaler, Netskope,\n * ZPA, Cloudflare Access). Reads the stored auth, decodes the JWT locally,\n * and probes a curated set of endpoints so we can tell apart:\n * - TLS interception (Node doesn't trust the proxy CA)\n * - URL-category filtering (some paths fail, others pass)\n * - Proxy-injected block pages (HTML body / missing request-id header)\n * - Real auth failures (401 with our header present)\n */\n\nimport process from 'node:process';\nimport { getArgValue, readStoredAuth, envToProfile, ENV_URLS } from './auth.js';\nimport { decodeJwtPayload } from './jwt.js';\nimport { apiFetch } from './api-fetch.js';\nimport { readBrandEnv } from './brand.js';\n\ninterface Probe {\n name: string;\n path: string;\n method?: string;\n}\n\nconst DEFAULT_PROBES: Probe[] = [\n { name: 'GET /me', path: '/me' },\n { name: 'GET /org/credentials', path: '/org/credentials' },\n { name: 'GET /org/properties', path: '/org/properties' },\n];\n\nfunction fmtExp(expSec: number | undefined): string {\n if (!expSec) return 'unknown';\n const now = Math.floor(Date.now() / 1000);\n const deltaSec = expSec - now;\n const date = new Date(expSec * 1000).toISOString();\n if (deltaSec < 0) return `${date} (expired ${Math.abs(deltaSec)}s ago)`;\n const days = Math.round(deltaSec / 86400);\n return `${date} (in ~${days} days)`;\n}\n\n/** Keep the first 8 chars of an identifier so users pasting doctor output\n * to IT don't leak full user/org IDs, but we still have enough for triage. */\nfunction truncateId(id: string | undefined): string {\n if (!id) return '(n/a)';\n return id.length > 8 ? `${id.slice(0, 8)}…` : id;\n}\n\nexport async function runAuthDoctor(argv: string[]): Promise<void> {\n const env = getArgValue(argv, '--env');\n const profile = env ? envToProfile(env) : undefined;\n const apiUrlOverride = getArgValue(argv, '--api-url') ?? readBrandEnv('CANARY_API_URL');\n\n const stored = await readStoredAuth(profile);\n const envToken = readBrandEnv('CANARY_API_TOKEN');\n const token = envToken ?? stored?.token;\n const apiUrl =\n apiUrlOverride ?? (env && ENV_URLS[env]?.api) ?? stored?.apiUrl ?? 'https://api.trycanary.ai';\n\n console.log('── canary auth doctor ──');\n console.log(`node: ${process.version}`);\n console.log(`platform: ${process.platform}`);\n console.log(`api url: ${apiUrl}`);\n console.log(`profile: ${profile ?? '(default)'}`);\n console.log(`token source: ${envToken ? 'API token env var' : stored?.token ? 'auth.json' : 'NONE'}`);\n console.log(\n `NODE_EXTRA_CA_CERTS: ${process.env.NODE_EXTRA_CA_CERTS ?? '(not set)'}`\n );\n console.log(`NODE_OPTIONS: ${process.env.NODE_OPTIONS ?? '(not set)'}`);\n\n if (!token) {\n console.log('');\n console.log('No token found. Run: canary login' + (env ? ` --env ${env}` : ''));\n process.exit(1);\n }\n\n const payload = decodeJwtPayload(token);\n const exp = typeof payload?.exp === 'number' ? (payload.exp as number) : undefined;\n const sub = typeof payload?.sub === 'string' ? (payload.sub as string) : undefined;\n const orgId = typeof payload?.org_id === 'string' ? (payload.org_id as string) : undefined;\n console.log('');\n console.log('── token ──');\n console.log(`decoded: ${payload ? 'ok' : 'UNDECODABLE (likely corrupted file)'}`);\n console.log(`sub: ${truncateId(sub)}`);\n console.log(`org_id: ${truncateId(orgId)}`);\n console.log(`exp: ${fmtExp(exp)}`);\n\n console.log('');\n console.log('── probes ──');\n console.log('Each probe exercises a different path — mixed pass/fail here is the');\n console.log('signal for Zscaler URL-category or DLP filtering.');\n console.log('');\n\n let hadProxyInjection = false;\n let hadTls = false;\n let passed = 0;\n\n for (const probe of DEFAULT_PROBES) {\n const url = `${apiUrl}${probe.path}`;\n const result = await apiFetch(url, {\n method: probe.method ?? 'GET',\n headers: { Authorization: `Bearer ${token}` },\n token,\n // Short per-probe timeout so one stalled endpoint doesn't block diagnosis.\n timeoutMs: 10_000,\n });\n if (result.ok) {\n const rid = result.requestId ?? '(absent)';\n console.log(` ✓ ${probe.name.padEnd(28)} 200 rid=${rid}`);\n passed += 1;\n } else {\n const f = result.failure;\n const rid = f.requestId ?? '(absent)';\n console.log(\n ` ✗ ${probe.name.padEnd(28)} ${f.status ?? 'ERR'} [${f.kind}] rid=${rid}`\n );\n const firstLine = f.message.split('\\n')[0];\n console.log(` ${firstLine}`);\n if (f.kind === 'tls') hadTls = true;\n if (f.kind === 'html-body' || f.kind === 'proxy-injected-4xx') hadProxyInjection = true;\n }\n }\n\n console.log('');\n console.log('── diagnosis ──');\n if (hadTls) {\n console.log('TLS verification failed on at least one probe.');\n console.log(' → A corporate proxy is intercepting HTTPS. Trust the proxy root CA:');\n console.log(' export NODE_EXTRA_CA_CERTS=/path/to/corporate-root.pem');\n console.log(' or on Node 20+:');\n console.log(' export NODE_OPTIONS=--use-system-ca');\n } else if (hadProxyInjection) {\n console.log('At least one response was NOT from our API (HTML body or missing');\n console.log('x-canary-request-id). A proxy block page or captive portal is in the way.');\n console.log(' → Share this output with your IT/Zscaler admin and ask them to');\n console.log(` allowlist ${apiUrl}.`);\n } else if (passed === DEFAULT_PROBES.length) {\n console.log('All probes reached our API successfully. Auth + connectivity look healthy.');\n console.log('If you are still seeing intermittent issues, re-run with --debug on the');\n console.log('failing command: CANARY_DEBUG=1 canary <cmd> …');\n } else if (passed > 0) {\n console.log('Mixed results: some probes reached our API, others did not.');\n console.log(' → This is the classic signature of URL-category filtering at the proxy');\n console.log(' (certain paths like /run, /execute are blocked while others pass)');\n console.log(' or partial domain allowlisting.');\n console.log(' → Share the probe table with your IT/Zscaler admin; include the exact');\n console.log(' failing paths and the \"[kind]\" column.');\n } else {\n console.log('Every probe failed. Check your network connection and proxy settings,');\n console.log('then retry with CANARY_DEBUG=1 canary auth doctor.');\n }\n\n if (passed < DEFAULT_PROBES.length) process.exit(1);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,221 @@
1
+ import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
2
+ import {
3
+ apiRequest,
4
+ fetchProperties
5
+ } from "./chunk-CQE46HSM.js";
6
+ import "./chunk-3CZU7XCS.js";
7
+ import {
8
+ getArgValue,
9
+ hasFlag,
10
+ resolveConfig
11
+ } from "./chunk-PZ4LCN6K.js";
12
+ import "./chunk-JZMJUPZP.js";
13
+ import "./chunk-JWHYXEA2.js";
14
+ import "./chunk-QGI4UCJX.js";
15
+ import "./chunk-VKVL7WBN.js";
16
+
17
+ // src/environment.ts
18
+ import process from "process";
19
+ function pad(s, n) {
20
+ return s.padEnd(n);
21
+ }
22
+ function printHelp() {
23
+ console.log(
24
+ [
25
+ "canary environment: Manage application environments (alias: canary env)",
26
+ "",
27
+ "Sub-commands:",
28
+ " list [options] List environments for an application",
29
+ " create [options] Create an environment (incl. sandbox)",
30
+ " set-default [options] Set an environment as the application default",
31
+ "",
32
+ "List options:",
33
+ " --application <name|id> Application (required; alias: --property)",
34
+ "",
35
+ "Create options:",
36
+ " --application <name|id> Application (required; alias: --property)",
37
+ " --name <name> Environment name (required)",
38
+ " --type <permanent|ephemeral|local|sandbox> Environment type (default: permanent)",
39
+ " --url <url> Base URL (required unless --type sandbox)",
40
+ " --sandbox-template <uuid> Backing template (required iff --type sandbox)",
41
+ " --login-path </path> Per-env login path override",
42
+ " --description <text> Optional description",
43
+ " --default Set this environment as the application default",
44
+ "",
45
+ "Set-default options:",
46
+ " --application <name|id> Application (required; alias: --property)",
47
+ " --environment <name|id> Environment to make default (required)",
48
+ "",
49
+ "Common options:",
50
+ " --json Output as JSON"
51
+ ].join("\n")
52
+ );
53
+ }
54
+ async function resolveApplicationId(argv, apiUrl, token) {
55
+ const arg = getArgValue(argv, "--application") ?? getArgValue(argv, "--property");
56
+ if (!arg) {
57
+ console.error("Error: --application <name|id> is required.");
58
+ process.exit(1);
59
+ }
60
+ const properties = await fetchProperties(apiUrl, token);
61
+ const match = properties.find(
62
+ (p) => p.id === arg || p.name.toLowerCase() === arg.toLowerCase()
63
+ );
64
+ if (!match) {
65
+ console.error(`Error: Application "${arg}" not found.`);
66
+ if (properties.length > 0) {
67
+ console.error("Available applications:");
68
+ for (const p of properties) console.error(` - ${p.name} (${p.id})`);
69
+ }
70
+ process.exit(1);
71
+ }
72
+ return match.id;
73
+ }
74
+ async function fetchEnvironments(propertyId, apiUrl, token) {
75
+ const res = await apiRequest(
76
+ apiUrl,
77
+ token,
78
+ "GET",
79
+ `/org/properties/${propertyId}/environments`
80
+ );
81
+ if (!res.ok) {
82
+ console.error(`Error: ${res.error ?? "Failed to list environments"}`);
83
+ process.exit(1);
84
+ }
85
+ return res.items ?? [];
86
+ }
87
+ async function handleList(argv, apiUrl, token) {
88
+ const json = hasFlag(argv, "--json");
89
+ const propertyId = await resolveApplicationId(argv, apiUrl, token);
90
+ const items = await fetchEnvironments(propertyId, apiUrl, token);
91
+ if (json) {
92
+ console.log(JSON.stringify(items, null, 2));
93
+ return;
94
+ }
95
+ if (items.length === 0) {
96
+ console.log("No environments found.");
97
+ return;
98
+ }
99
+ console.log(`${pad("Name", 28)} ${pad("Type", 11)} ${pad("Default", 8)} ${pad("URL", 36)} Template`);
100
+ for (const e of items) {
101
+ console.log(
102
+ `${pad(e.name, 28)} ${pad(e.type, 11)} ${pad(e.isDefault ? "yes" : "", 8)} ${pad(e.url || "(none)", 36)} ${e.sandboxTemplateId ?? ""}`
103
+ );
104
+ }
105
+ }
106
+ async function handleCreate(argv, apiUrl, token) {
107
+ const json = hasFlag(argv, "--json");
108
+ const propertyId = await resolveApplicationId(argv, apiUrl, token);
109
+ const name = getArgValue(argv, "--name");
110
+ const type = getArgValue(argv, "--type") ?? "permanent";
111
+ const url = getArgValue(argv, "--url");
112
+ const sandboxTemplateId = getArgValue(argv, "--sandbox-template");
113
+ const loginPath = getArgValue(argv, "--login-path");
114
+ const description = getArgValue(argv, "--description");
115
+ const isDefault = hasFlag(argv, "--default");
116
+ if (!name) {
117
+ console.error("Error: --name is required.");
118
+ process.exit(1);
119
+ }
120
+ if (type === "sandbox" && !sandboxTemplateId) {
121
+ console.error("Error: --sandbox-template <uuid> is required when --type sandbox.");
122
+ process.exit(1);
123
+ }
124
+ if (type !== "sandbox" && !url) {
125
+ console.error(`Error: --url is required for --type ${type}.`);
126
+ process.exit(1);
127
+ }
128
+ const body = { name, type };
129
+ if (url !== void 0) body.url = url;
130
+ if (sandboxTemplateId !== void 0) body.sandboxTemplateId = sandboxTemplateId;
131
+ if (loginPath !== void 0) body.loginPath = loginPath;
132
+ if (description !== void 0) body.description = description;
133
+ if (isDefault) body.isDefault = true;
134
+ const result = await apiRequest(
135
+ apiUrl,
136
+ token,
137
+ "POST",
138
+ `/org/properties/${propertyId}/environments`,
139
+ body
140
+ );
141
+ if (!result.ok) {
142
+ if (json) console.log(JSON.stringify(result, null, 2));
143
+ else console.error(`Error: ${result.error ?? "Unknown error"}`);
144
+ process.exit(1);
145
+ }
146
+ if (json) {
147
+ console.log(JSON.stringify(result, null, 2));
148
+ return;
149
+ }
150
+ console.log(`Created ${type} environment "${name}" (${result.item?.id ?? "?"})`);
151
+ }
152
+ async function handleSetDefault(argv, apiUrl, token) {
153
+ const json = hasFlag(argv, "--json");
154
+ const propertyId = await resolveApplicationId(argv, apiUrl, token);
155
+ const envArg = getArgValue(argv, "--environment");
156
+ if (!envArg) {
157
+ console.error("Error: --environment <name|id> is required.");
158
+ process.exit(1);
159
+ }
160
+ const items = await fetchEnvironments(propertyId, apiUrl, token);
161
+ const match = items.find(
162
+ (e) => e.id === envArg || e.name.toLowerCase() === envArg.toLowerCase()
163
+ );
164
+ if (!match) {
165
+ console.error(`Error: Environment "${envArg}" not found for this application.`);
166
+ if (items.length > 0) {
167
+ console.error("Available environments:");
168
+ for (const e of items) console.error(` - ${e.name} (${e.id})`);
169
+ }
170
+ process.exit(1);
171
+ }
172
+ const result = await apiRequest(
173
+ apiUrl,
174
+ token,
175
+ "POST",
176
+ `/org/properties/${propertyId}/environments/${match.id}/set-default`
177
+ );
178
+ if (!result.ok) {
179
+ if (json) console.log(JSON.stringify(result, null, 2));
180
+ else console.error(`Error: ${result.error ?? "Unknown error"}`);
181
+ process.exit(1);
182
+ }
183
+ if (json) {
184
+ console.log(JSON.stringify({ ok: true, environmentId: match.id }, null, 2));
185
+ return;
186
+ }
187
+ console.log(`Set "${match.name}" (${match.id}) as the default environment.`);
188
+ }
189
+ async function runEnvironment(argv) {
190
+ const [subCommand, ...rest] = argv;
191
+ if (!subCommand || subCommand === "help" || hasFlag(argv, "--help", "-h")) {
192
+ printHelp();
193
+ return;
194
+ }
195
+ const { apiUrl, token } = await resolveConfig(argv);
196
+ const globalFlags = /* @__PURE__ */ new Set(["--env", "--api-url", "--token"]);
197
+ const args = rest.filter((arg, i) => {
198
+ if (globalFlags.has(arg)) return false;
199
+ if (i > 0 && globalFlags.has(rest[i - 1])) return false;
200
+ return true;
201
+ });
202
+ switch (subCommand) {
203
+ case "list":
204
+ await handleList(args, apiUrl, token);
205
+ break;
206
+ case "create":
207
+ await handleCreate(args, apiUrl, token);
208
+ break;
209
+ case "set-default":
210
+ await handleSetDefault(args, apiUrl, token);
211
+ break;
212
+ default:
213
+ console.error(`Unknown sub-command: ${subCommand}`);
214
+ printHelp();
215
+ process.exit(1);
216
+ }
217
+ }
218
+ export {
219
+ runEnvironment
220
+ };
221
+ //# sourceMappingURL=environment-RQVU4P5M.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/environment.ts"],"sourcesContent":["/**\n * CLI Environment Management\n *\n * List, create, and set the default environment for an application, including\n * `type='sandbox'` environments backed by a verified sandbox template. Reuses\n * the existing `/org/properties/:id/environments` endpoints — no new API.\n */\n\nimport process from 'node:process';\nimport { resolveConfig, hasFlag, getArgValue } from './auth.js';\nimport { fetchProperties, apiRequest } from './cli-helpers.js';\n\ntype EnvironmentItem = {\n id: string;\n name: string;\n type: 'permanent' | 'ephemeral' | 'local' | 'sandbox';\n url: string;\n isDefault: boolean;\n sandboxTemplateId: string | null;\n};\n\nfunction pad(s: string, n: number): string {\n return s.padEnd(n);\n}\n\nfunction printHelp(): void {\n console.log(\n [\n 'canary environment: Manage application environments (alias: canary env)',\n '',\n 'Sub-commands:',\n ' list [options] List environments for an application',\n ' create [options] Create an environment (incl. sandbox)',\n ' set-default [options] Set an environment as the application default',\n '',\n 'List options:',\n ' --application <name|id> Application (required; alias: --property)',\n '',\n 'Create options:',\n ' --application <name|id> Application (required; alias: --property)',\n ' --name <name> Environment name (required)',\n ' --type <permanent|ephemeral|local|sandbox> Environment type (default: permanent)',\n ' --url <url> Base URL (required unless --type sandbox)',\n ' --sandbox-template <uuid> Backing template (required iff --type sandbox)',\n ' --login-path </path> Per-env login path override',\n ' --description <text> Optional description',\n ' --default Set this environment as the application default',\n '',\n 'Set-default options:',\n ' --application <name|id> Application (required; alias: --property)',\n ' --environment <name|id> Environment to make default (required)',\n '',\n 'Common options:',\n ' --json Output as JSON',\n ].join('\\n')\n );\n}\n\n/** Resolve `--application`/`--property` (name or id) to a property id. */\nasync function resolveApplicationId(\n argv: string[],\n apiUrl: string,\n token: string\n): Promise<string> {\n const arg = getArgValue(argv, '--application') ?? getArgValue(argv, '--property');\n if (!arg) {\n console.error('Error: --application <name|id> is required.');\n process.exit(1);\n }\n const properties = await fetchProperties(apiUrl, token);\n const match = properties.find(\n (p) => p.id === arg || p.name.toLowerCase() === arg.toLowerCase()\n );\n if (!match) {\n console.error(`Error: Application \"${arg}\" 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 return match.id;\n}\n\nasync function fetchEnvironments(\n propertyId: string,\n apiUrl: string,\n token: string\n): Promise<EnvironmentItem[]> {\n const res = await apiRequest<{ ok: boolean; items?: EnvironmentItem[]; error?: string }>(\n apiUrl,\n token,\n 'GET',\n `/org/properties/${propertyId}/environments`\n );\n if (!res.ok) {\n console.error(`Error: ${res.error ?? 'Failed to list environments'}`);\n process.exit(1);\n }\n return res.items ?? [];\n}\n\nasync function handleList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const json = hasFlag(argv, '--json');\n const propertyId = await resolveApplicationId(argv, apiUrl, token);\n const items = await fetchEnvironments(propertyId, apiUrl, token);\n\n if (json) {\n console.log(JSON.stringify(items, null, 2));\n return;\n }\n if (items.length === 0) {\n console.log('No environments found.');\n return;\n }\n console.log(`${pad('Name', 28)} ${pad('Type', 11)} ${pad('Default', 8)} ${pad('URL', 36)} Template`);\n for (const e of items) {\n console.log(\n `${pad(e.name, 28)} ${pad(e.type, 11)} ${pad(e.isDefault ? 'yes' : '', 8)} ` +\n `${pad(e.url || '(none)', 36)} ${e.sandboxTemplateId ?? ''}`\n );\n }\n}\n\nasync function handleCreate(argv: string[], apiUrl: string, token: string): Promise<void> {\n const json = hasFlag(argv, '--json');\n const propertyId = await resolveApplicationId(argv, apiUrl, token);\n const name = getArgValue(argv, '--name');\n const type = (getArgValue(argv, '--type') ?? 'permanent') as EnvironmentItem['type'];\n const url = getArgValue(argv, '--url');\n const sandboxTemplateId = getArgValue(argv, '--sandbox-template');\n const loginPath = getArgValue(argv, '--login-path');\n const description = getArgValue(argv, '--description');\n const isDefault = hasFlag(argv, '--default');\n\n if (!name) {\n console.error('Error: --name is required.');\n process.exit(1);\n }\n if (type === 'sandbox' && !sandboxTemplateId) {\n console.error('Error: --sandbox-template <uuid> is required when --type sandbox.');\n process.exit(1);\n }\n if (type !== 'sandbox' && !url) {\n console.error(`Error: --url is required for --type ${type}.`);\n process.exit(1);\n }\n\n const body: Record<string, unknown> = { name, type };\n if (url !== undefined) body.url = url;\n if (sandboxTemplateId !== undefined) body.sandboxTemplateId = sandboxTemplateId;\n if (loginPath !== undefined) body.loginPath = loginPath;\n if (description !== undefined) body.description = description;\n if (isDefault) body.isDefault = true;\n\n const result = await apiRequest<{ ok: boolean; item?: EnvironmentItem; error?: string }>(\n apiUrl,\n token,\n 'POST',\n `/org/properties/${propertyId}/environments`,\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 if (json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n console.log(`Created ${type} environment \"${name}\" (${result.item?.id ?? '?'})`);\n}\n\nasync function handleSetDefault(argv: string[], apiUrl: string, token: string): Promise<void> {\n const json = hasFlag(argv, '--json');\n const propertyId = await resolveApplicationId(argv, apiUrl, token);\n const envArg = getArgValue(argv, '--environment');\n if (!envArg) {\n console.error('Error: --environment <name|id> is required.');\n process.exit(1);\n }\n\n const items = await fetchEnvironments(propertyId, apiUrl, token);\n const match = items.find(\n (e) => e.id === envArg || e.name.toLowerCase() === envArg.toLowerCase()\n );\n if (!match) {\n console.error(`Error: Environment \"${envArg}\" not found for this application.`);\n if (items.length > 0) {\n console.error('Available environments:');\n for (const e of items) console.error(` - ${e.name} (${e.id})`);\n }\n process.exit(1);\n }\n\n const result = await apiRequest<{ ok: boolean; error?: string }>(\n apiUrl,\n token,\n 'POST',\n `/org/properties/${propertyId}/environments/${match.id}/set-default`\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 if (json) {\n console.log(JSON.stringify({ ok: true, environmentId: match.id }, null, 2));\n return;\n }\n console.log(`Set \"${match.name}\" (${match.id}) as the default environment.`);\n}\n\nexport async function runEnvironment(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 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 'set-default':\n await handleSetDefault(args, apiUrl, token);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
@@ -4,15 +4,16 @@ import {
4
4
  fetchList,
5
5
  parseLifecycleStage,
6
6
  toLifecycleLabel
7
- } from "./chunk-WOHL4FTB.js";
8
- import "./chunk-SJJW77WN.js";
7
+ } from "./chunk-CQE46HSM.js";
9
8
  import "./chunk-3CZU7XCS.js";
10
9
  import {
11
10
  getArgValue,
12
11
  hasFlag,
13
12
  resolveConfig
14
- } from "./chunk-A4OFTUVV.js";
13
+ } from "./chunk-PZ4LCN6K.js";
14
+ import "./chunk-JZMJUPZP.js";
15
15
  import "./chunk-JWHYXEA2.js";
16
+ import "./chunk-QGI4UCJX.js";
16
17
  import "./chunk-VKVL7WBN.js";
17
18
 
18
19
  // src/feature-flag.ts
@@ -37,26 +38,74 @@ async function handleList(argv, apiUrl, token) {
37
38
  const lifecycle = `lifecycle=${toLifecycleLabel(flag.lifecycleStage)}`;
38
39
  const finalValue = flag.lifecycleStage === "active" ? "" : ` final=${flag.finalValue === true ? "true" : "false"}`;
39
40
  const stale = flag.isStale ? " [STALE]" : "";
40
- console.log(` ${flag.name} ${flag.description ?? ""} (${lifecycle}${finalValue}) [orgs=${orgCount}, users=${userCount}]${stale}`);
41
+ const product = flag.productCardId ? ` product=${flag.productTitle ?? flag.productCardId}` : "";
42
+ console.log(` ${flag.name} ${flag.description ?? ""} (${lifecycle}${finalValue}) [orgs=${orgCount}, users=${userCount}]${product}${stale}`);
41
43
  }
42
44
  }
43
45
  async function handleCreate(argv, apiUrl, token) {
44
46
  const name = argv[0];
45
47
  if (!name || name.startsWith("--")) {
46
48
  console.error("Error: Missing flag name.");
47
- console.error("Usage: canary feature-flag create <name> [--description <text>]");
49
+ console.error("Usage: canary feature-flag create <name> [--description <text>] [--product <productCardId>]");
48
50
  process.exit(1);
49
51
  }
50
52
  const description = getArgValue(argv, "--description") ?? null;
53
+ const productCardId = getArgValue(argv, "--product") ?? null;
51
54
  const result = await apiRequest(apiUrl, token, "POST", "/superadmin/feature-flags", {
52
55
  name,
53
- description
56
+ description,
57
+ productCardId
54
58
  });
55
59
  if (!result.ok) {
56
60
  console.error(`Error: ${result.error}`);
57
61
  process.exit(1);
58
62
  }
59
- console.log(`Created feature flag: ${name}`);
63
+ console.log(`Created feature flag: ${name}${productCardId ? ` (product ${productCardId})` : ""}`);
64
+ }
65
+ async function handleProduct(argv, apiUrl, token) {
66
+ const name = argv[0];
67
+ const productCardId = getArgValue(argv, "--product");
68
+ const clear = hasFlag(argv, "--clear");
69
+ if (!name || name.startsWith("--")) {
70
+ console.error("Error: Missing flag name.");
71
+ console.error("Usage: canary feature-flag product <name> (--product <productCardId> | --clear)");
72
+ process.exit(1);
73
+ }
74
+ if (productCardId && clear || !productCardId && !clear) {
75
+ console.error("Error: Provide either --product <productCardId> or --clear.");
76
+ process.exit(1);
77
+ }
78
+ const result = await apiRequest(
79
+ apiUrl,
80
+ token,
81
+ "POST",
82
+ `/superadmin/feature-flags/${encodeURIComponent(name)}/product`,
83
+ { productCardId: clear ? null : productCardId }
84
+ );
85
+ if (!result.ok) {
86
+ console.error(`Error: ${result.error}`);
87
+ process.exit(1);
88
+ }
89
+ console.log(
90
+ clear ? `Cleared product link for ${name}` : `Linked ${name} to product ${result.flag?.productTitle ?? productCardId}`
91
+ );
92
+ }
93
+ async function handleProducts(argv, apiUrl, token) {
94
+ const jsonOutput = hasFlag(argv, "--json");
95
+ const search = getArgValue(argv, "--search");
96
+ const path = search ? `/superadmin/product-cards?search=${encodeURIComponent(search)}` : "/superadmin/product-cards";
97
+ const products = await fetchList(apiUrl, token, path, "products");
98
+ if (jsonOutput) {
99
+ console.log(JSON.stringify(products, null, 2));
100
+ return;
101
+ }
102
+ if (products.length === 0) {
103
+ console.log("No product cards found.");
104
+ return;
105
+ }
106
+ for (const product of products) {
107
+ console.log(` ${product.id} ${product.title} (stage=${product.stage}, org=${product.orgName})`);
108
+ }
60
109
  }
61
110
  async function handleDelete(argv, apiUrl, token) {
62
111
  const name = argv[0];
@@ -222,20 +271,27 @@ function printFeatureFlagHelp() {
222
271
  "",
223
272
  "Sub-commands:",
224
273
  " list List all feature flags",
225
- " create <name> [--description <text>] Create a new flag",
274
+ " create <name> [--description <text>] [--product <productCardId>]",
275
+ " Create a new flag (optionally linked to a product)",
226
276
  " delete <name> Delete a flag and all its gates",
227
277
  " enable <name> (--org <orgId> | --user <userId>)",
228
278
  " Enable a flag for an org or user",
229
279
  " disable <name> (--org <orgId> | --user <userId>)",
230
- " Disable a flag for an org or user",
280
+ " Disable a flag for an org or user (kept as 'was enabled' history)",
231
281
  " lifecycle <name> --stage <stage> [--final-value true|false]",
232
282
  " Mark lifecycle + final value",
283
+ " product <name> (--product <productCardId> | --clear)",
284
+ " Link/unlink a flag to a product board item",
285
+ " products [--search <text>] List product board items (find product card ids)",
233
286
  "",
234
287
  "Stages: active, deprecated, ready_for_cleanup",
235
288
  "",
236
289
  "Options:",
237
290
  " --org <orgId> Target organization",
238
291
  " --user <userId> Target user",
292
+ " --product <productCardId> Product board item (cards.id) to link",
293
+ " --clear Clear the product link (product sub-command only)",
294
+ " --search <text> Filter product cards by title (products sub-command only)",
239
295
  " --final-value <true|false> Final value for deprecated/ready_for_cleanup",
240
296
  " --clear-final-value Clear final value (only valid with --stage active)",
241
297
  " --env <env> Target environment (prod, dev, local)",
@@ -271,6 +327,12 @@ async function runFeatureFlag(argv) {
271
327
  case "lifecycle":
272
328
  await handleLifecycle(rest, apiUrl, token);
273
329
  break;
330
+ case "product":
331
+ await handleProduct(rest, apiUrl, token);
332
+ break;
333
+ case "products":
334
+ await handleProducts(rest, apiUrl, token);
335
+ break;
274
336
  default:
275
337
  console.error(`Unknown sub-command: ${subCommand}`);
276
338
  printFeatureFlagHelp();
@@ -280,4 +342,4 @@ async function runFeatureFlag(argv) {
280
342
  export {
281
343
  runFeatureFlag
282
344
  };
283
- //# sourceMappingURL=feature-flag-T2LRZME3.js.map
345
+ //# sourceMappingURL=feature-flag-XG26RURR.js.map