@gpc-cli/cli 0.9.64 → 0.9.66

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 (30) hide show
  1. package/README.md +13 -12
  2. package/dist/bin.js +2 -2
  3. package/dist/{changelog-EHQYZP22.js → changelog-STYBBYDC.js} +8 -2
  4. package/dist/changelog-STYBBYDC.js.map +1 -0
  5. package/dist/{chunk-I3SFXLIY.js → chunk-IUG4225Q.js} +11 -11
  6. package/dist/{config-SK7BOURM.js → config-DDZMNYOB.js} +2 -2
  7. package/dist/{docs-WVJCDX5X.js → docs-OU6LSSJD.js} +16 -7
  8. package/dist/{docs-WVJCDX5X.js.map → docs-OU6LSSJD.js.map} +1 -1
  9. package/dist/{doctor-FSUI44DD.js → doctor-QRHXY3FC.js} +181 -10
  10. package/dist/doctor-QRHXY3FC.js.map +1 -0
  11. package/dist/{feedback-PDQU5E6S.js → feedback-C2BA7CK6.js} +2 -2
  12. package/dist/generated/docs-bundle.json +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/{preflight-KIWZPFTX.js → preflight-BL67VGUX.js} +54 -1
  15. package/dist/preflight-BL67VGUX.js.map +1 -0
  16. package/dist/{update-E4VGHQUR.js → update-GEH352BE.js} +2 -2
  17. package/dist/verify-O2PSBTIC.js +330 -0
  18. package/dist/verify-O2PSBTIC.js.map +1 -0
  19. package/dist/{version-HXUIOHCL.js → version-2RUEWMPK.js} +2 -2
  20. package/package.json +4 -4
  21. package/dist/changelog-EHQYZP22.js.map +0 -1
  22. package/dist/doctor-FSUI44DD.js.map +0 -1
  23. package/dist/preflight-KIWZPFTX.js.map +0 -1
  24. package/dist/verify-H4ZUVHMZ.js +0 -98
  25. package/dist/verify-H4ZUVHMZ.js.map +0 -1
  26. /package/dist/{chunk-I3SFXLIY.js.map → chunk-IUG4225Q.js.map} +0 -0
  27. /package/dist/{config-SK7BOURM.js.map → config-DDZMNYOB.js.map} +0 -0
  28. /package/dist/{feedback-PDQU5E6S.js.map → feedback-C2BA7CK6.js.map} +0 -0
  29. /package/dist/{update-E4VGHQUR.js.map → update-GEH352BE.js.map} +0 -0
  30. /package/dist/{version-HXUIOHCL.js.map → version-2RUEWMPK.js.map} +0 -0
package/README.md CHANGED
@@ -22,22 +22,23 @@ gpc reviews reply <review-id> --text "Thanks for the feedback!"
22
22
  gpc listings push --dir metadata/ # Sync store metadata (Fastlane-compatible)
23
23
  gpc changelog generate --target play-store --locales auto --ai # AI-translated "What's new" in every locale
24
24
  gpc enterprise publish app.aab --account 123 --title "Private App" # Managed Google Play
25
+ gpc verify # Developer verification readiness
25
26
  gpc doctor # 20 setup checks
26
27
  ```
27
28
 
28
29
  ## Why this over Fastlane?
29
30
 
30
- | | **GPC** | Fastlane supply |
31
- | ----------------------- | ----------------------------- | --------------- |
32
- | API coverage | **217 endpoints** | ~20 |
33
- | Runtime | Node.js or binary | Ruby + Bundler |
34
- | Cold start | <500ms | 2-3s |
35
- | Reviews & Vitals | Yes | No |
36
- | Subscriptions | Yes | No |
37
- | **Managed Google Play** | **Yes (Play Custom App API)** | No |
38
- | **AI-translated release notes** | **Yes (80+ locales, BYO key)** | No |
39
- | Preflight scanner | 9 offline checks | No |
40
- | CI/CD native | JSON + exit codes | Partial |
31
+ | | **GPC** | Fastlane supply |
32
+ | ------------------------------- | ------------------------------ | --------------- |
33
+ | API coverage | **217 endpoints** | ~20 |
34
+ | Runtime | Node.js or binary | Ruby + Bundler |
35
+ | Cold start | <500ms | 2-3s |
36
+ | Reviews & Vitals | Yes | No |
37
+ | Subscriptions | Yes | No |
38
+ | **Managed Google Play** | **Yes (Play Custom App API)** | No |
39
+ | **AI-translated release notes** | **Yes (80+ locales, BYO key)** | No |
40
+ | Preflight scanner | 9 offline checks | No |
41
+ | CI/CD native | JSON + exit codes | Partial |
41
42
 
42
43
  [Migration guide](https://yasserstudio.github.io/gpc/migration/from-fastlane) with one-to-one command mapping.
43
44
 
@@ -91,7 +92,7 @@ curl -fsSL https://raw.githubusercontent.com/yasserstudio/gpc/main/scripts/insta
91
92
  - [Commands reference](https://yasserstudio.github.io/gpc/commands/)
92
93
  - [CI/CD recipes](https://yasserstudio.github.io/gpc/ci-cd/)
93
94
 
94
- Free to use. 2,076 tests. 90%+ coverage. Every write operation supports `--dry-run`.
95
+ Free to use. 2,143 tests. 90%+ coverage. Every write operation supports `--dry-run`.
95
96
 
96
97
  ## Licensing
97
98
 
package/dist/bin.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  createProgram,
4
4
  handleCliError,
5
5
  loadPlugins
6
- } from "./chunk-I3SFXLIY.js";
6
+ } from "./chunk-IUG4225Q.js";
7
7
  import {
8
8
  checkForUpdate,
9
9
  formatUpdateNotification
@@ -57,7 +57,7 @@ if (!_isJsonMode && !_isQuiet && !_isSetupCommand && !existsSync(getUserConfigPa
57
57
  }
58
58
  await setupNetworking();
59
59
  initAudit(getConfigDir());
60
- var currentVersion = "0.9.64";
60
+ var currentVersion = "0.9.66";
61
61
  var isUpdateCommand = process.argv[2] === "update";
62
62
  var isCompletionProvider = process.argv[2] === "__complete";
63
63
  var updateCheckPromise = isUpdateCommand || isCompletionProvider ? Promise.resolve(null) : checkForUpdate(currentVersion);
@@ -347,7 +347,13 @@ function registerChangelogCommand(program) {
347
347
  `);
348
348
  }
349
349
  if (opts.apply) {
350
- const ok = await performApply({ bundle: translated, program, track: opts.track, dryRun, aiBlock });
350
+ const ok = await performApply({
351
+ bundle: translated,
352
+ program,
353
+ track: opts.track,
354
+ dryRun,
355
+ aiBlock
356
+ });
351
357
  if (!ok) return;
352
358
  }
353
359
  const hasOverflow = translated.overflows.length > 0;
@@ -362,4 +368,4 @@ function registerChangelogCommand(program) {
362
368
  export {
363
369
  registerChangelogCommand
364
370
  };
365
- //# sourceMappingURL=changelog-EHQYZP22.js.map
371
+ //# sourceMappingURL=changelog-STYBBYDC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/changelog.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport {\n fetchChangelog,\n formatChangelogEntry,\n formatOutput,\n generateChangelog,\n RENDERERS,\n renderPlayStore,\n renderPlayStoreMd,\n renderPlayStorePrompt,\n buildLocaleBundle,\n translateBundle,\n resolveAiConfig,\n createTranslator,\n fetchAggregateCost,\n formatPathLabel,\n PROVIDER_WHITELIST,\n resolveLocales,\n validateBundleForApply,\n bundleToReleaseNotes,\n applyReleaseNotes,\n GpcError,\n type OutputMode,\n type PlayStoreFormat,\n} from \"@gpc-cli/core\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { getOutputFormat } from \"../format.js\";\nimport { yellow, dim } from \"../colors.js\";\nimport { resolvePackageName, getClient } from \"../resolve.js\";\n\nconst VALID_OUTPUT_MODES: OutputMode[] = [\"md\", \"json\", \"prompt\"];\nconst VALID_TARGETS = [\"github\", \"play-store\"] as const;\ntype ChangelogTarget = (typeof VALID_TARGETS)[number];\nconst REPO_RE = /^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/;\n\ninterface ApplyContext {\n bundle: Parameters<typeof validateBundleForApply>[0];\n program: Command;\n track: string;\n dryRun: boolean;\n aiBlock?: Record<string, unknown>;\n}\n\nasync function performApply(ctx: ApplyContext): Promise<boolean> {\n const blocked = validateBundleForApply(ctx.bundle);\n if (blocked.length > 0) {\n process.stderr.write(\n `Cannot --apply: ${blocked.length} locale(s) blocked:\\n` +\n blocked.map((b) => ` ${b}`).join(\"\\n\") +\n \"\\n\",\n );\n process.exitCode = 1;\n return false;\n }\n const notes = bundleToReleaseNotes(ctx.bundle);\n const config = await loadConfig();\n const packageName = resolvePackageName(ctx.program.opts()[\"app\"], config);\n if (ctx.dryRun) {\n const payload: Record<string, unknown> = {\n dryRun: true,\n action: \"apply release notes\",\n track: ctx.track,\n packageName,\n localeCount: notes.length,\n releaseNotes: notes,\n };\n if (ctx.aiBlock) payload[\"ai\"] = ctx.aiBlock;\n console.log(JSON.stringify(payload, null, 2));\n return false;\n }\n const client = await getClient(config);\n const result = await applyReleaseNotes(client, packageName, ctx.track, notes);\n process.stderr.write(\n `${dim(`→ Applied ${result.localeCount} locale(s) to draft on ${result.track} (${packageName})`)}\\n`,\n );\n return true;\n}\n\nexport function registerChangelogCommand(program: Command): void {\n const changelog = program\n .command(\"changelog\")\n .description(\"Show release history\")\n .option(\"-n, --limit <count>\", \"Number of releases to show\", parseInt, 5)\n .option(\"--tag <tag>\", \"Show a specific release (e.g., v0.9.43)\")\n .option(\"--all\", \"Show all releases\")\n .action(async (opts: { limit: number; tag?: string; all?: boolean }) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n\n const entries = await fetchChangelog({\n limit: opts.all ? 100 : opts.limit,\n version: opts.tag,\n });\n\n if (entries.length === 0) {\n console.log(\"No releases found.\");\n return;\n }\n\n if (format === \"json\") {\n console.log(formatOutput(entries, \"json\"));\n return;\n }\n\n if (opts.tag || entries.length === 1) {\n console.log(formatChangelogEntry(entries[0]!));\n return;\n }\n\n const header = \"VERSION DATE TITLE\";\n const separator = \"─\".repeat(header.length);\n console.log(header);\n console.log(separator);\n for (const entry of entries) {\n const version = entry.version.padEnd(12);\n const date = entry.date.padEnd(12);\n console.log(`${version} ${date} ${entry.title}`);\n }\n console.log(\"\");\n console.log(\n `Showing ${entries.length} releases. Use --tag <tag> for details, or --all for full history.`,\n );\n });\n\n changelog\n .command(\"generate\")\n .description(\"Generate release notes from local git commits\")\n .option(\"--from <ref>\", \"Starting ref (default: latest v* tag)\")\n .option(\"--to <ref>\", \"Ending ref (default: HEAD)\")\n .option(\"--format <mode>\", \"Renderer: md, json, or prompt\", \"md\")\n .option(\"--repo <owner/name>\", \"Override auto-detected repo (e.g., yasserstudio/gpc)\")\n .option(\"--target <mode>\", \"Output target: github or play-store\", \"github\")\n .option(\n \"--locales <csv|auto>\",\n \"Comma-separated BCP 47 locales, or 'auto' (play-store target only)\",\n )\n .option(\"--ai\", \"Translate non-source locales via LLM (play-store target only, BYO key)\")\n .option(\n \"--provider <name>\",\n `AI provider (${PROVIDER_WHITELIST.join(\"|\")}). Defaults to first env key detected`,\n )\n .option(\"--model <id>\", \"Override default model for the chosen provider\")\n .option(\"--strict\", \"Exit non-zero if warnings, overflows, or translation failures occur\")\n .option(\"--apply\", \"Write notes into the draft release on --track (play-store target only)\")\n .option(\"--track <name>\", \"Play Store track for --apply (default: production)\", \"production\")\n .action(\n async (opts: {\n from?: string;\n to?: string;\n format: string;\n repo?: string;\n target: string;\n locales?: string;\n strict?: boolean;\n ai?: boolean;\n provider?: string;\n model?: string;\n apply?: boolean;\n track: string;\n }) => {\n const dryRun = !!program.opts()[\"dryRun\"];\n const mode = opts.format as OutputMode;\n if (!VALID_OUTPUT_MODES.includes(mode)) {\n process.stderr.write(\n `Invalid --format \"${opts.format}\". Valid: ${VALID_OUTPUT_MODES.join(\", \")}\\n`,\n );\n process.exitCode = 2;\n return;\n }\n if (!VALID_TARGETS.includes(opts.target as ChangelogTarget)) {\n process.stderr.write(\n `Invalid --target \"${opts.target}\". Valid: ${VALID_TARGETS.join(\", \")}\\n`,\n );\n process.exitCode = 2;\n return;\n }\n const target = opts.target as ChangelogTarget;\n if (opts.repo && !REPO_RE.test(opts.repo)) {\n process.stderr.write(\n `Invalid --repo \"${opts.repo}\". Expected \"owner/name\" (e.g., yasserstudio/gpc).\\n`,\n );\n process.exitCode = 2;\n return;\n }\n if (target === \"github\" && opts.locales) {\n process.stderr.write(\n `--locales only applies to --target play-store (current target: github)\\n`,\n );\n process.exitCode = 2;\n return;\n }\n // Only block when the AI-adjacent flags are explicitly set. The root\n // program has its own `--dry-run` flag that may already be set\n // globally by the user for unrelated reasons; we silently ignore it\n // on non-AI code paths.\n if (target === \"github\" && (opts.ai || opts.provider || opts.model)) {\n process.stderr.write(\"--ai / --provider / --model only apply to --target play-store\\n\");\n process.exitCode = 2;\n return;\n }\n // --format prompt + --ai is nonsensical outside --dry-run: it would\n // render a \"please translate this\" prompt from already-translated\n // text. Either inspect the prompt via --dry-run, or pick md/json.\n if (opts.ai && opts.format === \"prompt\" && !dryRun) {\n process.stderr.write(\n \"--ai with --format prompt only makes sense with --dry-run\\n\" +\n \" (otherwise it would re-wrap translated text in a translation prompt).\\n\" +\n \" Hint: use --format md or --format json for live translation, or add --dry-run to inspect the prompt.\\n\",\n );\n process.exitCode = 2;\n return;\n }\n if (opts.apply && target !== \"play-store\") {\n process.stderr.write(\"--apply only applies to --target play-store\\n\");\n process.exitCode = 2;\n return;\n }\n if (opts.apply && mode === \"prompt\") {\n process.stderr.write(\n \"--apply cannot be combined with --format prompt\\n\" +\n \" Hint: use --format md or --format json.\\n\",\n );\n process.exitCode = 2;\n return;\n }\n if (target === \"play-store\" && !opts.locales) {\n process.stderr.write(\n \"--target play-store requires --locales <csv|auto>\\n\" +\n \" Example: --locales en-US,fr-FR,de-DE\\n\" +\n \" Example: --locales auto (reads current Play Store listing — requires --app)\\n\",\n );\n process.exitCode = 2;\n return;\n }\n\n const generated = await generateChangelog({\n from: opts.from,\n to: opts.to,\n repo: opts.repo,\n });\n\n for (const w of generated.warnings) {\n process.stderr.write(`${yellow(\"warn:\")} ${w}\\n`);\n }\n if (generated.warnings.length > 0) {\n process.stderr.write(\n `${dim(`(${generated.warnings.length} warning${generated.warnings.length === 1 ? \"\" : \"s\"} — review before publishing)`)}\\n`,\n );\n }\n\n if (target === \"github\") {\n const output = RENDERERS[mode](generated);\n console.log(output);\n if (opts.strict && generated.warnings.length > 0) {\n process.exitCode = 1;\n }\n return;\n }\n\n // target === \"play-store\"\n let locales: string[];\n try {\n if (opts.locales === \"auto\") {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n locales = await resolveLocales(\"auto\", { client, packageName });\n } else {\n locales = await resolveLocales(opts.locales!);\n }\n } catch (error) {\n if (error instanceof GpcError) {\n process.stderr.write(`${error.message}\\n`);\n if (error.suggestion) process.stderr.write(`${dim(error.suggestion)}\\n`);\n process.exitCode = error.exitCode;\n return;\n }\n throw error;\n }\n\n const playStoreFormat = mode as PlayStoreFormat;\n\n // Non-AI path: existing v0.9.62 behavior\n if (!opts.ai) {\n const { output, bundle } = renderPlayStore(generated, {\n locales,\n format: playStoreFormat,\n });\n console.log(output);\n\n for (const lang of bundle.overflows) {\n process.stderr.write(\n `${yellow(\"warn:\")} ${lang} exceeds ${bundle.limit} chars (truncated)\\n`,\n );\n }\n\n if (opts.apply) {\n const ok = await performApply({ bundle, program, track: opts.track, dryRun });\n if (!ok) return;\n }\n\n const hasOverflow = bundle.overflows.length > 0;\n const hasWarnings = generated.warnings.length > 0;\n if (opts.strict && (hasWarnings || hasOverflow)) {\n process.exitCode = 1;\n }\n return;\n }\n\n // --ai path: resolve config, translate, render with ai block\n let aiConfig;\n try {\n aiConfig = resolveAiConfig({ provider: opts.provider, model: opts.model });\n } catch (error) {\n if (error instanceof GpcError) {\n process.stderr.write(`${error.message}\\n`);\n if (error.suggestion) process.stderr.write(`${dim(error.suggestion)}\\n`);\n process.exitCode = error.exitCode;\n return;\n }\n throw error;\n }\n\n process.stderr.write(`${dim(`→ ${formatPathLabel(aiConfig)}`)}\\n`);\n\n const baseBundle = buildLocaleBundle(generated, {\n locales,\n format: playStoreFormat,\n });\n\n if (dryRun) {\n const preview = renderPlayStorePrompt(baseBundle, generated);\n console.log(preview);\n process.stderr.write(\n `${dim(\"(--dry-run: no API call was made; the prompt above is what would be sent per locale)\")}\\n`,\n );\n return;\n }\n\n const translator = await createTranslator(aiConfig);\n let translated;\n try {\n translated = await translateBundle(baseBundle, {\n translator,\n strict: opts.strict,\n onError: ({ language, reason }) => {\n process.stderr.write(\n `${yellow(\"warn:\")} ${language} translation failed: ${reason}\\n`,\n );\n },\n });\n } catch (error) {\n if (error instanceof GpcError) {\n process.stderr.write(`${error.message}\\n`);\n if (error.suggestion) process.stderr.write(`${dim(error.suggestion)}\\n`);\n process.exitCode = error.exitCode;\n return;\n }\n throw error;\n }\n\n const costUsd =\n aiConfig.path === \"gateway\" ? await fetchAggregateCost(aiConfig.runId) : undefined;\n\n const aiBlock: Record<string, unknown> = {\n path: aiConfig.path,\n provider: aiConfig.provider,\n model: aiConfig.model,\n tokensIn: translated.tokensIn,\n tokensOut: translated.tokensOut,\n };\n if (aiConfig.path === \"gateway\") {\n aiBlock[\"runId\"] = aiConfig.runId;\n if (typeof costUsd === \"number\") aiBlock[\"costUsd\"] = costUsd;\n }\n\n if (playStoreFormat === \"json\") {\n const payload = {\n from: translated.from,\n to: translated.to,\n limit: translated.limit,\n sourceLanguage: translated.sourceLanguage,\n ai: aiBlock,\n locales: translated.locales,\n overflows: translated.overflows,\n failures: translated.failures,\n };\n console.log(JSON.stringify(payload, null, 2));\n } else if (playStoreFormat === \"prompt\") {\n console.log(renderPlayStorePrompt(translated, generated));\n } else {\n console.log(renderPlayStoreMd(translated));\n }\n\n for (const lang of translated.overflows) {\n process.stderr.write(\n `${yellow(\"warn:\")} ${lang} exceeds ${translated.limit} chars (truncated)\\n`,\n );\n }\n\n if (translated.failures.length > 0) {\n process.stderr.write(\n `${dim(`(${translated.failures.length} locale${translated.failures.length === 1 ? \"\" : \"s\"} failed — see placeholders in output)`)}\\n`,\n );\n }\n\n if (typeof costUsd === \"number\") {\n process.stderr.write(`${dim(`(run cost: $${costUsd.toFixed(4)})`)}\\n`);\n }\n\n if (opts.apply) {\n const ok = await performApply({\n bundle: translated,\n program,\n track: opts.track,\n dryRun,\n aiBlock,\n });\n if (!ok) return;\n }\n\n const hasOverflow = translated.overflows.length > 0;\n const hasWarnings = generated.warnings.length > 0;\n const hasFailures = translated.failures.length > 0;\n if (opts.strict && (hasWarnings || hasOverflow || hasFailures)) {\n process.exitCode = 1;\n }\n },\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,kBAAkB;AAK3B,IAAM,qBAAmC,CAAC,MAAM,QAAQ,QAAQ;AAChE,IAAM,gBAAgB,CAAC,UAAU,YAAY;AAE7C,IAAM,UAAU;AAUhB,eAAe,aAAa,KAAqC;AAC/D,QAAM,UAAU,uBAAuB,IAAI,MAAM;AACjD,MAAI,QAAQ,SAAS,GAAG;AACtB,YAAQ,OAAO;AAAA,MACb,mBAAmB,QAAQ,MAAM;AAAA,IAC/B,QAAQ,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,IACtC;AAAA,IACJ;AACA,YAAQ,WAAW;AACnB,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,qBAAqB,IAAI,MAAM;AAC7C,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,cAAc,mBAAmB,IAAI,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACxE,MAAI,IAAI,QAAQ;AACd,UAAM,UAAmC;AAAA,MACvC,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,OAAO,IAAI;AAAA,MACX;AAAA,MACA,aAAa,MAAM;AAAA,MACnB,cAAc;AAAA,IAChB;AACA,QAAI,IAAI,QAAS,SAAQ,IAAI,IAAI,IAAI;AACrC,YAAQ,IAAI,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAC5C,WAAO;AAAA,EACT;AACA,QAAM,SAAS,MAAM,UAAU,MAAM;AACrC,QAAM,SAAS,MAAM,kBAAkB,QAAQ,aAAa,IAAI,OAAO,KAAK;AAC5E,UAAQ,OAAO;AAAA,IACb,GAAG,IAAI,kBAAa,OAAO,WAAW,0BAA0B,OAAO,KAAK,KAAK,WAAW,GAAG,CAAC;AAAA;AAAA,EAClG;AACA,SAAO;AACT;AAEO,SAAS,yBAAyB,SAAwB;AAC/D,QAAM,YAAY,QACf,QAAQ,WAAW,EACnB,YAAY,sBAAsB,EAClC,OAAO,uBAAuB,8BAA8B,UAAU,CAAC,EACvE,OAAO,eAAe,yCAAyC,EAC/D,OAAO,SAAS,mBAAmB,EACnC,OAAO,OAAO,SAAyD;AACtE,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,UAAM,UAAU,MAAM,eAAe;AAAA,MACnC,OAAO,KAAK,MAAM,MAAM,KAAK;AAAA,MAC7B,SAAS,KAAK;AAAA,IAChB,CAAC;AAED,QAAI,QAAQ,WAAW,GAAG;AACxB,cAAQ,IAAI,oBAAoB;AAChC;AAAA,IACF;AAEA,QAAI,WAAW,QAAQ;AACrB,cAAQ,IAAI,aAAa,SAAS,MAAM,CAAC;AACzC;AAAA,IACF;AAEA,QAAI,KAAK,OAAO,QAAQ,WAAW,GAAG;AACpC,cAAQ,IAAI,qBAAqB,QAAQ,CAAC,CAAE,CAAC;AAC7C;AAAA,IACF;AAEA,UAAM,SAAS;AACf,UAAM,YAAY,SAAI,OAAO,OAAO,MAAM;AAC1C,YAAQ,IAAI,MAAM;AAClB,YAAQ,IAAI,SAAS;AACrB,eAAW,SAAS,SAAS;AAC3B,YAAM,UAAU,MAAM,QAAQ,OAAO,EAAE;AACvC,YAAM,OAAO,MAAM,KAAK,OAAO,EAAE;AACjC,cAAQ,IAAI,GAAG,OAAO,IAAI,IAAI,IAAI,MAAM,KAAK,EAAE;AAAA,IACjD;AACA,YAAQ,IAAI,EAAE;AACd,YAAQ;AAAA,MACN,WAAW,QAAQ,MAAM;AAAA,IAC3B;AAAA,EACF,CAAC;AAEH,YACG,QAAQ,UAAU,EAClB,YAAY,+CAA+C,EAC3D,OAAO,gBAAgB,uCAAuC,EAC9D,OAAO,cAAc,4BAA4B,EACjD,OAAO,mBAAmB,iCAAiC,IAAI,EAC/D,OAAO,uBAAuB,sDAAsD,EACpF,OAAO,mBAAmB,uCAAuC,QAAQ,EACzE;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,QAAQ,wEAAwE,EACvF;AAAA,IACC;AAAA,IACA,gBAAgB,mBAAmB,KAAK,GAAG,CAAC;AAAA,EAC9C,EACC,OAAO,gBAAgB,gDAAgD,EACvE,OAAO,YAAY,qEAAqE,EACxF,OAAO,WAAW,wEAAwE,EAC1F,OAAO,kBAAkB,sDAAsD,YAAY,EAC3F;AAAA,IACC,OAAO,SAaD;AACJ,YAAM,SAAS,CAAC,CAAC,QAAQ,KAAK,EAAE,QAAQ;AACxC,YAAM,OAAO,KAAK;AAClB,UAAI,CAAC,mBAAmB,SAAS,IAAI,GAAG;AACtC,gBAAQ,OAAO;AAAA,UACb,qBAAqB,KAAK,MAAM,aAAa,mBAAmB,KAAK,IAAI,CAAC;AAAA;AAAA,QAC5E;AACA,gBAAQ,WAAW;AACnB;AAAA,MACF;AACA,UAAI,CAAC,cAAc,SAAS,KAAK,MAAyB,GAAG;AAC3D,gBAAQ,OAAO;AAAA,UACb,qBAAqB,KAAK,MAAM,aAAa,cAAc,KAAK,IAAI,CAAC;AAAA;AAAA,QACvE;AACA,gBAAQ,WAAW;AACnB;AAAA,MACF;AACA,YAAM,SAAS,KAAK;AACpB,UAAI,KAAK,QAAQ,CAAC,QAAQ,KAAK,KAAK,IAAI,GAAG;AACzC,gBAAQ,OAAO;AAAA,UACb,mBAAmB,KAAK,IAAI;AAAA;AAAA,QAC9B;AACA,gBAAQ,WAAW;AACnB;AAAA,MACF;AACA,UAAI,WAAW,YAAY,KAAK,SAAS;AACvC,gBAAQ,OAAO;AAAA,UACb;AAAA;AAAA,QACF;AACA,gBAAQ,WAAW;AACnB;AAAA,MACF;AAKA,UAAI,WAAW,aAAa,KAAK,MAAM,KAAK,YAAY,KAAK,QAAQ;AACnE,gBAAQ,OAAO,MAAM,iEAAiE;AACtF,gBAAQ,WAAW;AACnB;AAAA,MACF;AAIA,UAAI,KAAK,MAAM,KAAK,WAAW,YAAY,CAAC,QAAQ;AAClD,gBAAQ,OAAO;AAAA,UACb;AAAA,QAGF;AACA,gBAAQ,WAAW;AACnB;AAAA,MACF;AACA,UAAI,KAAK,SAAS,WAAW,cAAc;AACzC,gBAAQ,OAAO,MAAM,+CAA+C;AACpE,gBAAQ,WAAW;AACnB;AAAA,MACF;AACA,UAAI,KAAK,SAAS,SAAS,UAAU;AACnC,gBAAQ,OAAO;AAAA,UACb;AAAA,QAEF;AACA,gBAAQ,WAAW;AACnB;AAAA,MACF;AACA,UAAI,WAAW,gBAAgB,CAAC,KAAK,SAAS;AAC5C,gBAAQ,OAAO;AAAA,UACb;AAAA,QAGF;AACA,gBAAQ,WAAW;AACnB;AAAA,MACF;AAEA,YAAM,YAAY,MAAM,kBAAkB;AAAA,QACxC,MAAM,KAAK;AAAA,QACX,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,MACb,CAAC;AAED,iBAAW,KAAK,UAAU,UAAU;AAClC,gBAAQ,OAAO,MAAM,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC;AAAA,CAAI;AAAA,MAClD;AACA,UAAI,UAAU,SAAS,SAAS,GAAG;AACjC,gBAAQ,OAAO;AAAA,UACb,GAAG,IAAI,IAAI,UAAU,SAAS,MAAM,WAAW,UAAU,SAAS,WAAW,IAAI,KAAK,GAAG,mCAA8B,CAAC;AAAA;AAAA,QAC1H;AAAA,MACF;AAEA,UAAI,WAAW,UAAU;AACvB,cAAM,SAAS,UAAU,IAAI,EAAE,SAAS;AACxC,gBAAQ,IAAI,MAAM;AAClB,YAAI,KAAK,UAAU,UAAU,SAAS,SAAS,GAAG;AAChD,kBAAQ,WAAW;AAAA,QACrB;AACA;AAAA,MACF;AAGA,UAAI;AACJ,UAAI;AACF,YAAI,KAAK,YAAY,QAAQ;AAC3B,gBAAM,SAAS,MAAM,WAAW;AAChC,gBAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,gBAAM,SAAS,MAAM,UAAU,MAAM;AACrC,oBAAU,MAAM,eAAe,QAAQ,EAAE,QAAQ,YAAY,CAAC;AAAA,QAChE,OAAO;AACL,oBAAU,MAAM,eAAe,KAAK,OAAQ;AAAA,QAC9C;AAAA,MACF,SAAS,OAAO;AACd,YAAI,iBAAiB,UAAU;AAC7B,kBAAQ,OAAO,MAAM,GAAG,MAAM,OAAO;AAAA,CAAI;AACzC,cAAI,MAAM,WAAY,SAAQ,OAAO,MAAM,GAAG,IAAI,MAAM,UAAU,CAAC;AAAA,CAAI;AACvE,kBAAQ,WAAW,MAAM;AACzB;AAAA,QACF;AACA,cAAM;AAAA,MACR;AAEA,YAAM,kBAAkB;AAGxB,UAAI,CAAC,KAAK,IAAI;AACZ,cAAM,EAAE,QAAQ,OAAO,IAAI,gBAAgB,WAAW;AAAA,UACpD;AAAA,UACA,QAAQ;AAAA,QACV,CAAC;AACD,gBAAQ,IAAI,MAAM;AAElB,mBAAW,QAAQ,OAAO,WAAW;AACnC,kBAAQ,OAAO;AAAA,YACb,GAAG,OAAO,OAAO,CAAC,IAAI,IAAI,YAAY,OAAO,KAAK;AAAA;AAAA,UACpD;AAAA,QACF;AAEA,YAAI,KAAK,OAAO;AACd,gBAAM,KAAK,MAAM,aAAa,EAAE,QAAQ,SAAS,OAAO,KAAK,OAAO,OAAO,CAAC;AAC5E,cAAI,CAAC,GAAI;AAAA,QACX;AAEA,cAAMA,eAAc,OAAO,UAAU,SAAS;AAC9C,cAAMC,eAAc,UAAU,SAAS,SAAS;AAChD,YAAI,KAAK,WAAWA,gBAAeD,eAAc;AAC/C,kBAAQ,WAAW;AAAA,QACrB;AACA;AAAA,MACF;AAGA,UAAI;AACJ,UAAI;AACF,mBAAW,gBAAgB,EAAE,UAAU,KAAK,UAAU,OAAO,KAAK,MAAM,CAAC;AAAA,MAC3E,SAAS,OAAO;AACd,YAAI,iBAAiB,UAAU;AAC7B,kBAAQ,OAAO,MAAM,GAAG,MAAM,OAAO;AAAA,CAAI;AACzC,cAAI,MAAM,WAAY,SAAQ,OAAO,MAAM,GAAG,IAAI,MAAM,UAAU,CAAC;AAAA,CAAI;AACvE,kBAAQ,WAAW,MAAM;AACzB;AAAA,QACF;AACA,cAAM;AAAA,MACR;AAEA,cAAQ,OAAO,MAAM,GAAG,IAAI,UAAK,gBAAgB,QAAQ,CAAC,EAAE,CAAC;AAAA,CAAI;AAEjE,YAAM,aAAa,kBAAkB,WAAW;AAAA,QAC9C;AAAA,QACA,QAAQ;AAAA,MACV,CAAC;AAED,UAAI,QAAQ;AACV,cAAM,UAAU,sBAAsB,YAAY,SAAS;AAC3D,gBAAQ,IAAI,OAAO;AACnB,gBAAQ,OAAO;AAAA,UACb,GAAG,IAAI,sFAAsF,CAAC;AAAA;AAAA,QAChG;AACA;AAAA,MACF;AAEA,YAAM,aAAa,MAAM,iBAAiB,QAAQ;AAClD,UAAI;AACJ,UAAI;AACF,qBAAa,MAAM,gBAAgB,YAAY;AAAA,UAC7C;AAAA,UACA,QAAQ,KAAK;AAAA,UACb,SAAS,CAAC,EAAE,UAAU,OAAO,MAAM;AACjC,oBAAQ,OAAO;AAAA,cACb,GAAG,OAAO,OAAO,CAAC,IAAI,QAAQ,wBAAwB,MAAM;AAAA;AAAA,YAC9D;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH,SAAS,OAAO;AACd,YAAI,iBAAiB,UAAU;AAC7B,kBAAQ,OAAO,MAAM,GAAG,MAAM,OAAO;AAAA,CAAI;AACzC,cAAI,MAAM,WAAY,SAAQ,OAAO,MAAM,GAAG,IAAI,MAAM,UAAU,CAAC;AAAA,CAAI;AACvE,kBAAQ,WAAW,MAAM;AACzB;AAAA,QACF;AACA,cAAM;AAAA,MACR;AAEA,YAAM,UACJ,SAAS,SAAS,YAAY,MAAM,mBAAmB,SAAS,KAAK,IAAI;AAE3E,YAAM,UAAmC;AAAA,QACvC,MAAM,SAAS;AAAA,QACf,UAAU,SAAS;AAAA,QACnB,OAAO,SAAS;AAAA,QAChB,UAAU,WAAW;AAAA,QACrB,WAAW,WAAW;AAAA,MACxB;AACA,UAAI,SAAS,SAAS,WAAW;AAC/B,gBAAQ,OAAO,IAAI,SAAS;AAC5B,YAAI,OAAO,YAAY,SAAU,SAAQ,SAAS,IAAI;AAAA,MACxD;AAEA,UAAI,oBAAoB,QAAQ;AAC9B,cAAM,UAAU;AAAA,UACd,MAAM,WAAW;AAAA,UACjB,IAAI,WAAW;AAAA,UACf,OAAO,WAAW;AAAA,UAClB,gBAAgB,WAAW;AAAA,UAC3B,IAAI;AAAA,UACJ,SAAS,WAAW;AAAA,UACpB,WAAW,WAAW;AAAA,UACtB,UAAU,WAAW;AAAA,QACvB;AACA,gBAAQ,IAAI,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAAA,MAC9C,WAAW,oBAAoB,UAAU;AACvC,gBAAQ,IAAI,sBAAsB,YAAY,SAAS,CAAC;AAAA,MAC1D,OAAO;AACL,gBAAQ,IAAI,kBAAkB,UAAU,CAAC;AAAA,MAC3C;AAEA,iBAAW,QAAQ,WAAW,WAAW;AACvC,gBAAQ,OAAO;AAAA,UACb,GAAG,OAAO,OAAO,CAAC,IAAI,IAAI,YAAY,WAAW,KAAK;AAAA;AAAA,QACxD;AAAA,MACF;AAEA,UAAI,WAAW,SAAS,SAAS,GAAG;AAClC,gBAAQ,OAAO;AAAA,UACb,GAAG,IAAI,IAAI,WAAW,SAAS,MAAM,UAAU,WAAW,SAAS,WAAW,IAAI,KAAK,GAAG,4CAAuC,CAAC;AAAA;AAAA,QACpI;AAAA,MACF;AAEA,UAAI,OAAO,YAAY,UAAU;AAC/B,gBAAQ,OAAO,MAAM,GAAG,IAAI,eAAe,QAAQ,QAAQ,CAAC,CAAC,GAAG,CAAC;AAAA,CAAI;AAAA,MACvE;AAEA,UAAI,KAAK,OAAO;AACd,cAAM,KAAK,MAAM,aAAa;AAAA,UAC5B,QAAQ;AAAA,UACR;AAAA,UACA,OAAO,KAAK;AAAA,UACZ;AAAA,UACA;AAAA,QACF,CAAC;AACD,YAAI,CAAC,GAAI;AAAA,MACX;AAEA,YAAM,cAAc,WAAW,UAAU,SAAS;AAClD,YAAM,cAAc,UAAU,SAAS,SAAS;AAChD,YAAM,cAAc,WAAW,SAAS,SAAS;AACjD,UAAI,KAAK,WAAW,eAAe,eAAe,cAAc;AAC9D,gBAAQ,WAAW;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AACJ;","names":["hasOverflow","hasWarnings"]}
@@ -67,25 +67,25 @@ function registerPluginCommands(program, manager) {
67
67
  import { Command } from "commander";
68
68
  async function createProgram(pluginManager) {
69
69
  const program = new Command();
70
- program.name("gpc").description("GPC \u2014 Google Play Console CLI").version("0.9.64", "-V, --version").option("-o, --output <format>", "Output format: table, json, yaml, markdown, junit").option("-v, --verbose", "Enable debug logging").option("-q, --quiet", "Suppress non-essential output").option("-a, --app <package>", "App package name").option("-p, --profile <name>", "Auth profile name").option("--no-color", "Disable colored output").option("--no-interactive", "Disable interactive prompts").option("-y, --yes", "Skip confirmation prompts").option("--dry-run", "Preview changes without executing").option("--notify [target]", "Send webhook notification on completion (slack, discord, custom)").option("--ci", "Force CI mode (JSON output, no prompts, strict exit codes)").option("-j, --json", "Shorthand for --output json").option("--apps <csv>", "Comma-separated package names for multi-app operations").showSuggestionAfterError(false);
70
+ program.name("gpc").description("GPC \u2014 Google Play Console CLI").version("0.9.66", "-V, --version").option("-o, --output <format>", "Output format: table, json, yaml, markdown, junit").option("-v, --verbose", "Enable debug logging").option("-q, --quiet", "Suppress non-essential output").option("-a, --app <package>", "App package name").option("-p, --profile <name>", "Auth profile name").option("--no-color", "Disable colored output").option("--no-interactive", "Disable interactive prompts").option("-y, --yes", "Skip confirmation prompts").option("--dry-run", "Preview changes without executing").option("--notify [target]", "Send webhook notification on completion (slack, discord, custom)").option("--ci", "Force CI mode (JSON output, no prompts, strict exit codes)").option("-j, --json", "Shorthand for --output json").option("--apps <csv>", "Comma-separated package names for multi-app operations").showSuggestionAfterError(false);
71
71
  const commandLoaders = {
72
72
  auth: async () => {
73
73
  (await import("./auth-4DRT7ZH2.js")).registerAuthCommands(program);
74
74
  },
75
75
  config: async () => {
76
- (await import("./config-SK7BOURM.js")).registerConfigCommands(program);
76
+ (await import("./config-DDZMNYOB.js")).registerConfigCommands(program);
77
77
  },
78
78
  doctor: async () => {
79
- (await import("./doctor-FSUI44DD.js")).registerDoctorCommand(program);
79
+ (await import("./doctor-QRHXY3FC.js")).registerDoctorCommand(program);
80
80
  },
81
81
  update: async () => {
82
- (await import("./update-E4VGHQUR.js")).registerUpdateCommand(program);
82
+ (await import("./update-GEH352BE.js")).registerUpdateCommand(program);
83
83
  },
84
84
  docs: async () => {
85
- (await import("./docs-WVJCDX5X.js")).registerDocsCommand(program);
85
+ (await import("./docs-OU6LSSJD.js")).registerDocsCommand(program);
86
86
  },
87
87
  changelog: async () => {
88
- (await import("./changelog-EHQYZP22.js")).registerChangelogCommand(program);
88
+ (await import("./changelog-STYBBYDC.js")).registerChangelogCommand(program);
89
89
  },
90
90
  completion: async () => {
91
91
  (await import("./completion-ZK7RPPFD.js")).registerCompletionCommand(program, async () => {
@@ -190,16 +190,16 @@ async function createProgram(pluginManager) {
190
190
  (await import("./install-skills-S342NJ7T.js")).registerInstallSkillsCommand(program);
191
191
  },
192
192
  verify: async () => {
193
- (await import("./verify-H4ZUVHMZ.js")).registerVerifyCommand(program);
193
+ (await import("./verify-O2PSBTIC.js")).registerVerifyCommand(program);
194
194
  },
195
195
  version: async () => {
196
- (await import("./version-HXUIOHCL.js")).registerVersionCommand(program);
196
+ (await import("./version-2RUEWMPK.js")).registerVersionCommand(program);
197
197
  },
198
198
  cache: async () => {
199
199
  (await import("./cache-FGNP7Y37.js")).registerCacheCommand(program);
200
200
  },
201
201
  feedback: async () => {
202
- (await import("./feedback-PDQU5E6S.js")).registerFeedbackCommand(program);
202
+ (await import("./feedback-C2BA7CK6.js")).registerFeedbackCommand(program);
203
203
  },
204
204
  quickstart: async () => {
205
205
  (await import("./quickstart-FOWM3OKT.js")).registerQuickstartCommand(program);
@@ -226,7 +226,7 @@ async function createProgram(pluginManager) {
226
226
  (await import("./init-OCBFI4VH.js")).registerInitCommand(program);
227
227
  },
228
228
  preflight: async () => {
229
- (await import("./preflight-KIWZPFTX.js")).registerPreflightCommand(program);
229
+ (await import("./preflight-BL67VGUX.js")).registerPreflightCommand(program);
230
230
  },
231
231
  plugins: async () => {
232
232
  registerPluginsCommand(program, pluginManager);
@@ -467,4 +467,4 @@ export {
467
467
  createProgram,
468
468
  handleCliError
469
469
  };
470
- //# sourceMappingURL=chunk-I3SFXLIY.js.map
470
+ //# sourceMappingURL=chunk-IUG4225Q.js.map
@@ -78,7 +78,7 @@ Configuration file created: ${path}`);
78
78
  });
79
79
  console.log("\nVerifying setup...");
80
80
  try {
81
- const { registerDoctorCommand } = await import("./doctor-FSUI44DD.js");
81
+ const { registerDoctorCommand } = await import("./doctor-QRHXY3FC.js");
82
82
  const { Command } = await import("commander");
83
83
  const doctorProgram = new Command();
84
84
  doctorProgram.option("-o, --output <format>", "Output format").option("-j, --json", "JSON mode");
@@ -107,4 +107,4 @@ Configuration file created: ${path}`);
107
107
  export {
108
108
  registerConfigCommands
109
109
  };
110
- //# sourceMappingURL=config-SK7BOURM.js.map
110
+ //# sourceMappingURL=config-DDZMNYOB.js.map
@@ -87,7 +87,10 @@ function renderMarkdown(content) {
87
87
  function renderInline(text) {
88
88
  let result = text.replace(/\*\*(.+?)\*\*/g, (_, t) => bold(t));
89
89
  result = result.replace(/`([^`]+)`/g, (_, t) => dim(t));
90
- result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, url) => `${label} ${dim(`(${url})`)}`);
90
+ result = result.replace(
91
+ /\[([^\]]+)\]\(([^)]+)\)/g,
92
+ (_, label, url) => `${label} ${dim(`(${url})`)}`
93
+ );
91
94
  return result;
92
95
  }
93
96
  function formatSearchResult(slug, title, snippet, score) {
@@ -281,12 +284,14 @@ Run: gpc docs list` : "Run: gpc docs list"
281
284
  Search results for "${query}"
282
285
  `));
283
286
  for (const r of results) {
284
- console.log(
285
- " " + formatSearchResult(r.page.slug, r.page.title, r.snippet, r.score)
286
- );
287
+ console.log(" " + formatSearchResult(r.page.slug, r.page.title, r.snippet, r.score));
287
288
  console.log("");
288
289
  }
289
- console.log(dim(` ${results.length} result${results.length === 1 ? "" : "s"}. Use: gpc docs show <topic>`));
290
+ console.log(
291
+ dim(
292
+ ` ${results.length} result${results.length === 1 ? "" : "s"}. Use: gpc docs show <topic>`
293
+ )
294
+ );
290
295
  });
291
296
  docs.command("init").description("Create GPC.md quick-reference for AI agents in this directory").option("--force", "Overwrite existing GPC.md").option("--path <dir>", "Output directory", ".").action(async (opts) => {
292
297
  const outDir = opts.path;
@@ -309,7 +314,11 @@ Run: gpc docs list` : "Run: gpc docs list"
309
314
  const existing = await readFile(agentPath, "utf-8");
310
315
  if (!existing.includes("GPC.md")) {
311
316
  const separator = existing.endsWith("\n") ? "\n" : "\n\n";
312
- await writeFile(agentPath, existing + separator + "See also: @GPC.md for GPC CLI reference.\n", "utf-8");
317
+ await writeFile(
318
+ agentPath,
319
+ existing + separator + "See also: @GPC.md for GPC CLI reference.\n",
320
+ "utf-8"
321
+ );
313
322
  console.log(`Updated ${agentPath} (added @GPC.md reference)`);
314
323
  }
315
324
  }
@@ -375,4 +384,4 @@ function generateQuickReference(bundle) {
375
384
  export {
376
385
  registerDocsCommand
377
386
  };
378
- //# sourceMappingURL=docs-WVJCDX5X.js.map
387
+ //# sourceMappingURL=docs-OU6LSSJD.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/docs.ts","../src/docs-renderer.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport * as cp from \"node:child_process\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { renderMarkdown, formatSearchResult } from \"../docs-renderer.js\";\nimport { bold, dim } from \"../colors.js\";\nimport { getOutputFormat } from \"../format.js\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { formatOutput, GpcError } from \"@gpc-cli/core\";\nimport type { DocPage, DocsBundle } from \"../generated/docs-types.js\";\n\nlet _bundle: DocsBundle | undefined;\nlet _pageMap: Map<string, DocPage> | undefined;\n\nfunction getBundle(): DocsBundle {\n if (!_bundle) {\n const moduleDir = dirname(fileURLToPath(import.meta.url));\n // Works from src/commands/ (dev/test) and dist/ (built output)\n const candidates = [\n join(moduleDir, \"..\", \"generated\", \"docs-bundle.json\"),\n join(moduleDir, \"generated\", \"docs-bundle.json\"),\n ];\n const bundlePath = candidates.find((p) => existsSync(p));\n if (!bundlePath) {\n throw new GpcError(\n \"Embedded docs bundle not found. Run the build first.\",\n \"DOCS_BUNDLE_MISSING\",\n 1,\n \"Run: pnpm build --filter @gpc-cli/cli\",\n );\n }\n _bundle = JSON.parse(readFileSync(bundlePath, \"utf-8\")) as DocsBundle;\n }\n return _bundle;\n}\n\nfunction getPageMap(): Map<string, DocPage> {\n if (!_pageMap) {\n const bundle = getBundle();\n _pageMap = new Map<string, DocPage>();\n for (const page of bundle.pages) {\n _pageMap.set(page.slug, page);\n }\n }\n return _pageMap;\n}\n\nfunction fuzzyMatch(query: string, pages: DocPage[]): DocPage | undefined {\n const q = query.toLowerCase();\n // Exact full slug match (e.g., \"guide/authentication\")\n const exact = pages.find((p) => p.slug === q);\n if (exact) return exact;\n // Match on the filename part (e.g., \"authentication\" matches \"guide/authentication\")\n const byName = pages.find((p) => p.slug.endsWith(`/${q}`));\n if (byName) return byName;\n // Prefix match on filename part\n const prefix = pages.find((p) => {\n const name = p.slug.split(\"/\").pop() || \"\";\n return name.startsWith(q);\n });\n if (prefix) return prefix;\n // Contains match anywhere in slug\n const contains = pages.find((p) => p.slug.includes(q));\n if (contains) return contains;\n // Title match\n const titleMatch = pages.find((p) => p.title.toLowerCase().includes(q));\n if (titleMatch) return titleMatch;\n return undefined;\n}\n\nfunction searchPages(\n query: string,\n bundle: DocsBundle,\n): { page: DocPage; score: number; snippet: string }[] {\n const words = query\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length > 2);\n\n if (words.length === 0) return [];\n\n const pageMap = getPageMap();\n const scores = new Map<string, number>();\n for (const word of words) {\n const entries = bundle.searchIndex[word];\n if (!entries) continue;\n for (const entry of entries) {\n scores.set(entry.slug, (scores.get(entry.slug) || 0) + entry.score);\n }\n }\n\n const results: { page: DocPage; score: number; snippet: string }[] = [];\n for (const [slug, score] of scores) {\n const page = pageMap.get(slug);\n if (!page) continue;\n const snippet = extractSnippet(page.content, words);\n results.push({ page, score, snippet });\n }\n\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, 15);\n}\n\nfunction extractSnippet(content: string, words: string[]): string {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const lower = lines[i]!.toLowerCase();\n if (words.some((w) => lower.includes(w))) {\n const start = Math.max(0, i - 1);\n const end = Math.min(lines.length, i + 2);\n return lines.slice(start, end).join(\"\\n\");\n }\n }\n return lines.slice(0, 3).join(\"\\n\");\n}\n\nconst DOCS_BASE = \"https://yasserstudio.github.io/gpc/\";\n\nfunction openInBrowser(url: string): void {\n const platform = process.platform;\n if (platform === \"win32\") {\n cp.exec(`start \"\" \"${url}\"`, (error) => {\n if (error) console.log(`Open in your browser: ${url}`);\n });\n } else {\n const cmd = platform === \"darwin\" ? \"open\" : \"xdg-open\";\n cp.execFile(cmd, [url], (error) => {\n if (error) console.log(`Open in your browser: ${url}`);\n });\n }\n}\n\nexport function registerDocsCommand(program: Command): void {\n const docs = program\n .command(\"docs\")\n .description(\"Access embedded documentation (list, show, search, init, web)\");\n\n docs\n .command(\"list\")\n .description(\"List all available documentation topics\")\n .action(async () => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n const bundle = getBundle();\n\n if (format === \"json\") {\n const data = bundle.pages.map((p) => ({\n slug: p.slug,\n section: p.section,\n title: p.title,\n description: p.description,\n }));\n console.log(formatOutput(data, \"json\"));\n return;\n }\n\n const bySection = new Map<string, DocPage[]>();\n for (const page of bundle.pages) {\n if (!bySection.has(page.section)) bySection.set(page.section, []);\n bySection.get(page.section)!.push(page);\n }\n\n for (const [section, pages] of bySection) {\n console.log(bold(`\\n ${section.toUpperCase()}`));\n for (const page of pages) {\n const label = page.slug.padEnd(36);\n console.log(` ${label} ${dim(page.title || page.slug)}`);\n }\n }\n console.log(\"\");\n console.log(dim(` ${bundle.pageCount} topics. Use: gpc docs show <topic>`));\n });\n\n docs\n .command(\"show <topic>\")\n .description(\"Show a documentation page in the terminal\")\n .action(async (topic: string) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n const bundle = getBundle();\n\n const page = fuzzyMatch(topic, bundle.pages);\n if (!page) {\n const suggestions = bundle.pages\n .filter((p) => p.slug.includes(topic.toLowerCase().slice(0, 3)))\n .slice(0, 5)\n .map((p) => p.slug);\n\n throw new GpcError(\n `No documentation found for \"${topic}\"`,\n \"DOCS_NOT_FOUND\",\n 2,\n suggestions.length > 0\n ? `Did you mean: ${suggestions.join(\", \")}?\\nRun: gpc docs list`\n : \"Run: gpc docs list\",\n );\n }\n\n if (format === \"json\") {\n console.log(\n formatOutput(\n { slug: page.slug, section: page.section, title: page.title, content: page.content },\n \"json\",\n ),\n );\n return;\n }\n\n console.log(renderMarkdown(page.content));\n });\n\n docs\n .command(\"search <query>\")\n .description(\"Search documentation\")\n .action(async (query: string) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n const bundle = getBundle();\n\n const results = searchPages(query, bundle);\n\n if (results.length === 0) {\n console.log(dim(` No results for \"${query}\".`));\n console.log(dim(\" Try a different search term, or: gpc docs list\"));\n return;\n }\n\n if (format === \"json\") {\n const data = results.map((r) => ({\n slug: r.page.slug,\n section: r.page.section,\n title: r.page.title,\n score: r.score,\n }));\n console.log(formatOutput(data, \"json\"));\n return;\n }\n\n console.log(bold(`\\n Search results for \"${query}\"\\n`));\n for (const r of results) {\n console.log(\n \" \" +\n formatSearchResult(r.page.slug, r.page.title, r.snippet, r.score),\n );\n console.log(\"\");\n }\n console.log(dim(` ${results.length} result${results.length === 1 ? \"\" : \"s\"}. Use: gpc docs show <topic>`));\n });\n\n docs\n .command(\"init\")\n .description(\"Create GPC.md quick-reference for AI agents in this directory\")\n .option(\"--force\", \"Overwrite existing GPC.md\")\n .option(\"--path <dir>\", \"Output directory\", \".\")\n .action(async (opts: { force?: boolean; path: string }) => {\n const outDir = opts.path;\n const outFile = join(outDir, \"GPC.md\");\n\n if (existsSync(outFile) && !opts.force) {\n throw new GpcError(\n `GPC.md already exists at ${outFile}`,\n \"DOCS_INIT_EXISTS\",\n 1,\n \"Use --force to overwrite.\",\n );\n }\n\n const bundle = getBundle();\n const content = generateQuickReference(bundle);\n await writeFile(outFile, content, \"utf-8\");\n console.log(`Created ${outFile} (${bundle.pageCount} topics indexed)`);\n\n for (const agentFile of [\"CLAUDE.md\", \"AGENTS.md\"]) {\n const agentPath = join(outDir, agentFile);\n if (existsSync(agentPath)) {\n const existing = await readFile(agentPath, \"utf-8\");\n if (!existing.includes(\"GPC.md\")) {\n const separator = existing.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n await writeFile(agentPath, existing + separator + \"See also: @GPC.md for GPC CLI reference.\\n\", \"utf-8\");\n console.log(`Updated ${agentPath} (added @GPC.md reference)`);\n }\n }\n }\n });\n\n docs\n .command(\"web [topic]\")\n .description(\"Open documentation in browser\")\n .action((topic?: string) => {\n const bundle = getBundle();\n if (!topic) {\n openInBrowser(DOCS_BASE);\n return;\n }\n const page = fuzzyMatch(topic, bundle.pages);\n if (page) {\n openInBrowser(`${DOCS_BASE}${page.slug}`);\n } else {\n openInBrowser(DOCS_BASE);\n console.log(dim(`Topic \"${topic}\" not found. Opened docs home page.`));\n }\n });\n}\n\nfunction generateQuickReference(bundle: DocsBundle): string {\n const lines: string[] = [\n \"# GPC Quick Reference\",\n \"\",\n \"> Auto-generated by `gpc docs init`. See full docs: https://yasserstudio.github.io/gpc/\",\n \"\",\n \"## Commands\",\n \"\",\n ];\n\n const commandPages = bundle.pages\n .filter((p) => p.section === \"commands\")\n .sort((a, b) => a.slug.localeCompare(b.slug));\n\n for (const page of commandPages) {\n const desc = page.description || page.title;\n lines.push(`- **gpc ${page.slug}** -- ${desc}`);\n }\n\n lines.push(\"\", \"## Guides\", \"\");\n\n const guidePages = bundle.pages\n .filter((p) => p.section === \"guide\")\n .sort((a, b) => a.slug.localeCompare(b.slug));\n\n for (const page of guidePages) {\n lines.push(`- **${page.title || page.slug}** -- \\`gpc docs show ${page.slug}\\``);\n }\n\n lines.push(\n \"\",\n \"## Quick Workflows\",\n \"\",\n \"```bash\",\n \"# Upload and publish\",\n \"gpc publish app.aab\",\n \"\",\n \"# Check vitals before release\",\n \"gpc preflight app.aab\",\n \"\",\n \"# Generate changelog with AI translation\",\n \"gpc changelog generate --target play-store --locales auto --ai\",\n \"\",\n \"# Staged rollout\",\n \"gpc releases rollout --fraction 0.1 --app com.example.app\",\n \"```\",\n \"\",\n `*${bundle.pageCount} docs pages available offline via \\`gpc docs show <topic>\\`*`,\n \"\",\n );\n\n return lines.join(\"\\n\");\n}\n","import { bold, dim, yellow, green, gray } from \"./colors.js\";\n\nexport function renderMarkdown(content: string): string {\n const lines = content.split(\"\\n\");\n const out: string[] = [];\n\n let inCodeBlock = false;\n\n for (const line of lines) {\n if (line.startsWith(\"```\")) {\n inCodeBlock = !inCodeBlock;\n if (inCodeBlock) {\n out.push(dim(\" ┌─────────────────────────────────────\"));\n } else {\n out.push(dim(\" └─────────────────────────────────────\"));\n }\n continue;\n }\n\n if (inCodeBlock) {\n out.push(dim(` │ ${line}`));\n continue;\n }\n\n // Headers\n const h1 = line.match(/^# (.+)$/);\n if (h1) {\n out.push(\"\");\n out.push(bold(green(` ${h1[1]}`)));\n out.push(green(\" \" + \"─\".repeat(h1[1].length)));\n out.push(\"\");\n continue;\n }\n const h2 = line.match(/^## (.+)$/);\n if (h2) {\n out.push(\"\");\n out.push(bold(yellow(` ${h2[1]}`)));\n out.push(\"\");\n continue;\n }\n const h3 = line.match(/^### (.+)$/);\n if (h3) {\n out.push(bold(` ${h3[1]}`));\n continue;\n }\n\n // Blockquotes (converted from ::: containers)\n if (line.startsWith(\"> \")) {\n out.push(dim(` │ ${renderInline(line.slice(2))}`));\n continue;\n }\n\n // Table rows\n if (line.startsWith(\"|\")) {\n if (line.match(/^\\|[\\s-|]+\\|$/)) {\n out.push(gray(\" \" + \"─\".repeat(Math.min(line.length, 60))));\n continue;\n }\n const cells = line.split(\"|\").filter(Boolean).map((c) => c.trim());\n out.push(\" \" + cells.join(\" \"));\n continue;\n }\n\n // List items\n if (line.match(/^\\s*[-*]\\s/)) {\n out.push(` ${renderInline(line)}`);\n continue;\n }\n\n // Numbered list items\n if (line.match(/^\\s*\\d+\\.\\s/)) {\n out.push(` ${renderInline(line)}`);\n continue;\n }\n\n // Regular text\n out.push(` ${renderInline(line)}`);\n }\n\n // Close unclosed code block gracefully\n if (inCodeBlock) {\n out.push(dim(\" └─────────────────────────────────────\"));\n }\n\n return out.join(\"\\n\");\n}\n\nfunction renderInline(text: string): string {\n let result = text.replace(/\\*\\*(.+?)\\*\\*/g, (_, t) => bold(t));\n result = result.replace(/`([^`]+)`/g, (_, t) => dim(t));\n result = result.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_, label, url) => `${label} ${dim(`(${url})`)}`);\n return result;\n}\n\nexport function formatSearchResult(\n slug: string,\n title: string,\n snippet: string,\n score: number,\n): string {\n const header = bold(slug) + dim(` (score: ${score})`);\n const titleLine = ` ${title}`;\n const snippetLines = snippet\n .split(\"\\n\")\n .slice(0, 3)\n .map((l) => gray(` ${l.trim()}`))\n .join(\"\\n\");\n return `${header}\\n${titleLine}\\n${snippetLines}`;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/docs.ts","../src/docs-renderer.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport * as cp from \"node:child_process\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { renderMarkdown, formatSearchResult } from \"../docs-renderer.js\";\nimport { bold, dim } from \"../colors.js\";\nimport { getOutputFormat } from \"../format.js\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { formatOutput, GpcError } from \"@gpc-cli/core\";\nimport type { DocPage, DocsBundle } from \"../generated/docs-types.js\";\n\nlet _bundle: DocsBundle | undefined;\nlet _pageMap: Map<string, DocPage> | undefined;\n\nfunction getBundle(): DocsBundle {\n if (!_bundle) {\n const moduleDir = dirname(fileURLToPath(import.meta.url));\n // Works from src/commands/ (dev/test) and dist/ (built output)\n const candidates = [\n join(moduleDir, \"..\", \"generated\", \"docs-bundle.json\"),\n join(moduleDir, \"generated\", \"docs-bundle.json\"),\n ];\n const bundlePath = candidates.find((p) => existsSync(p));\n if (!bundlePath) {\n throw new GpcError(\n \"Embedded docs bundle not found. Run the build first.\",\n \"DOCS_BUNDLE_MISSING\",\n 1,\n \"Run: pnpm build --filter @gpc-cli/cli\",\n );\n }\n _bundle = JSON.parse(readFileSync(bundlePath, \"utf-8\")) as DocsBundle;\n }\n return _bundle;\n}\n\nfunction getPageMap(): Map<string, DocPage> {\n if (!_pageMap) {\n const bundle = getBundle();\n _pageMap = new Map<string, DocPage>();\n for (const page of bundle.pages) {\n _pageMap.set(page.slug, page);\n }\n }\n return _pageMap;\n}\n\nfunction fuzzyMatch(query: string, pages: DocPage[]): DocPage | undefined {\n const q = query.toLowerCase();\n // Exact full slug match (e.g., \"guide/authentication\")\n const exact = pages.find((p) => p.slug === q);\n if (exact) return exact;\n // Match on the filename part (e.g., \"authentication\" matches \"guide/authentication\")\n const byName = pages.find((p) => p.slug.endsWith(`/${q}`));\n if (byName) return byName;\n // Prefix match on filename part\n const prefix = pages.find((p) => {\n const name = p.slug.split(\"/\").pop() || \"\";\n return name.startsWith(q);\n });\n if (prefix) return prefix;\n // Contains match anywhere in slug\n const contains = pages.find((p) => p.slug.includes(q));\n if (contains) return contains;\n // Title match\n const titleMatch = pages.find((p) => p.title.toLowerCase().includes(q));\n if (titleMatch) return titleMatch;\n return undefined;\n}\n\nfunction searchPages(\n query: string,\n bundle: DocsBundle,\n): { page: DocPage; score: number; snippet: string }[] {\n const words = query\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length > 2);\n\n if (words.length === 0) return [];\n\n const pageMap = getPageMap();\n const scores = new Map<string, number>();\n for (const word of words) {\n const entries = bundle.searchIndex[word];\n if (!entries) continue;\n for (const entry of entries) {\n scores.set(entry.slug, (scores.get(entry.slug) || 0) + entry.score);\n }\n }\n\n const results: { page: DocPage; score: number; snippet: string }[] = [];\n for (const [slug, score] of scores) {\n const page = pageMap.get(slug);\n if (!page) continue;\n const snippet = extractSnippet(page.content, words);\n results.push({ page, score, snippet });\n }\n\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, 15);\n}\n\nfunction extractSnippet(content: string, words: string[]): string {\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const lower = lines[i]!.toLowerCase();\n if (words.some((w) => lower.includes(w))) {\n const start = Math.max(0, i - 1);\n const end = Math.min(lines.length, i + 2);\n return lines.slice(start, end).join(\"\\n\");\n }\n }\n return lines.slice(0, 3).join(\"\\n\");\n}\n\nconst DOCS_BASE = \"https://yasserstudio.github.io/gpc/\";\n\nfunction openInBrowser(url: string): void {\n const platform = process.platform;\n if (platform === \"win32\") {\n cp.exec(`start \"\" \"${url}\"`, (error) => {\n if (error) console.log(`Open in your browser: ${url}`);\n });\n } else {\n const cmd = platform === \"darwin\" ? \"open\" : \"xdg-open\";\n cp.execFile(cmd, [url], (error) => {\n if (error) console.log(`Open in your browser: ${url}`);\n });\n }\n}\n\nexport function registerDocsCommand(program: Command): void {\n const docs = program\n .command(\"docs\")\n .description(\"Access embedded documentation (list, show, search, init, web)\");\n\n docs\n .command(\"list\")\n .description(\"List all available documentation topics\")\n .action(async () => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n const bundle = getBundle();\n\n if (format === \"json\") {\n const data = bundle.pages.map((p) => ({\n slug: p.slug,\n section: p.section,\n title: p.title,\n description: p.description,\n }));\n console.log(formatOutput(data, \"json\"));\n return;\n }\n\n const bySection = new Map<string, DocPage[]>();\n for (const page of bundle.pages) {\n if (!bySection.has(page.section)) bySection.set(page.section, []);\n bySection.get(page.section)!.push(page);\n }\n\n for (const [section, pages] of bySection) {\n console.log(bold(`\\n ${section.toUpperCase()}`));\n for (const page of pages) {\n const label = page.slug.padEnd(36);\n console.log(` ${label} ${dim(page.title || page.slug)}`);\n }\n }\n console.log(\"\");\n console.log(dim(` ${bundle.pageCount} topics. Use: gpc docs show <topic>`));\n });\n\n docs\n .command(\"show <topic>\")\n .description(\"Show a documentation page in the terminal\")\n .action(async (topic: string) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n const bundle = getBundle();\n\n const page = fuzzyMatch(topic, bundle.pages);\n if (!page) {\n const suggestions = bundle.pages\n .filter((p) => p.slug.includes(topic.toLowerCase().slice(0, 3)))\n .slice(0, 5)\n .map((p) => p.slug);\n\n throw new GpcError(\n `No documentation found for \"${topic}\"`,\n \"DOCS_NOT_FOUND\",\n 2,\n suggestions.length > 0\n ? `Did you mean: ${suggestions.join(\", \")}?\\nRun: gpc docs list`\n : \"Run: gpc docs list\",\n );\n }\n\n if (format === \"json\") {\n console.log(\n formatOutput(\n { slug: page.slug, section: page.section, title: page.title, content: page.content },\n \"json\",\n ),\n );\n return;\n }\n\n console.log(renderMarkdown(page.content));\n });\n\n docs\n .command(\"search <query>\")\n .description(\"Search documentation\")\n .action(async (query: string) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n const bundle = getBundle();\n\n const results = searchPages(query, bundle);\n\n if (results.length === 0) {\n console.log(dim(` No results for \"${query}\".`));\n console.log(dim(\" Try a different search term, or: gpc docs list\"));\n return;\n }\n\n if (format === \"json\") {\n const data = results.map((r) => ({\n slug: r.page.slug,\n section: r.page.section,\n title: r.page.title,\n score: r.score,\n }));\n console.log(formatOutput(data, \"json\"));\n return;\n }\n\n console.log(bold(`\\n Search results for \"${query}\"\\n`));\n for (const r of results) {\n console.log(\" \" + formatSearchResult(r.page.slug, r.page.title, r.snippet, r.score));\n console.log(\"\");\n }\n console.log(\n dim(\n ` ${results.length} result${results.length === 1 ? \"\" : \"s\"}. Use: gpc docs show <topic>`,\n ),\n );\n });\n\n docs\n .command(\"init\")\n .description(\"Create GPC.md quick-reference for AI agents in this directory\")\n .option(\"--force\", \"Overwrite existing GPC.md\")\n .option(\"--path <dir>\", \"Output directory\", \".\")\n .action(async (opts: { force?: boolean; path: string }) => {\n const outDir = opts.path;\n const outFile = join(outDir, \"GPC.md\");\n\n if (existsSync(outFile) && !opts.force) {\n throw new GpcError(\n `GPC.md already exists at ${outFile}`,\n \"DOCS_INIT_EXISTS\",\n 1,\n \"Use --force to overwrite.\",\n );\n }\n\n const bundle = getBundle();\n const content = generateQuickReference(bundle);\n await writeFile(outFile, content, \"utf-8\");\n console.log(`Created ${outFile} (${bundle.pageCount} topics indexed)`);\n\n for (const agentFile of [\"CLAUDE.md\", \"AGENTS.md\"]) {\n const agentPath = join(outDir, agentFile);\n if (existsSync(agentPath)) {\n const existing = await readFile(agentPath, \"utf-8\");\n if (!existing.includes(\"GPC.md\")) {\n const separator = existing.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n await writeFile(\n agentPath,\n existing + separator + \"See also: @GPC.md for GPC CLI reference.\\n\",\n \"utf-8\",\n );\n console.log(`Updated ${agentPath} (added @GPC.md reference)`);\n }\n }\n }\n });\n\n docs\n .command(\"web [topic]\")\n .description(\"Open documentation in browser\")\n .action((topic?: string) => {\n const bundle = getBundle();\n if (!topic) {\n openInBrowser(DOCS_BASE);\n return;\n }\n const page = fuzzyMatch(topic, bundle.pages);\n if (page) {\n openInBrowser(`${DOCS_BASE}${page.slug}`);\n } else {\n openInBrowser(DOCS_BASE);\n console.log(dim(`Topic \"${topic}\" not found. Opened docs home page.`));\n }\n });\n}\n\nfunction generateQuickReference(bundle: DocsBundle): string {\n const lines: string[] = [\n \"# GPC Quick Reference\",\n \"\",\n \"> Auto-generated by `gpc docs init`. See full docs: https://yasserstudio.github.io/gpc/\",\n \"\",\n \"## Commands\",\n \"\",\n ];\n\n const commandPages = bundle.pages\n .filter((p) => p.section === \"commands\")\n .sort((a, b) => a.slug.localeCompare(b.slug));\n\n for (const page of commandPages) {\n const desc = page.description || page.title;\n lines.push(`- **gpc ${page.slug}** -- ${desc}`);\n }\n\n lines.push(\"\", \"## Guides\", \"\");\n\n const guidePages = bundle.pages\n .filter((p) => p.section === \"guide\")\n .sort((a, b) => a.slug.localeCompare(b.slug));\n\n for (const page of guidePages) {\n lines.push(`- **${page.title || page.slug}** -- \\`gpc docs show ${page.slug}\\``);\n }\n\n lines.push(\n \"\",\n \"## Quick Workflows\",\n \"\",\n \"```bash\",\n \"# Upload and publish\",\n \"gpc publish app.aab\",\n \"\",\n \"# Check vitals before release\",\n \"gpc preflight app.aab\",\n \"\",\n \"# Generate changelog with AI translation\",\n \"gpc changelog generate --target play-store --locales auto --ai\",\n \"\",\n \"# Staged rollout\",\n \"gpc releases rollout --fraction 0.1 --app com.example.app\",\n \"```\",\n \"\",\n `*${bundle.pageCount} docs pages available offline via \\`gpc docs show <topic>\\`*`,\n \"\",\n );\n\n return lines.join(\"\\n\");\n}\n","import { bold, dim, yellow, green, gray } from \"./colors.js\";\n\nexport function renderMarkdown(content: string): string {\n const lines = content.split(\"\\n\");\n const out: string[] = [];\n\n let inCodeBlock = false;\n\n for (const line of lines) {\n if (line.startsWith(\"```\")) {\n inCodeBlock = !inCodeBlock;\n if (inCodeBlock) {\n out.push(dim(\" ┌─────────────────────────────────────\"));\n } else {\n out.push(dim(\" └─────────────────────────────────────\"));\n }\n continue;\n }\n\n if (inCodeBlock) {\n out.push(dim(` │ ${line}`));\n continue;\n }\n\n // Headers\n const h1 = line.match(/^# (.+)$/);\n if (h1) {\n out.push(\"\");\n out.push(bold(green(` ${h1[1]!}`)));\n out.push(green(\" \" + \"─\".repeat(h1[1]!.length)));\n out.push(\"\");\n continue;\n }\n const h2 = line.match(/^## (.+)$/);\n if (h2) {\n out.push(\"\");\n out.push(bold(yellow(` ${h2[1]}`)));\n out.push(\"\");\n continue;\n }\n const h3 = line.match(/^### (.+)$/);\n if (h3) {\n out.push(bold(` ${h3[1]}`));\n continue;\n }\n\n // Blockquotes (converted from ::: containers)\n if (line.startsWith(\"> \")) {\n out.push(dim(` │ ${renderInline(line.slice(2))}`));\n continue;\n }\n\n // Table rows\n if (line.startsWith(\"|\")) {\n if (line.match(/^\\|[\\s-|]+\\|$/)) {\n out.push(gray(\" \" + \"─\".repeat(Math.min(line.length, 60))));\n continue;\n }\n const cells = line\n .split(\"|\")\n .filter(Boolean)\n .map((c) => c.trim());\n out.push(\" \" + cells.join(\" \"));\n continue;\n }\n\n // List items\n if (line.match(/^\\s*[-*]\\s/)) {\n out.push(` ${renderInline(line)}`);\n continue;\n }\n\n // Numbered list items\n if (line.match(/^\\s*\\d+\\.\\s/)) {\n out.push(` ${renderInline(line)}`);\n continue;\n }\n\n // Regular text\n out.push(` ${renderInline(line)}`);\n }\n\n // Close unclosed code block gracefully\n if (inCodeBlock) {\n out.push(dim(\" └─────────────────────────────────────\"));\n }\n\n return out.join(\"\\n\");\n}\n\nfunction renderInline(text: string): string {\n let result = text.replace(/\\*\\*(.+?)\\*\\*/g, (_, t) => bold(t));\n result = result.replace(/`([^`]+)`/g, (_, t) => dim(t));\n result = result.replace(\n /\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n (_, label, url) => `${label} ${dim(`(${url})`)}`,\n );\n return result;\n}\n\nexport function formatSearchResult(\n slug: string,\n title: string,\n snippet: string,\n score: number,\n): string {\n const header = bold(slug) + dim(` (score: ${score})`);\n const titleLine = ` ${title}`;\n const snippetLines = snippet\n .split(\"\\n\")\n .slice(0, 3)\n .map((l) => gray(` ${l.trim()}`))\n .join(\"\\n\");\n return `${header}\\n${titleLine}\\n${snippetLines}`;\n}\n"],"mappings":"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","names":[]}
@@ -141,7 +141,7 @@ function checkCiEnvironment() {
141
141
  };
142
142
  }
143
143
  async function checkGpcVersion() {
144
- const currentVersion = "0.9.64";
144
+ const currentVersion = "0.9.66";
145
145
  if (currentVersion === "0.0.0") {
146
146
  return { name: "version", status: "info", message: "GPC development build" };
147
147
  }
@@ -374,23 +374,167 @@ async function checkEnterpriseAccess(accessToken) {
374
374
  };
375
375
  }
376
376
  }
377
- var VERIFICATION_ENFORCEMENT = /* @__PURE__ */ new Date("2026-09-01");
377
+ var VERIFICATION_ENFORCEMENT = /* @__PURE__ */ new Date("2026-09-30");
378
378
  function checkVerificationDeadline() {
379
- if (Date.now() < VERIFICATION_ENFORCEMENT.getTime()) {
379
+ const daysLeft = Math.ceil(
380
+ (VERIFICATION_ENFORCEMENT.getTime() - Date.now()) / (1e3 * 60 * 60 * 24)
381
+ );
382
+ if (daysLeft > 0) {
380
383
  return {
381
384
  name: "verification",
382
- status: "warn",
383
- message: "Android developer verification enforcement begins September 2026 (BR, ID, SG, TH)",
384
- suggestion: "Run 'gpc verify' for details and resources"
385
+ status: daysLeft <= 90 ? "warn" : "info",
386
+ message: `Android developer verification enforcement begins September 30, 2026 (${daysLeft} days, BR/ID/SG/TH)`,
387
+ suggestion: "Run 'gpc verify' for details or 'gpc verify checklist' for a readiness walkthrough"
385
388
  };
386
389
  }
387
390
  return {
388
391
  name: "verification",
389
- status: "info",
392
+ status: "warn",
390
393
  message: "Android developer verification is being enforced. Ensure your account is verified.",
391
- suggestion: "Run 'gpc verify' to check your status"
394
+ suggestion: "Run 'gpc verify checklist' to check your readiness"
392
395
  };
393
396
  }
397
+ async function checkSigningKey(packageName, accessToken, keystorePath, storePassword, keyAlias) {
398
+ const results = [];
399
+ const baseUrl = `https://${API_HOST}/androidpublisher/v3/applications/${encodeURIComponent(packageName)}`;
400
+ let apiFingerprint;
401
+ let latestVersionCode;
402
+ try {
403
+ const editResp = await fetch(`${baseUrl}/edits`, {
404
+ method: "POST",
405
+ headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" },
406
+ body: JSON.stringify({}),
407
+ signal: AbortSignal.timeout(1e4)
408
+ });
409
+ if (!editResp.ok) {
410
+ results.push({
411
+ name: "signing-api",
412
+ status: "warn",
413
+ message: "Could not create edit to check signing key"
414
+ });
415
+ return results;
416
+ }
417
+ const edit = await editResp.json();
418
+ try {
419
+ const bundlesResp = await fetch(`${baseUrl}/edits/${edit.id}/bundles`, {
420
+ headers: { Authorization: `Bearer ${accessToken}` },
421
+ signal: AbortSignal.timeout(1e4)
422
+ });
423
+ if (!bundlesResp.ok) {
424
+ results.push({
425
+ name: "signing-api",
426
+ status: "warn",
427
+ message: "Could not list bundles"
428
+ });
429
+ return results;
430
+ }
431
+ const bundlesData = await bundlesResp.json();
432
+ const bundles = bundlesData.bundles ?? [];
433
+ if (bundles.length === 0) {
434
+ results.push({
435
+ name: "signing-api",
436
+ status: "warn",
437
+ message: "No bundles uploaded yet",
438
+ suggestion: "Upload at least one AAB with 'gpc publish' to enable signing key verification"
439
+ });
440
+ return results;
441
+ }
442
+ latestVersionCode = bundles.reduce(
443
+ (max, b) => b.versionCode > max.versionCode ? b : max
444
+ ).versionCode;
445
+ const apksResp = await fetch(`${baseUrl}/generatedApks/${latestVersionCode}`, {
446
+ headers: { Authorization: `Bearer ${accessToken}` },
447
+ signal: AbortSignal.timeout(1e4)
448
+ });
449
+ if (apksResp.ok) {
450
+ const apksData = await apksResp.json();
451
+ apiFingerprint = apksData.generatedApks?.[0]?.certificateSha256Fingerprint;
452
+ }
453
+ } finally {
454
+ await fetch(`${baseUrl}/edits/${edit.id}`, {
455
+ method: "DELETE",
456
+ headers: { Authorization: `Bearer ${accessToken}` },
457
+ signal: AbortSignal.timeout(5e3)
458
+ }).catch(() => {
459
+ });
460
+ }
461
+ } catch (err) {
462
+ results.push({
463
+ name: "signing-api",
464
+ status: "warn",
465
+ message: `Could not verify signing key: ${err instanceof Error ? err.message : String(err)}`
466
+ });
467
+ return results;
468
+ }
469
+ if (apiFingerprint) {
470
+ results.push({
471
+ name: "signing-api",
472
+ status: "pass",
473
+ message: `Play signing cert (v${latestVersionCode}): ${apiFingerprint}`
474
+ });
475
+ } else {
476
+ results.push({
477
+ name: "signing-api",
478
+ status: "warn",
479
+ message: `No signing certificate found for versionCode ${latestVersionCode}`,
480
+ suggestion: "Your app may not be enrolled in Play App Signing"
481
+ });
482
+ return results;
483
+ }
484
+ if (!keystorePath) {
485
+ results.push({
486
+ name: "signing-local",
487
+ status: "info",
488
+ message: "No local keystore provided for comparison",
489
+ suggestion: "Provide --keystore <path> and --store-pass <password> to compare against Play signing cert"
490
+ });
491
+ return results;
492
+ }
493
+ if (!storePassword) {
494
+ results.push({
495
+ name: "signing-local",
496
+ status: "warn",
497
+ message: "Keystore path provided but no password",
498
+ suggestion: "Provide --store-pass <password> or set GPC_STORE_PASSWORD"
499
+ });
500
+ return results;
501
+ }
502
+ try {
503
+ const { getKeystoreFingerprint, compareFingerprints } = await import("@gpc-cli/core");
504
+ const local = await getKeystoreFingerprint(keystorePath, storePassword, keyAlias);
505
+ if (compareFingerprints(local.sha256, apiFingerprint)) {
506
+ results.push({
507
+ name: "signing-local",
508
+ status: "pass",
509
+ message: `Local keystore (${local.alias}) matches Play signing cert`
510
+ });
511
+ } else {
512
+ results.push({
513
+ name: "signing-local",
514
+ status: "fail",
515
+ message: `Signing key mismatch: local ${local.sha256} vs Play ${apiFingerprint}`,
516
+ suggestion: "Your local keystore does not match the Play signing certificate. If you distribute outside Play with this key, register it in Play Console to avoid installation blocks after September 30, 2026."
517
+ });
518
+ }
519
+ } catch (err) {
520
+ const error = err;
521
+ if (error.code === "KEYTOOL_NOT_FOUND") {
522
+ results.push({
523
+ name: "signing-local",
524
+ status: "warn",
525
+ message: "keytool not found",
526
+ suggestion: "Install a JDK to enable local keystore verification"
527
+ });
528
+ } else {
529
+ results.push({
530
+ name: "signing-local",
531
+ status: "warn",
532
+ message: `Could not read keystore: ${error.message ?? String(err)}`
533
+ });
534
+ }
535
+ }
536
+ return results;
537
+ }
394
538
  async function applyFix(check) {
395
539
  switch (check.name) {
396
540
  case "config-dir":
@@ -443,7 +587,7 @@ async function applyFix(check) {
443
587
  }
444
588
  }
445
589
  function registerDoctorCommand(program) {
446
- program.command("doctor").description("Verify setup and connectivity").option("--fix", "Attempt to auto-fix failing checks").action(async (opts, cmd) => {
590
+ program.command("doctor").description("Verify setup and connectivity").option("--fix", "Attempt to auto-fix failing checks").option("--verify", "Run signing key verification checks").option("--keystore <path>", "Path to Android keystore (or set GPC_KEYSTORE_PATH)").option("--store-pass <password>", "Keystore password (or set GPC_STORE_PASSWORD)").option("--key-alias <alias>", "Key alias in keystore").action(async (opts, cmd) => {
447
591
  const results = [];
448
592
  const parentOpts = cmd.parent?.opts() ?? {};
449
593
  const jsonMode = !!(parentOpts["json"] || parentOpts["output"] === "json");
@@ -734,6 +878,33 @@ function registerDoctorCommand(program) {
734
878
  }
735
879
  }
736
880
  results.push(checkVerificationDeadline());
881
+ if (opts["verify"] && accessToken && config?.app) {
882
+ const ksPath = opts["keystore"] ?? process.env["GPC_KEYSTORE_PATH"];
883
+ const ksPass = opts["storePass"] ?? process.env["GPC_STORE_PASSWORD"];
884
+ const ksAlias = opts["keyAlias"];
885
+ const signingResults = await checkSigningKey(
886
+ config.app,
887
+ accessToken,
888
+ ksPath,
889
+ ksPass,
890
+ ksAlias
891
+ );
892
+ results.push(...signingResults);
893
+ } else if (opts["verify"] && !accessToken) {
894
+ results.push({
895
+ name: "signing-api",
896
+ status: "warn",
897
+ message: "Cannot verify signing key without authentication",
898
+ suggestion: "Run 'gpc auth login' first, then retry with --verify"
899
+ });
900
+ } else if (opts["verify"] && !config?.app) {
901
+ results.push({
902
+ name: "signing-api",
903
+ status: "warn",
904
+ message: "Cannot verify signing key without a configured app",
905
+ suggestion: "Set a default app with 'gpc config set app <package>' or use --app"
906
+ });
907
+ }
737
908
  if (opts["fix"]) {
738
909
  for (const r of results) {
739
910
  if (r.status === "fail" || r.status === "warn") {
@@ -800,4 +971,4 @@ export {
800
971
  checkVerificationDeadline,
801
972
  registerDoctorCommand
802
973
  };
803
- //# sourceMappingURL=doctor-FSUI44DD.js.map
974
+ //# sourceMappingURL=doctor-QRHXY3FC.js.map