@posthog/wizard 2.0.1 → 2.1.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 (116) hide show
  1. package/dist/bin.js +53 -8
  2. package/dist/bin.js.map +1 -1
  3. package/dist/src/__tests__/cli.test.js +50 -3
  4. package/dist/src/__tests__/cli.test.js.map +1 -1
  5. package/dist/src/__tests__/package-json.test.d.ts +1 -0
  6. package/dist/src/__tests__/package-json.test.js +173 -0
  7. package/dist/src/__tests__/package-json.test.js.map +1 -0
  8. package/dist/src/frameworks/angular/angular-wizard-agent.js +1 -6
  9. package/dist/src/frameworks/angular/angular-wizard-agent.js.map +1 -1
  10. package/dist/src/frameworks/astro/astro-wizard-agent.js +1 -4
  11. package/dist/src/frameworks/astro/astro-wizard-agent.js.map +1 -1
  12. package/dist/src/frameworks/nextjs/nextjs-wizard-agent.js +1 -4
  13. package/dist/src/frameworks/nextjs/nextjs-wizard-agent.js.map +1 -1
  14. package/dist/src/frameworks/nuxt/nuxt-wizard-agent.js +1 -4
  15. package/dist/src/frameworks/nuxt/nuxt-wizard-agent.js.map +1 -1
  16. package/dist/src/frameworks/react-native/react-native-wizard-agent.js +1 -6
  17. package/dist/src/frameworks/react-native/react-native-wizard-agent.js.map +1 -1
  18. package/dist/src/frameworks/react-router/react-router-wizard-agent.js +1 -6
  19. package/dist/src/frameworks/react-router/react-router-wizard-agent.js.map +1 -1
  20. package/dist/src/frameworks/tanstack-router/tanstack-router-wizard-agent.js +1 -6
  21. package/dist/src/frameworks/tanstack-router/tanstack-router-wizard-agent.js.map +1 -1
  22. package/dist/src/frameworks/tanstack-start/tanstack-start-wizard-agent.js +1 -6
  23. package/dist/src/frameworks/tanstack-start/tanstack-start-wizard-agent.js.map +1 -1
  24. package/dist/src/frameworks/vue/vue-wizard-agent.js +1 -4
  25. package/dist/src/frameworks/vue/vue-wizard-agent.js.map +1 -1
  26. package/dist/src/lib/__tests__/agent-interface.test.js +1 -0
  27. package/dist/src/lib/__tests__/agent-interface.test.js.map +1 -1
  28. package/dist/src/lib/__tests__/yara-hooks.test.d.ts +1 -0
  29. package/dist/src/lib/__tests__/yara-hooks.test.js +432 -0
  30. package/dist/src/lib/__tests__/yara-hooks.test.js.map +1 -0
  31. package/dist/src/lib/__tests__/yara-scanner.test.d.ts +1 -0
  32. package/dist/src/lib/__tests__/yara-scanner.test.js +613 -0
  33. package/dist/src/lib/__tests__/yara-scanner.test.js.map +1 -0
  34. package/dist/src/lib/agent-interface.d.ts +4 -2
  35. package/dist/src/lib/agent-interface.js +40 -26
  36. package/dist/src/lib/agent-interface.js.map +1 -1
  37. package/dist/src/lib/agent-runner.js +49 -15
  38. package/dist/src/lib/agent-runner.js.map +1 -1
  39. package/dist/src/lib/commandments.js +1 -0
  40. package/dist/src/lib/commandments.js.map +1 -1
  41. package/dist/src/lib/constants.d.ts +4 -3
  42. package/dist/src/lib/constants.js +3 -2
  43. package/dist/src/lib/constants.js.map +1 -1
  44. package/dist/src/lib/middleware/benchmark.js +2 -6
  45. package/dist/src/lib/middleware/benchmark.js.map +1 -1
  46. package/dist/src/lib/middleware/benchmarks/json-writer.js +1 -2
  47. package/dist/src/lib/middleware/benchmarks/json-writer.js.map +1 -1
  48. package/dist/src/lib/middleware/benchmarks/summary.js +6 -10
  49. package/dist/src/lib/middleware/benchmarks/summary.js.map +1 -1
  50. package/dist/src/lib/skill-install.d.ts +10 -0
  51. package/dist/src/lib/skill-install.js +23 -0
  52. package/dist/src/lib/skill-install.js.map +1 -0
  53. package/dist/src/lib/version.d.ts +1 -1
  54. package/dist/src/lib/version.js +1 -1
  55. package/dist/src/lib/version.js.map +1 -1
  56. package/dist/src/lib/wizard-session.d.ts +13 -0
  57. package/dist/src/lib/wizard-session.js +3 -0
  58. package/dist/src/lib/wizard-session.js.map +1 -1
  59. package/dist/src/lib/yara-hooks.d.ts +44 -0
  60. package/dist/src/lib/yara-hooks.js +377 -0
  61. package/dist/src/lib/yara-hooks.js.map +1 -0
  62. package/dist/src/lib/yara-scanner.d.ts +61 -0
  63. package/dist/src/lib/yara-scanner.js +328 -0
  64. package/dist/src/lib/yara-scanner.js.map +1 -0
  65. package/dist/src/run.d.ts +3 -0
  66. package/dist/src/run.js +11 -2
  67. package/dist/src/run.js.map +1 -1
  68. package/dist/src/steps/add-mcp-server-to-clients/index.d.ts +2 -1
  69. package/dist/src/steps/add-mcp-server-to-clients/index.js +1 -1
  70. package/dist/src/steps/add-mcp-server-to-clients/index.js.map +1 -1
  71. package/dist/src/steps/add-or-update-environment-variables.js +9 -10
  72. package/dist/src/steps/add-or-update-environment-variables.js.map +1 -1
  73. package/dist/src/steps/upload-environment-variables/providers/vercel.js +4 -8
  74. package/dist/src/steps/upload-environment-variables/providers/vercel.js.map +1 -1
  75. package/dist/src/ui/logging-ui.d.ts +5 -0
  76. package/dist/src/ui/logging-ui.js +3 -0
  77. package/dist/src/ui/logging-ui.js.map +1 -1
  78. package/dist/src/ui/tui/ink-ui.d.ts +5 -0
  79. package/dist/src/ui/tui/ink-ui.js +3 -0
  80. package/dist/src/ui/tui/ink-ui.js.map +1 -1
  81. package/dist/src/ui/tui/primitives/Divider.d.ts +6 -0
  82. package/dist/src/ui/tui/primitives/Divider.js +15 -0
  83. package/dist/src/ui/tui/primitives/Divider.js.map +1 -0
  84. package/dist/src/ui/tui/primitives/index.d.ts +1 -0
  85. package/dist/src/ui/tui/primitives/index.js +1 -0
  86. package/dist/src/ui/tui/primitives/index.js.map +1 -1
  87. package/dist/src/ui/tui/router.d.ts +2 -1
  88. package/dist/src/ui/tui/router.js +1 -0
  89. package/dist/src/ui/tui/router.js.map +1 -1
  90. package/dist/src/ui/tui/screen-registry.js +2 -0
  91. package/dist/src/ui/tui/screen-registry.js.map +1 -1
  92. package/dist/src/ui/tui/screens/IntroScreen.js +18 -2
  93. package/dist/src/ui/tui/screens/IntroScreen.js.map +1 -1
  94. package/dist/src/ui/tui/screens/PortConflictScreen.d.ts +11 -0
  95. package/dist/src/ui/tui/screens/PortConflictScreen.js +30 -0
  96. package/dist/src/ui/tui/screens/PortConflictScreen.js.map +1 -0
  97. package/dist/src/ui/tui/store.d.ts +18 -0
  98. package/dist/src/ui/tui/store.js +25 -0
  99. package/dist/src/ui/tui/store.js.map +1 -1
  100. package/dist/src/ui/wizard-ui.d.ts +6 -0
  101. package/dist/src/ui/wizard-ui.js.map +1 -1
  102. package/dist/src/utils/debug.js +1 -5
  103. package/dist/src/utils/debug.js.map +1 -1
  104. package/dist/src/utils/logging.js +7 -10
  105. package/dist/src/utils/logging.js.map +1 -1
  106. package/dist/src/utils/oauth.js +44 -4
  107. package/dist/src/utils/oauth.js.map +1 -1
  108. package/dist/src/utils/package-json.d.ts +5 -0
  109. package/dist/src/utils/package-json.js +20 -0
  110. package/dist/src/utils/package-json.js.map +1 -1
  111. package/dist/src/utils/rules/universal.md +12 -0
  112. package/dist/src/utils/setup-utils.js +12 -14
  113. package/dist/src/utils/setup-utils.js.map +1 -1
  114. package/dist/src/utils/types.d.ts +9 -0
  115. package/dist/src/utils/types.js.map +1 -1
  116. package/package.json +1 -2
@@ -1 +1 @@
1
- {"version":3,"file":"IntroScreen.js","sourceRoot":"","sources":["../../../../../src/ui/tui/screens/IntroScreen.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * IntroScreen — Welcome, framework detection, and continue/cancel prompt.\n *\n * Three states:\n * 1. Detecting: spinner while bin.ts runs detection\n * 2. Detection failed: framework picker, then continue/cancel\n * 3. Detection succeeded: show result, then continue/cancel\n *\n * Calls store.completeSetup() which unblocks bin.ts to start runWizard.\n */\n\nimport path from 'path';\nimport { Box, Text } from 'ink';\nimport { useState, useSyncExternalStore } from 'react';\nimport type { WizardStore } from '../store.js';\nimport { Integration } from '../../../lib/constants.js';\nimport { PickerMenu, LoadingBox } from '../primitives/index.js';\n\ninterface IntroScreenProps {\n store: WizardStore;\n}\n\nexport const IntroScreen = ({ store }: IntroScreenProps) => {\n useSyncExternalStore(\n (cb) => store.subscribe(cb),\n () => store.getSnapshot(),\n );\n\n const [pickingFramework, setPickingFramework] = useState(false);\n const [manuallySelected, setManuallySelected] = useState(false);\n\n const { session } = store;\n const config = session.frameworkConfig;\n const frameworkLabel =\n session.detectedFrameworkLabel ?? config?.metadata.name;\n const detecting = !session.detectionComplete;\n const needsFrameworkPick =\n session.detectionComplete && !session.frameworkConfig;\n const showContinue =\n session.frameworkConfig !== null && !detecting && !pickingFramework;\n const showDescription = showContinue;\n\n return (\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n alignItems=\"center\"\n justifyContent=\"center\"\n >\n <Box flexDirection=\"column\" alignItems=\"center\" marginBottom={1}>\n <Text bold>\n <Text color=\"#1D4AFF\">{'\\u2588'}</Text>\n <Text color=\"#F54E00\">{'\\u2588'}</Text>\n <Text color=\"#F9BD2B\">{'\\u2588'}</Text>\n {detecting ? ' PostHog Wizard starting up' : ' PostHog Wizard 🦔'}\n </Text>\n\n {showDescription && (\n <Box flexDirection=\"column\" alignItems=\"center\" marginTop={1}>\n <Text dimColor>\n We'll use AI to analyze your project and integrate PostHog.\n </Text>\n <Text dimColor>\n .env* file contents will not leave your machine.\n </Text>\n <Box marginTop={1}>\n <Text>Let's do two hours of work in eight minutes.</Text>\n </Box>\n </Box>\n )}\n </Box>\n\n {detecting && (\n <Box marginY={1}>\n <LoadingBox message=\"Detecting project framework...\" />\n </Box>\n )}\n\n {needsFrameworkPick && (\n <Box marginY={1}>\n <Text dimColor>Could not auto-detect your framework.</Text>\n </Box>\n )}\n\n {config?.metadata.preRunNotice && (\n <Text color=\"yellow\">{config.metadata.preRunNotice}</Text>\n )}\n\n {(needsFrameworkPick || pickingFramework) && (\n <FrameworkPicker\n store={store}\n onComplete={() => setPickingFramework(false)}\n />\n )}\n\n {!detecting && !pickingFramework && (\n <Box flexDirection=\"column\">\n <Text>\n <Text>\n Directory <Text color=\"green\">{'\\u2714'}</Text>{' '}\n </Text>\n <Text>\n {'/'}\n {path.basename(session.installDir)}{' '}\n </Text>\n </Text>\n {frameworkLabel && (\n <Text>\n <Text>\n Framework <Text color=\"green\">{'\\u2714'}</Text>{' '}\n </Text>\n <Text>\n {frameworkLabel}\n {!manuallySelected && ' (detected)'}{' '}\n {config?.metadata.beta && '[BETA]'}\n </Text>\n </Text>\n )}\n {showContinue && (\n <PickerMenu\n options={[\n { label: 'Continue', value: 'continue' },\n { label: 'Change framework', value: 'framework' },\n { label: 'Cancel', value: 'cancel' },\n ]}\n onSelect={(value) => {\n const choice = Array.isArray(value) ? value[0] : value;\n if (choice === 'cancel') {\n process.exit(0);\n } else if (choice === 'framework') {\n setPickingFramework(true);\n setManuallySelected(true);\n } else {\n store.completeSetup();\n }\n }}\n />\n )}\n </Box>\n )}\n </Box>\n );\n};\n\n/** Framework picker shown when auto-detection fails. */\nconst FrameworkPicker = ({\n store,\n onComplete,\n}: {\n store: WizardStore;\n onComplete?: () => void;\n}) => {\n // Build options from the framework registry (loaded dynamically to avoid circular deps)\n const options = Object.values(Integration).map((value) => ({\n label: value,\n value,\n }));\n\n return (\n <PickerMenu<Integration>\n centered\n columns={2}\n message=\"Select your framework\"\n options={options}\n onSelect={(value) => {\n const integration = Array.isArray(value) ? value[0] : value;\n void import('../../../lib/registry.js').then(\n ({ FRAMEWORK_REGISTRY }) => {\n const config = FRAMEWORK_REGISTRY[integration];\n store.setFrameworkConfig(integration, config);\n store.setDetectedFramework(config.metadata.name);\n onComplete?.();\n },\n );\n }}\n />\n );\n};\n"]}
1
+ {"version":3,"file":"IntroScreen.js","sourceRoot":"","sources":["../../../../../src/ui/tui/screens/IntroScreen.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * IntroScreen — Welcome, framework detection, and continue/cancel prompt.\n *\n * Three states:\n * 1. Detecting: spinner while bin.ts runs detection\n * 2. Detection failed: framework picker, then continue/cancel\n * 3. Detection succeeded: show result, then continue/cancel\n *\n * Calls store.completeSetup() which unblocks bin.ts to start runWizard.\n */\n\nimport path from 'path';\nimport { Box, Text } from 'ink';\nimport { useState, useSyncExternalStore } from 'react';\nimport type { WizardStore } from '../store.js';\nimport { Integration } from '../../../lib/constants.js';\nimport { PickerMenu, LoadingBox } from '../primitives/index.js';\n\ninterface IntroScreenProps {\n store: WizardStore;\n}\n\nexport const IntroScreen = ({ store }: IntroScreenProps) => {\n useSyncExternalStore(\n (cb) => store.subscribe(cb),\n () => store.getSnapshot(),\n );\n\n const [pickingFramework, setPickingFramework] = useState(false);\n const [manuallySelected, setManuallySelected] = useState(false);\n\n const { session } = store;\n const config = session.frameworkConfig;\n const frameworkLabel =\n session.detectedFrameworkLabel ?? config?.metadata.name;\n const detecting = !session.detectionComplete;\n const needsFrameworkPick =\n session.detectionComplete && !session.frameworkConfig;\n const unsupported = session.unsupportedVersion;\n const showContinue =\n session.frameworkConfig !== null &&\n !detecting &&\n !pickingFramework &&\n !unsupported;\n const showDescription = showContinue;\n\n return (\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n alignItems=\"center\"\n justifyContent=\"center\"\n >\n <Box flexDirection=\"column\" alignItems=\"center\" marginBottom={1}>\n <Text bold>\n <Text color=\"#1D4AFF\">{'\\u2588'}</Text>\n <Text color=\"#F54E00\">{'\\u2588'}</Text>\n <Text color=\"#F9BD2B\">{'\\u2588'}</Text>\n {detecting ? ' PostHog Wizard starting up' : ' PostHog Wizard 🦔'}\n </Text>\n\n {showDescription && (\n <Box flexDirection=\"column\" alignItems=\"center\" marginTop={1}>\n <Text dimColor>\n We'll use AI to analyze your project and integrate PostHog.\n </Text>\n <Text dimColor>\n .env* file contents will not leave your machine.\n </Text>\n <Box marginTop={1}>\n <Text>Let's do two hours of work in eight minutes.</Text>\n </Box>\n </Box>\n )}\n </Box>\n\n {detecting && (\n <Box marginY={1}>\n <LoadingBox message=\"Detecting project framework...\" />\n </Box>\n )}\n\n {needsFrameworkPick && (\n <Box marginY={1}>\n <Text dimColor>Could not auto-detect your framework.</Text>\n </Box>\n )}\n\n {config?.metadata.preRunNotice && (\n <Text color=\"yellow\">{config.metadata.preRunNotice}</Text>\n )}\n\n {(needsFrameworkPick || pickingFramework) && (\n <FrameworkPicker\n store={store}\n onComplete={() => setPickingFramework(false)}\n />\n )}\n\n {!detecting && !pickingFramework && (\n <Box flexDirection=\"column\">\n <Text>\n <Text>\n Directory <Text color=\"green\">{'\\u2714'}</Text>{' '}\n </Text>\n <Text>\n {'/'}\n {path.basename(session.installDir)}{' '}\n </Text>\n </Text>\n {frameworkLabel && (\n <Text>\n <Text>\n Framework <Text color=\"green\">{'\\u2714'}</Text>{' '}\n </Text>\n <Text>\n {frameworkLabel}\n {!manuallySelected && ' (detected)'}{' '}\n {config?.metadata.beta && '[BETA]'}\n </Text>\n </Text>\n )}\n {unsupported && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color=\"#DC9300\">\n Version {unsupported.current} is not supported by the wizard.\n Please upgrade to {unsupported.minimum} or later.\n </Text>\n <Text dimColor>Manual setup guide: {unsupported.docsUrl}</Text>\n <Box marginTop={1}>\n <Text dimColor>\n Did we get this wrong? You can also select another framework.\n </Text>\n </Box>\n <PickerMenu\n options={[\n { label: 'Select another framework', value: 'framework' },\n { label: 'Exit', value: 'exit' },\n ]}\n onSelect={(value) => {\n const choice = Array.isArray(value) ? value[0] : value;\n if (choice === 'framework') {\n setPickingFramework(true);\n setManuallySelected(true);\n } else {\n process.exit(0);\n }\n }}\n />\n </Box>\n )}\n {showContinue && (\n <PickerMenu\n options={[\n { label: 'Continue', value: 'continue' },\n { label: 'Change framework', value: 'framework' },\n { label: 'Cancel', value: 'cancel' },\n ]}\n onSelect={(value) => {\n const choice = Array.isArray(value) ? value[0] : value;\n if (choice === 'cancel') {\n process.exit(0);\n } else if (choice === 'framework') {\n setPickingFramework(true);\n setManuallySelected(true);\n } else {\n store.completeSetup();\n }\n }}\n />\n )}\n </Box>\n )}\n </Box>\n );\n};\n\n/** Framework picker shown when auto-detection fails. */\nconst FrameworkPicker = ({\n store,\n onComplete,\n}: {\n store: WizardStore;\n onComplete?: () => void;\n}) => {\n // Build options from the framework registry (loaded dynamically to avoid circular deps)\n const options = Object.values(Integration).map((value) => ({\n label: value,\n value,\n }));\n\n return (\n <PickerMenu<Integration>\n centered\n columns={2}\n message=\"Select your framework\"\n options={options}\n onSelect={(value) => {\n const integration = Array.isArray(value) ? value[0] : value;\n void import('../../../lib/registry.js').then(\n ({ FRAMEWORK_REGISTRY }) => {\n const config = FRAMEWORK_REGISTRY[integration];\n store.setFrameworkConfig(integration, config);\n store.setDetectedFramework(config.metadata.name);\n onComplete?.();\n },\n );\n }}\n />\n );\n};\n"]}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * PortConflictScreen — Modal when another process is blocking the OAuth port.
3
+ *
4
+ * Offers to kill the blocking process and retry, or exit.
5
+ */
6
+ import type { WizardStore } from '../store.js';
7
+ interface PortConflictScreenProps {
8
+ store: WizardStore;
9
+ }
10
+ export declare const PortConflictScreen: ({ store }: PortConflictScreenProps) => import("react/jsx-runtime").JSX.Element | null;
11
+ export {};
@@ -0,0 +1,30 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * PortConflictScreen — Modal when another process is blocking the OAuth port.
4
+ *
5
+ * Offers to kill the blocking process and retry, or exit.
6
+ */
7
+ import { Box, Text } from 'ink';
8
+ import { useState, useSyncExternalStore } from 'react';
9
+ import { execSync } from 'node:child_process';
10
+ import { ConfirmationInput, Divider } from '../primitives/index.js';
11
+ import { OAUTH_PORT } from '../../../lib/constants.js';
12
+ export const PortConflictScreen = ({ store }) => {
13
+ useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
14
+ const [feedback, setFeedback] = useState(null);
15
+ const processInfo = store.session.portConflictProcess;
16
+ if (!processInfo)
17
+ return null;
18
+ return (_jsx(Box, { flexDirection: "column", flexGrow: 1, alignItems: "center", justifyContent: "center", children: _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "#DC9300", paddingX: 3, paddingY: 2, width: 72, children: [_jsx(Box, { justifyContent: "center", marginBottom: 1, children: _jsxs(Text, { color: "#DC9300", bold: true, children: ["Port ", OAUTH_PORT, " in use"] }) }), _jsx(Text, { children: "Another process is blocking the authentication server:" }), _jsxs(Box, { flexDirection: "column", marginY: 1, paddingLeft: 2, gap: 0, children: [_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Command " }), _jsx(Text, { bold: true, children: processInfo.command })] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "PID " }), _jsx(Text, { bold: true, children: processInfo.pid })] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "User " }), _jsx(Text, { bold: true, children: processInfo.user })] })] }), _jsx(Text, { dimColor: true, children: "Kill this process to continue, or exit and free the port manually." }), feedback && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: feedback }) })), _jsx(Box, { marginY: 1, children: _jsx(Divider, {}) }), _jsx(ConfirmationInput, { message: `Kill process and continue?`, confirmLabel: "Kill & continue [Enter]", cancelLabel: "Exit [Esc]", onConfirm: () => {
19
+ try {
20
+ execSync(`lsof -ti :${OAUTH_PORT} | xargs kill`, {
21
+ stdio: 'ignore',
22
+ });
23
+ store.resolvePortConflict();
24
+ }
25
+ catch {
26
+ setFeedback(`Could not kill the process. Try running: lsof -ti :${OAUTH_PORT} | xargs kill`);
27
+ }
28
+ }, onCancel: () => process.exit(1) })] }) }));
29
+ };
30
+ //# sourceMappingURL=PortConflictScreen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PortConflictScreen.js","sourceRoot":"","sources":["../../../../../src/ui/tui/screens/PortConflictScreen.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * PortConflictScreen — Modal when another process is blocking the OAuth port.\n *\n * Offers to kill the blocking process and retry, or exit.\n */\n\nimport { Box, Text } from 'ink';\nimport { useState, useSyncExternalStore } from 'react';\nimport { execSync } from 'node:child_process';\nimport type { WizardStore } from '../store.js';\nimport { ConfirmationInput, Divider } from '../primitives/index.js';\nimport { OAUTH_PORT } from '../../../lib/constants.js';\n\ninterface PortConflictScreenProps {\n store: WizardStore;\n}\n\nexport const PortConflictScreen = ({ store }: PortConflictScreenProps) => {\n useSyncExternalStore(\n (cb) => store.subscribe(cb),\n () => store.getSnapshot(),\n );\n\n const [feedback, setFeedback] = useState<string | null>(null);\n const processInfo = store.session.portConflictProcess;\n\n if (!processInfo) return null;\n\n return (\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n alignItems=\"center\"\n justifyContent=\"center\"\n >\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor=\"#DC9300\"\n paddingX={3}\n paddingY={2}\n width={72}\n >\n <Box justifyContent=\"center\" marginBottom={1}>\n <Text color=\"#DC9300\" bold>\n Port {OAUTH_PORT} in use\n </Text>\n </Box>\n\n <Text>Another process is blocking the authentication server:</Text>\n <Box flexDirection=\"column\" marginY={1} paddingLeft={2} gap={0}>\n <Text>\n <Text dimColor>Command </Text>\n <Text bold>{processInfo.command}</Text>\n </Text>\n <Text>\n <Text dimColor>PID </Text>\n <Text bold>{processInfo.pid}</Text>\n </Text>\n <Text>\n <Text dimColor>User </Text>\n <Text bold>{processInfo.user}</Text>\n </Text>\n </Box>\n <Text dimColor>\n Kill this process to continue, or exit and free the port manually.\n </Text>\n\n {feedback && (\n <Box marginTop={1}>\n <Text color=\"yellow\">{feedback}</Text>\n </Box>\n )}\n\n <Box marginY={1}>\n <Divider />\n </Box>\n\n <ConfirmationInput\n message={`Kill process and continue?`}\n confirmLabel=\"Kill & continue [Enter]\"\n cancelLabel=\"Exit [Esc]\"\n onConfirm={() => {\n try {\n execSync(`lsof -ti :${OAUTH_PORT} | xargs kill`, {\n stdio: 'ignore',\n });\n store.resolvePortConflict();\n } catch {\n setFeedback(\n `Could not kill the process. Try running: lsof -ti :${OAUTH_PORT} | xargs kill`,\n );\n }\n }}\n onCancel={() => process.exit(1)}\n />\n </Box>\n </Box>\n );\n};\n"]}
@@ -50,6 +50,8 @@ export declare class WizardStore {
50
50
  /** Blocks agent execution until the settings-override overlay is dismissed. */
51
51
  private _resolveSettingsOverride;
52
52
  private _backupAndFixSettings;
53
+ /** Blocks OAuth flow until the port-conflict overlay is dismissed. */
54
+ private _resolvePortConflict;
53
55
  constructor(flow?: Flow);
54
56
  get session(): WizardSession;
55
57
  set session(value: WizardSession);
@@ -66,6 +68,11 @@ export declare class WizardStore {
66
68
  setFrameworkConfig(integration: WizardSession['integration'], config: WizardSession['frameworkConfig']): void;
67
69
  setDetectionComplete(): void;
68
70
  setDetectedFramework(label: string): void;
71
+ setUnsupportedVersion(info: {
72
+ current: string;
73
+ minimum: string;
74
+ docsUrl: string;
75
+ }): void;
69
76
  setLoginUrl(url: string | null): void;
70
77
  setServiceStatus(status: {
71
78
  description: string;
@@ -76,6 +83,17 @@ export declare class WizardStore {
76
83
  * until the user dismisses it via backupAndFixSettingsOverride().
77
84
  */
78
85
  showSettingsOverride(keys: string[], backupAndFix: () => boolean): Promise<void>;
86
+ /**
87
+ * Push the port-conflict overlay and return a promise that blocks
88
+ * until the user kills the blocking process or exits.
89
+ */
90
+ showPortConflict(processInfo: {
91
+ command: string;
92
+ pid: string;
93
+ user: string;
94
+ }): Promise<void>;
95
+ /** Dismiss the port-conflict overlay after the user kills the process. */
96
+ resolvePortConflict(): void;
79
97
  /**
80
98
  * Back up .claude/settings.json. Dismisses the overlay on success.
81
99
  */
@@ -43,6 +43,8 @@ export class WizardStore {
43
43
  /** Blocks agent execution until the settings-override overlay is dismissed. */
44
44
  _resolveSettingsOverride = null;
45
45
  _backupAndFixSettings = null;
46
+ /** Blocks OAuth flow until the port-conflict overlay is dismissed. */
47
+ _resolvePortConflict = null;
46
48
  constructor(flow = Flow.Wizard) {
47
49
  this.router = new WizardRouter(flow);
48
50
  }
@@ -99,6 +101,7 @@ export class WizardStore {
99
101
  setFrameworkConfig(integration, config) {
100
102
  this.$session.setKey('integration', integration);
101
103
  this.$session.setKey('frameworkConfig', config);
104
+ this.$session.setKey('unsupportedVersion', null);
102
105
  this.emitChange();
103
106
  }
104
107
  setDetectionComplete() {
@@ -109,6 +112,10 @@ export class WizardStore {
109
112
  this.$session.setKey('detectedFrameworkLabel', label);
110
113
  this.emitChange();
111
114
  }
115
+ setUnsupportedVersion(info) {
116
+ this.$session.setKey('unsupportedVersion', info);
117
+ this.emitChange();
118
+ }
112
119
  setLoginUrl(url) {
113
120
  this.$session.setKey('loginUrl', url);
114
121
  this.emitChange();
@@ -129,6 +136,24 @@ export class WizardStore {
129
136
  this._resolveSettingsOverride = resolve;
130
137
  });
131
138
  }
139
+ /**
140
+ * Push the port-conflict overlay and return a promise that blocks
141
+ * until the user kills the blocking process or exits.
142
+ */
143
+ showPortConflict(processInfo) {
144
+ this.$session.setKey('portConflictProcess', processInfo);
145
+ this.pushOverlay(Overlay.PortConflict);
146
+ return new Promise((resolve) => {
147
+ this._resolvePortConflict = resolve;
148
+ });
149
+ }
150
+ /** Dismiss the port-conflict overlay after the user kills the process. */
151
+ resolvePortConflict() {
152
+ this.$session.setKey('portConflictProcess', null);
153
+ this.popOverlay();
154
+ this._resolvePortConflict?.();
155
+ this._resolvePortConflict = null;
156
+ }
132
157
  /**
133
158
  * Back up .claude/settings.json. Dismisses the overlay on success.
134
159
  */
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/ui/tui/store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * WizardStore — Nanostore-backed reactive store for the TUI.\n * React components subscribe via useSyncExternalStore.\n *\n * Navigation is delegated to WizardRouter.\n * The active screen is derived from session state — not imperatively set.\n * Overlays (outage, etc.) are the only imperative navigation.\n *\n * All session mutations that affect screen resolution go through\n * explicit setters so emitChange() is always called.\n */\n\nimport { atom, map } from 'nanostores';\nimport { TaskStatus } from '../wizard-ui.js';\nimport {\n type WizardSession,\n type OutroData,\n type DiscoveredFeature,\n AdditionalFeature,\n McpOutcome,\n RunPhase,\n buildSession,\n} from '../../lib/wizard-session.js';\nimport {\n WizardRouter,\n type ScreenName,\n Screen,\n Overlay,\n Flow,\n} from './router.js';\nimport { analytics, sessionProperties } from '../../utils/analytics.js';\n\nexport { TaskStatus, Screen, Overlay, Flow, RunPhase, McpOutcome };\nexport type { ScreenName, OutroData, WizardSession };\n\nexport interface TaskItem {\n label: string;\n activeForm?: string;\n status: TaskStatus;\n /** Legacy compat */\n done: boolean;\n}\n\nexport interface PlannedEvent {\n name: string;\n description: string;\n}\n\nexport class WizardStore {\n // ── Internal nanostore atoms ─────────────────────────────────────\n private $session = map<WizardSession>(buildSession({}));\n private $statusMessages = atom<string[]>([]);\n private $statusExpanded = atom(false);\n private $tasks = atom<TaskItem[]>([]);\n private $eventPlan = atom<PlannedEvent[]>([]);\n private $learnCardBlockIdx = atom(0);\n private $learnCardComplete = atom(false);\n private $version = atom(0);\n\n /** Last screen seen — used to detect screen transitions for analytics. */\n private _lastScreen: ScreenName | null = null;\n\n /** Hooks run when transitioning onto a screen. */\n private _enterScreenHooks = new Map<ScreenName, (() => void)[]>();\n\n version = '';\n\n /** Navigation router — resolves active screen from session state. */\n readonly router: WizardRouter;\n\n /**\n * Setup promise — IntroScreen resolves this when the user confirms.\n * bin.ts awaits it before calling runWizard.\n */\n private _resolveSetup!: () => void;\n readonly setupComplete: Promise<void> = new Promise((resolve) => {\n this._resolveSetup = resolve;\n });\n\n /** Blocks agent execution until the settings-override overlay is dismissed. */\n private _resolveSettingsOverride: (() => void) | null = null;\n private _backupAndFixSettings: (() => boolean) | null = null;\n\n constructor(flow: Flow = Flow.Wizard) {\n this.router = new WizardRouter(flow);\n }\n\n // ── State accessors (read from atoms) ────────────────────────────\n\n get session(): WizardSession {\n return this.$session.get();\n }\n\n set session(value: WizardSession) {\n this.$session.set(value);\n }\n\n get statusMessages(): string[] {\n return this.$statusMessages.get();\n }\n\n get tasks(): TaskItem[] {\n return this.$tasks.get();\n }\n\n get eventPlan(): PlannedEvent[] {\n return this.$eventPlan.get();\n }\n\n get statusExpanded(): boolean {\n return this.$statusExpanded.get();\n }\n\n toggleStatusExpanded(): void {\n this.$statusExpanded.set(!this.$statusExpanded.get());\n this.emitChange();\n }\n\n setStatusExpanded(expanded: boolean): void {\n if (this.$statusExpanded.get() !== expanded) {\n this.$statusExpanded.set(expanded);\n this.emitChange();\n }\n }\n\n // ── Session setters ─────────────────────────────────────────────\n // Every setter that affects screen resolution calls emitChange().\n // Business logic calls these instead of mutating session directly.\n\n /** Unblocks bin.ts via the setupComplete promise. */\n completeSetup(): void {\n this.$session.setKey('setupConfirmed', true);\n analytics.wizardCapture('setup confirmed', sessionProperties(this.session));\n this._resolveSetup();\n this.emitChange();\n }\n\n setRunPhase(phase: RunPhase): void {\n this.$session.setKey('runPhase', phase);\n this.emitChange();\n }\n\n setCredentials(credentials: WizardSession['credentials']): void {\n this.$session.setKey('credentials', credentials);\n analytics.wizardCapture('auth complete', {\n project_id: credentials?.projectId,\n });\n this.emitChange();\n }\n\n setFrameworkConfig(\n integration: WizardSession['integration'],\n config: WizardSession['frameworkConfig'],\n ): void {\n this.$session.setKey('integration', integration);\n this.$session.setKey('frameworkConfig', config);\n this.emitChange();\n }\n\n setDetectionComplete(): void {\n this.$session.setKey('detectionComplete', true);\n this.emitChange();\n }\n\n setDetectedFramework(label: string): void {\n this.$session.setKey('detectedFrameworkLabel', label);\n this.emitChange();\n }\n\n setLoginUrl(url: string | null): void {\n this.$session.setKey('loginUrl', url);\n this.emitChange();\n }\n\n setServiceStatus(\n status: { description: string; statusPageUrl: string } | null,\n ): void {\n this.$session.setKey('serviceStatus', status);\n this.emitChange();\n }\n\n /**\n * Push the settings-override overlay and return a promise that blocks\n * until the user dismisses it via backupAndFixSettingsOverride().\n */\n showSettingsOverride(\n keys: string[],\n backupAndFix: () => boolean,\n ): Promise<void> {\n this.$session.setKey('settingsOverrideKeys', keys);\n this._backupAndFixSettings = backupAndFix;\n this.pushOverlay(Overlay.SettingsOverride);\n return new Promise((resolve) => {\n this._resolveSettingsOverride = resolve;\n });\n }\n\n /**\n * Back up .claude/settings.json. Dismisses the overlay on success.\n */\n backupAndFixSettingsOverride(): boolean {\n const ok = this._backupAndFixSettings?.() ?? false;\n if (ok) {\n this.$session.setKey('settingsOverrideKeys', null);\n this.popOverlay();\n this._resolveSettingsOverride?.();\n this._resolveSettingsOverride = null;\n this._backupAndFixSettings = null;\n }\n return ok;\n }\n\n addDiscoveredFeature(feature: DiscoveredFeature): void {\n if (!this.session.discoveredFeatures.includes(feature)) {\n this.session.discoveredFeatures.push(feature);\n this.emitChange();\n }\n }\n\n /**\n * Enable an additional feature: enqueue it for the stop hook\n * and set any feature-specific session flags.\n */\n enableFeature(feature: AdditionalFeature): void {\n if (!this.session.additionalFeatureQueue.includes(feature)) {\n this.session.additionalFeatureQueue.push(feature);\n }\n // Feature-specific flags\n if (feature === AdditionalFeature.LLM) {\n this.session.llmOptIn = true;\n }\n analytics.wizardCapture('feature enabled', { feature });\n this.emitChange();\n }\n\n setMcpComplete(\n outcome: McpOutcome = McpOutcome.Skipped,\n installedClients: string[] = [],\n ): void {\n this.$session.setKey('mcpComplete', true);\n this.$session.setKey('mcpOutcome', outcome);\n this.$session.setKey('mcpInstalledClients', installedClients);\n analytics.wizardCapture('mcp complete', {\n mcp_outcome: outcome,\n mcp_installed_clients: installedClients,\n ...sessionProperties(this.session),\n });\n this.emitChange();\n }\n\n setOutroData(data: OutroData): void {\n this.$session.setKey('outroData', data);\n this.emitChange();\n }\n\n setFrameworkContext(key: string, value: unknown): void {\n const ctx = { ...this.$session.get().frameworkContext, [key]: value };\n this.$session.setKey('frameworkContext', ctx);\n this.emitChange();\n }\n\n // ── Derived state ───────────────────────────────────────────────\n\n /**\n * The screen that should be rendered right now.\n * Derived from session state via the router.\n */\n get currentScreen(): ScreenName {\n return this.router.resolve(this.session);\n }\n\n /** Direction hint for screen transitions. */\n get lastNavDirection(): 'push' | 'pop' | null {\n return this.router.lastNavDirection;\n }\n\n // ── Change notification ─────────────────────────────────────────\n\n getVersion(): number {\n return this.$version.get();\n }\n\n /**\n * Notify React that state has changed.\n * The router re-resolves the active screen on next render.\n */\n emitChange(): void {\n this.router._setDirection('push');\n this.$version.set(this.$version.get() + 1);\n this._detectTransition();\n }\n\n // ── Overlay navigation ──────────────────────────────────────────\n\n pushOverlay(overlay: Overlay): void {\n this.router._setDirection('push');\n this.router.pushOverlay(overlay);\n this.$version.set(this.$version.get() + 1);\n this._detectTransition();\n }\n\n popOverlay(): void {\n this.router._setDirection('pop');\n this.router.popOverlay();\n this.$version.set(this.$version.get() + 1);\n this._detectTransition();\n }\n\n // ── Screen transition analytics ─────────────────────────────────\n\n /**\n * Register a callback to run when transitioning onto the given screen.\n * Fires after every transition that lands on this screen.\n */\n onEnterScreen(screen: ScreenName, fn: () => void): void {\n const list = this._enterScreenHooks.get(screen) ?? [];\n list.push(fn);\n this._enterScreenHooks.set(screen, list);\n }\n\n /**\n * Detect screen transitions, run enter-screen hooks, and fire analytics.\n * Called at the end of emitChange/pushOverlay/popOverlay.\n */\n private _detectTransition(): void {\n const next = this.router.resolve(this.session);\n const prev = this._lastScreen;\n if (prev !== null && next !== prev) {\n const hooks = this._enterScreenHooks.get(next);\n if (hooks) {\n for (const fn of hooks) fn();\n }\n analytics.wizardCapture(`screen ${next}`, {\n from_screen: prev,\n ...sessionProperties(this.session),\n });\n }\n this._lastScreen = next;\n }\n\n // ── Agent observation state ─────────────────────────────────────\n\n pushStatus(message: string): void {\n const msgs = this.$statusMessages.get();\n // Skip consecutive duplicate messages\n if (msgs.length > 0 && msgs[msgs.length - 1] === message) return;\n this.$statusMessages.set([...msgs, message]);\n this.emitChange();\n }\n\n setTasks(tasks: TaskItem[]): void {\n this.$tasks.set(tasks);\n this.emitChange();\n }\n\n updateTask(index: number, done: boolean): void {\n const tasks = this.$tasks.get();\n if (tasks[index]) {\n const updated = [...tasks];\n updated[index] = {\n ...updated[index],\n done,\n status: done ? TaskStatus.Completed : TaskStatus.Pending,\n };\n this.$tasks.set(updated);\n this.emitChange();\n }\n }\n\n setEventPlan(events: PlannedEvent[]): void {\n this.$eventPlan.set(events);\n this.emitChange();\n }\n\n get learnCardBlockIdx(): number {\n return this.$learnCardBlockIdx.get();\n }\n\n setLearnCardBlockIdx(idx: number): void {\n this.$learnCardBlockIdx.set(idx);\n }\n\n get learnCardComplete(): boolean {\n return this.$learnCardComplete.get();\n }\n\n setLearnCardComplete(): void {\n this.$learnCardComplete.set(true);\n this.emitChange();\n }\n\n syncTodos(\n todos: Array<{ content: string; status: string; activeForm?: string }>,\n ): void {\n const incoming = todos.map((t) => ({\n label: t.content,\n activeForm: t.activeForm,\n status: (t.status as TaskStatus) || TaskStatus.Pending,\n done: t.status === TaskStatus.Completed,\n }));\n\n const incomingLabels = new Set(incoming.map((t) => t.label));\n\n const retained = this.$tasks\n .get()\n .filter((t) => t.done && !incomingLabels.has(t.label));\n\n this.$tasks.set([...retained, ...incoming]);\n this.emitChange();\n }\n\n // ── React integration ───────────────────────────────────────────\n\n subscribe(callback: () => void): () => void {\n return this.$version.listen(() => callback());\n }\n\n getSnapshot(): number {\n return this.$version.get();\n }\n}\n"]}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/ui/tui/store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * WizardStore — Nanostore-backed reactive store for the TUI.\n * React components subscribe via useSyncExternalStore.\n *\n * Navigation is delegated to WizardRouter.\n * The active screen is derived from session state — not imperatively set.\n * Overlays (outage, etc.) are the only imperative navigation.\n *\n * All session mutations that affect screen resolution go through\n * explicit setters so emitChange() is always called.\n */\n\nimport { atom, map } from 'nanostores';\nimport { TaskStatus } from '../wizard-ui.js';\nimport {\n type WizardSession,\n type OutroData,\n type DiscoveredFeature,\n AdditionalFeature,\n McpOutcome,\n RunPhase,\n buildSession,\n} from '../../lib/wizard-session.js';\nimport {\n WizardRouter,\n type ScreenName,\n Screen,\n Overlay,\n Flow,\n} from './router.js';\nimport { analytics, sessionProperties } from '../../utils/analytics.js';\n\nexport { TaskStatus, Screen, Overlay, Flow, RunPhase, McpOutcome };\nexport type { ScreenName, OutroData, WizardSession };\n\nexport interface TaskItem {\n label: string;\n activeForm?: string;\n status: TaskStatus;\n /** Legacy compat */\n done: boolean;\n}\n\nexport interface PlannedEvent {\n name: string;\n description: string;\n}\n\nexport class WizardStore {\n // ── Internal nanostore atoms ─────────────────────────────────────\n private $session = map<WizardSession>(buildSession({}));\n private $statusMessages = atom<string[]>([]);\n private $statusExpanded = atom(false);\n private $tasks = atom<TaskItem[]>([]);\n private $eventPlan = atom<PlannedEvent[]>([]);\n private $learnCardBlockIdx = atom(0);\n private $learnCardComplete = atom(false);\n private $version = atom(0);\n\n /** Last screen seen — used to detect screen transitions for analytics. */\n private _lastScreen: ScreenName | null = null;\n\n /** Hooks run when transitioning onto a screen. */\n private _enterScreenHooks = new Map<ScreenName, (() => void)[]>();\n\n version = '';\n\n /** Navigation router — resolves active screen from session state. */\n readonly router: WizardRouter;\n\n /**\n * Setup promise — IntroScreen resolves this when the user confirms.\n * bin.ts awaits it before calling runWizard.\n */\n private _resolveSetup!: () => void;\n readonly setupComplete: Promise<void> = new Promise((resolve) => {\n this._resolveSetup = resolve;\n });\n\n /** Blocks agent execution until the settings-override overlay is dismissed. */\n private _resolveSettingsOverride: (() => void) | null = null;\n private _backupAndFixSettings: (() => boolean) | null = null;\n\n /** Blocks OAuth flow until the port-conflict overlay is dismissed. */\n private _resolvePortConflict: (() => void) | null = null;\n\n constructor(flow: Flow = Flow.Wizard) {\n this.router = new WizardRouter(flow);\n }\n\n // ── State accessors (read from atoms) ────────────────────────────\n\n get session(): WizardSession {\n return this.$session.get();\n }\n\n set session(value: WizardSession) {\n this.$session.set(value);\n }\n\n get statusMessages(): string[] {\n return this.$statusMessages.get();\n }\n\n get tasks(): TaskItem[] {\n return this.$tasks.get();\n }\n\n get eventPlan(): PlannedEvent[] {\n return this.$eventPlan.get();\n }\n\n get statusExpanded(): boolean {\n return this.$statusExpanded.get();\n }\n\n toggleStatusExpanded(): void {\n this.$statusExpanded.set(!this.$statusExpanded.get());\n this.emitChange();\n }\n\n setStatusExpanded(expanded: boolean): void {\n if (this.$statusExpanded.get() !== expanded) {\n this.$statusExpanded.set(expanded);\n this.emitChange();\n }\n }\n\n // ── Session setters ─────────────────────────────────────────────\n // Every setter that affects screen resolution calls emitChange().\n // Business logic calls these instead of mutating session directly.\n\n /** Unblocks bin.ts via the setupComplete promise. */\n completeSetup(): void {\n this.$session.setKey('setupConfirmed', true);\n analytics.wizardCapture('setup confirmed', sessionProperties(this.session));\n this._resolveSetup();\n this.emitChange();\n }\n\n setRunPhase(phase: RunPhase): void {\n this.$session.setKey('runPhase', phase);\n this.emitChange();\n }\n\n setCredentials(credentials: WizardSession['credentials']): void {\n this.$session.setKey('credentials', credentials);\n analytics.wizardCapture('auth complete', {\n project_id: credentials?.projectId,\n });\n this.emitChange();\n }\n\n setFrameworkConfig(\n integration: WizardSession['integration'],\n config: WizardSession['frameworkConfig'],\n ): void {\n this.$session.setKey('integration', integration);\n this.$session.setKey('frameworkConfig', config);\n this.$session.setKey('unsupportedVersion', null);\n this.emitChange();\n }\n\n setDetectionComplete(): void {\n this.$session.setKey('detectionComplete', true);\n this.emitChange();\n }\n\n setDetectedFramework(label: string): void {\n this.$session.setKey('detectedFrameworkLabel', label);\n this.emitChange();\n }\n\n setUnsupportedVersion(info: {\n current: string;\n minimum: string;\n docsUrl: string;\n }): void {\n this.$session.setKey('unsupportedVersion', info);\n this.emitChange();\n }\n\n setLoginUrl(url: string | null): void {\n this.$session.setKey('loginUrl', url);\n this.emitChange();\n }\n\n setServiceStatus(\n status: { description: string; statusPageUrl: string } | null,\n ): void {\n this.$session.setKey('serviceStatus', status);\n this.emitChange();\n }\n\n /**\n * Push the settings-override overlay and return a promise that blocks\n * until the user dismisses it via backupAndFixSettingsOverride().\n */\n showSettingsOverride(\n keys: string[],\n backupAndFix: () => boolean,\n ): Promise<void> {\n this.$session.setKey('settingsOverrideKeys', keys);\n this._backupAndFixSettings = backupAndFix;\n this.pushOverlay(Overlay.SettingsOverride);\n return new Promise((resolve) => {\n this._resolveSettingsOverride = resolve;\n });\n }\n\n /**\n * Push the port-conflict overlay and return a promise that blocks\n * until the user kills the blocking process or exits.\n */\n showPortConflict(processInfo: {\n command: string;\n pid: string;\n user: string;\n }): Promise<void> {\n this.$session.setKey('portConflictProcess', processInfo);\n this.pushOverlay(Overlay.PortConflict);\n return new Promise((resolve) => {\n this._resolvePortConflict = resolve;\n });\n }\n\n /** Dismiss the port-conflict overlay after the user kills the process. */\n resolvePortConflict(): void {\n this.$session.setKey('portConflictProcess', null);\n this.popOverlay();\n this._resolvePortConflict?.();\n this._resolvePortConflict = null;\n }\n\n /**\n * Back up .claude/settings.json. Dismisses the overlay on success.\n */\n backupAndFixSettingsOverride(): boolean {\n const ok = this._backupAndFixSettings?.() ?? false;\n if (ok) {\n this.$session.setKey('settingsOverrideKeys', null);\n this.popOverlay();\n this._resolveSettingsOverride?.();\n this._resolveSettingsOverride = null;\n this._backupAndFixSettings = null;\n }\n return ok;\n }\n\n addDiscoveredFeature(feature: DiscoveredFeature): void {\n if (!this.session.discoveredFeatures.includes(feature)) {\n this.session.discoveredFeatures.push(feature);\n this.emitChange();\n }\n }\n\n /**\n * Enable an additional feature: enqueue it for the stop hook\n * and set any feature-specific session flags.\n */\n enableFeature(feature: AdditionalFeature): void {\n if (!this.session.additionalFeatureQueue.includes(feature)) {\n this.session.additionalFeatureQueue.push(feature);\n }\n // Feature-specific flags\n if (feature === AdditionalFeature.LLM) {\n this.session.llmOptIn = true;\n }\n analytics.wizardCapture('feature enabled', { feature });\n this.emitChange();\n }\n\n setMcpComplete(\n outcome: McpOutcome = McpOutcome.Skipped,\n installedClients: string[] = [],\n ): void {\n this.$session.setKey('mcpComplete', true);\n this.$session.setKey('mcpOutcome', outcome);\n this.$session.setKey('mcpInstalledClients', installedClients);\n analytics.wizardCapture('mcp complete', {\n mcp_outcome: outcome,\n mcp_installed_clients: installedClients,\n ...sessionProperties(this.session),\n });\n this.emitChange();\n }\n\n setOutroData(data: OutroData): void {\n this.$session.setKey('outroData', data);\n this.emitChange();\n }\n\n setFrameworkContext(key: string, value: unknown): void {\n const ctx = { ...this.$session.get().frameworkContext, [key]: value };\n this.$session.setKey('frameworkContext', ctx);\n this.emitChange();\n }\n\n // ── Derived state ───────────────────────────────────────────────\n\n /**\n * The screen that should be rendered right now.\n * Derived from session state via the router.\n */\n get currentScreen(): ScreenName {\n return this.router.resolve(this.session);\n }\n\n /** Direction hint for screen transitions. */\n get lastNavDirection(): 'push' | 'pop' | null {\n return this.router.lastNavDirection;\n }\n\n // ── Change notification ─────────────────────────────────────────\n\n getVersion(): number {\n return this.$version.get();\n }\n\n /**\n * Notify React that state has changed.\n * The router re-resolves the active screen on next render.\n */\n emitChange(): void {\n this.router._setDirection('push');\n this.$version.set(this.$version.get() + 1);\n this._detectTransition();\n }\n\n // ── Overlay navigation ──────────────────────────────────────────\n\n pushOverlay(overlay: Overlay): void {\n this.router._setDirection('push');\n this.router.pushOverlay(overlay);\n this.$version.set(this.$version.get() + 1);\n this._detectTransition();\n }\n\n popOverlay(): void {\n this.router._setDirection('pop');\n this.router.popOverlay();\n this.$version.set(this.$version.get() + 1);\n this._detectTransition();\n }\n\n // ── Screen transition analytics ─────────────────────────────────\n\n /**\n * Register a callback to run when transitioning onto the given screen.\n * Fires after every transition that lands on this screen.\n */\n onEnterScreen(screen: ScreenName, fn: () => void): void {\n const list = this._enterScreenHooks.get(screen) ?? [];\n list.push(fn);\n this._enterScreenHooks.set(screen, list);\n }\n\n /**\n * Detect screen transitions, run enter-screen hooks, and fire analytics.\n * Called at the end of emitChange/pushOverlay/popOverlay.\n */\n private _detectTransition(): void {\n const next = this.router.resolve(this.session);\n const prev = this._lastScreen;\n if (prev !== null && next !== prev) {\n const hooks = this._enterScreenHooks.get(next);\n if (hooks) {\n for (const fn of hooks) fn();\n }\n analytics.wizardCapture(`screen ${next}`, {\n from_screen: prev,\n ...sessionProperties(this.session),\n });\n }\n this._lastScreen = next;\n }\n\n // ── Agent observation state ─────────────────────────────────────\n\n pushStatus(message: string): void {\n const msgs = this.$statusMessages.get();\n // Skip consecutive duplicate messages\n if (msgs.length > 0 && msgs[msgs.length - 1] === message) return;\n this.$statusMessages.set([...msgs, message]);\n this.emitChange();\n }\n\n setTasks(tasks: TaskItem[]): void {\n this.$tasks.set(tasks);\n this.emitChange();\n }\n\n updateTask(index: number, done: boolean): void {\n const tasks = this.$tasks.get();\n if (tasks[index]) {\n const updated = [...tasks];\n updated[index] = {\n ...updated[index],\n done,\n status: done ? TaskStatus.Completed : TaskStatus.Pending,\n };\n this.$tasks.set(updated);\n this.emitChange();\n }\n }\n\n setEventPlan(events: PlannedEvent[]): void {\n this.$eventPlan.set(events);\n this.emitChange();\n }\n\n get learnCardBlockIdx(): number {\n return this.$learnCardBlockIdx.get();\n }\n\n setLearnCardBlockIdx(idx: number): void {\n this.$learnCardBlockIdx.set(idx);\n }\n\n get learnCardComplete(): boolean {\n return this.$learnCardComplete.get();\n }\n\n setLearnCardComplete(): void {\n this.$learnCardComplete.set(true);\n this.emitChange();\n }\n\n syncTodos(\n todos: Array<{ content: string; status: string; activeForm?: string }>,\n ): void {\n const incoming = todos.map((t) => ({\n label: t.content,\n activeForm: t.activeForm,\n status: (t.status as TaskStatus) || TaskStatus.Pending,\n done: t.status === TaskStatus.Completed,\n }));\n\n const incomingLabels = new Set(incoming.map((t) => t.label));\n\n const retained = this.$tasks\n .get()\n .filter((t) => t.done && !incomingLabels.has(t.label));\n\n this.$tasks.set([...retained, ...incoming]);\n this.emitChange();\n }\n\n // ── React integration ───────────────────────────────────────────\n\n subscribe(callback: () => void): () => void {\n return this.$version.listen(() => callback());\n }\n\n getSnapshot(): number {\n return this.$version.get();\n }\n}\n"]}
@@ -45,6 +45,12 @@ export interface WizardUI {
45
45
  description: string;
46
46
  statusPageUrl: string;
47
47
  }): void;
48
+ /** Warn that another process is blocking the OAuth port (pushes overlay in TUI). */
49
+ showPortConflict(processInfo: {
50
+ command: string;
51
+ pid: string;
52
+ user: string;
53
+ }): Promise<void>;
48
54
  /** Warn that .claude/settings.json overrides blocking env vars (pushes blocking overlay in TUI). */
49
55
  showSettingsOverride(keys: string[], backupAndFix: () => boolean): Promise<void>;
50
56
  /** Set the detected framework label (e.g., "Django with Wagtail CMS") */
@@ -1 +1 @@
1
- {"version":3,"file":"wizard-ui.js","sourceRoot":"","sources":["../../../src/ui/wizard-ui.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAEH,IAAY,UAIX;AAJD,WAAY,UAAU;IACpB,iCAAmB,CAAA;IACnB,wCAA0B,CAAA;IAC1B,qCAAuB,CAAA;AACzB,CAAC,EAJW,UAAU,0BAAV,UAAU,QAIrB","sourcesContent":["/**\n * WizardUI — abstraction layer for all user-facing operations.\n *\n * Business logic calls `getUI()` instead of importing the store directly.\n * Implementations: InkUI (TUI), LoggingUI (CI).\n *\n * No prompt methods — the TUI screens own all user input.\n * Session-mutating methods trigger reactive screen resolution in the TUI.\n */\n\nexport enum TaskStatus {\n Pending = 'pending',\n InProgress = 'in_progress',\n Completed = 'completed',\n}\n\nexport interface SpinnerHandle {\n start(message?: string): void;\n stop(message?: string): void;\n message(msg?: string): void;\n}\n\nexport interface WizardUI {\n // ── Lifecycle messages ────────────────────────────────────────────\n intro(message: string): void;\n outro(message: string): void;\n cancel(message: string): void;\n\n // ── Logging ───────────────────────────────────────────────────────\n log: {\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n success(message: string): void;\n step(message: string): void;\n };\n\n note(message: string): void;\n pushStatus(message: string): void;\n\n // ── Spinner ───────────────────────────────────────────────────────\n spinner(): SpinnerHandle;\n\n // ── Session state (triggers reactive screen resolution in TUI) ────\n /** Signal that the main work (agent run) has started. */\n startRun(): void;\n\n /** Store OAuth/API credentials. Resolves past AuthScreen in TUI. */\n setCredentials(credentials: {\n accessToken: string;\n projectApiKey: string;\n host: string;\n projectId: number;\n }): void;\n\n /** Show service degradation (pushes outage overlay in TUI). */\n showServiceStatus(data: { description: string; statusPageUrl: string }): void;\n\n /** Warn that .claude/settings.json overrides blocking env vars (pushes blocking overlay in TUI). */\n showSettingsOverride(\n keys: string[],\n backupAndFix: () => boolean,\n ): Promise<void>;\n\n // ── Display state ──────────────────────────────────────────────────\n /** Set the detected framework label (e.g., \"Django with Wagtail CMS\") */\n setDetectedFramework(label: string): void;\n\n /** Register a callback to run when the TUI transitions onto the given screen. */\n onEnterScreen(screen: string, fn: () => void): void;\n\n setLoginUrl(url: string | null): void;\n\n // ── Todo tracking from SDK TodoWrite events ───────────────────────\n syncTodos(\n todos: Array<{ content: string; status: string; activeForm?: string }>,\n ): void;\n\n // ── Event plan from .posthog-events.json ────────────────────\n setEventPlan(events: Array<{ name: string; description: string }>): void;\n}\n"]}
1
+ {"version":3,"file":"wizard-ui.js","sourceRoot":"","sources":["../../../src/ui/wizard-ui.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAEH,IAAY,UAIX;AAJD,WAAY,UAAU;IACpB,iCAAmB,CAAA;IACnB,wCAA0B,CAAA;IAC1B,qCAAuB,CAAA;AACzB,CAAC,EAJW,UAAU,0BAAV,UAAU,QAIrB","sourcesContent":["/**\n * WizardUI — abstraction layer for all user-facing operations.\n *\n * Business logic calls `getUI()` instead of importing the store directly.\n * Implementations: InkUI (TUI), LoggingUI (CI).\n *\n * No prompt methods — the TUI screens own all user input.\n * Session-mutating methods trigger reactive screen resolution in the TUI.\n */\n\nexport enum TaskStatus {\n Pending = 'pending',\n InProgress = 'in_progress',\n Completed = 'completed',\n}\n\nexport interface SpinnerHandle {\n start(message?: string): void;\n stop(message?: string): void;\n message(msg?: string): void;\n}\n\nexport interface WizardUI {\n // ── Lifecycle messages ────────────────────────────────────────────\n intro(message: string): void;\n outro(message: string): void;\n cancel(message: string): void;\n\n // ── Logging ───────────────────────────────────────────────────────\n log: {\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n success(message: string): void;\n step(message: string): void;\n };\n\n note(message: string): void;\n pushStatus(message: string): void;\n\n // ── Spinner ───────────────────────────────────────────────────────\n spinner(): SpinnerHandle;\n\n // ── Session state (triggers reactive screen resolution in TUI) ────\n /** Signal that the main work (agent run) has started. */\n startRun(): void;\n\n /** Store OAuth/API credentials. Resolves past AuthScreen in TUI. */\n setCredentials(credentials: {\n accessToken: string;\n projectApiKey: string;\n host: string;\n projectId: number;\n }): void;\n\n /** Show service degradation (pushes outage overlay in TUI). */\n showServiceStatus(data: { description: string; statusPageUrl: string }): void;\n\n /** Warn that another process is blocking the OAuth port (pushes overlay in TUI). */\n showPortConflict(processInfo: {\n command: string;\n pid: string;\n user: string;\n }): Promise<void>;\n\n /** Warn that .claude/settings.json overrides blocking env vars (pushes blocking overlay in TUI). */\n showSettingsOverride(\n keys: string[],\n backupAndFix: () => boolean,\n ): Promise<void>;\n\n // ── Display state ──────────────────────────────────────────────────\n /** Set the detected framework label (e.g., \"Django with Wagtail CMS\") */\n setDetectedFramework(label: string): void;\n\n /** Register a callback to run when the TUI transitions onto the given screen. */\n onEnterScreen(screen: string, fn: () => void): void;\n\n setLoginUrl(url: string | null): void;\n\n // ── Todo tracking from SDK TodoWrite events ───────────────────────\n syncTodos(\n todos: Array<{ content: string; status: string; activeForm?: string }>,\n ): void;\n\n // ── Event plan from .posthog-events.json ────────────────────\n setEventPlan(events: Array<{ name: string; description: string }>): void;\n}\n"]}
@@ -1,7 +1,4 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.getLogFilePath = getLogFilePath;
7
4
  exports.configureLogFile = configureLogFile;
@@ -9,7 +6,6 @@ exports.initLogFile = initLogFile;
9
6
  exports.logToFile = logToFile;
10
7
  exports.debug = debug;
11
8
  exports.enableDebugLogs = enableDebugLogs;
12
- const chalk_1 = __importDefault(require("chalk"));
13
9
  const fs_1 = require("fs");
14
10
  const logging_1 = require("./logging");
15
11
  const ui_1 = require("../ui");
@@ -67,7 +63,7 @@ function debug(...args) {
67
63
  return;
68
64
  }
69
65
  const msg = args.map((a) => (0, logging_1.prepareMessage)(a)).join(' ');
70
- (0, ui_1.getUI)().log.info(chalk_1.default.dim(msg));
66
+ (0, ui_1.getUI)().log.info(msg);
71
67
  }
72
68
  function enableDebugLogs() {
73
69
  debugEnabled = true;
@@ -1 +1 @@
1
- {"version":3,"file":"debug.js","sourceRoot":"","sources":["../../../src/utils/debug.ts"],"names":[],"mappings":";;;;;AASA,wCAEC;AAMD,4CAMC;AAOD,kCAUC;AAOD,8BASC;AAED,sBAQC;AAED,0CAEC;AAtED,kDAA0B;AAC1B,2BAAoC;AACpC,uCAA2C;AAC3C,8BAA8B;AAE9B,IAAI,YAAY,GAAG,KAAK,CAAC;AACzB,IAAI,WAAW,GAAG,yBAAyB,CAAC;AAC5C,IAAI,UAAU,GAAG,IAAI,CAAC;AAEtB,SAAgB,cAAc;IAC5B,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,IAGhC;IACC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;QAAE,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC;IACrD,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;QAAE,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC;AAC5D,CAAC;AAED;;;;GAIG;AACH,SAAgB,WAAW;IACzB,IAAI,CAAC,UAAU;QAAE,OAAO;IACxB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,KAAK,GAAG,CAAC,MAAM,CAC5B,EAAE,CACH,yBAAyB,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC;QAC1E,IAAA,mBAAc,EAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,4CAA4C;IAC9C,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,SAAS,CAAC,GAAG,IAAe;IAC1C,IAAI,CAAC,UAAU;QAAE,OAAO;IACxB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,wBAAc,EAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzD,IAAA,mBAAc,EAAC,WAAW,EAAE,IAAI,SAAS,KAAK,GAAG,IAAI,CAAC,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;IACtE,CAAC;AACH,CAAC;AAED,SAAgB,KAAK,CAAC,GAAG,IAAe;IACtC,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,wBAAc,EAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEzD,IAAA,UAAK,GAAE,CAAC,GAAG,CAAC,IAAI,CAAC,eAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,SAAgB,eAAe;IAC7B,YAAY,GAAG,IAAI,CAAC;AACtB,CAAC","sourcesContent":["import chalk from 'chalk';\nimport { appendFileSync } from 'fs';\nimport { prepareMessage } from './logging';\nimport { getUI } from '../ui';\n\nlet debugEnabled = false;\nlet logFilePath = '/tmp/posthog-wizard.log';\nlet logEnabled = true;\n\nexport function getLogFilePath(): string {\n return logFilePath;\n}\n\n/**\n * Configure the log file path and enable/disable state.\n * Call before initLogFile() to override defaults.\n */\nexport function configureLogFile(opts: {\n path?: string;\n enabled?: boolean;\n}): void {\n if (opts.path !== undefined) logFilePath = opts.path;\n if (opts.enabled !== undefined) logEnabled = opts.enabled;\n}\n\n/**\n * Initialize the log file with a run header.\n * Call this at the start of each wizard run.\n * Fails silently to avoid crashing the wizard.\n */\nexport function initLogFile() {\n if (!logEnabled) return;\n try {\n const header = `\\n${'='.repeat(\n 60,\n )}\\nPostHog Wizard Run: ${new Date().toISOString()}\\n${'='.repeat(60)}\\n`;\n appendFileSync(logFilePath, header);\n } catch {\n // Silently ignore - logging is non-critical\n }\n}\n\n/**\n * Log a message to the log file.\n * Always writes regardless of debug flag (when logging is enabled).\n * Fails silently to avoid masking errors in catch blocks.\n */\nexport function logToFile(...args: unknown[]) {\n if (!logEnabled) return;\n try {\n const timestamp = new Date().toISOString();\n const msg = args.map((a) => prepareMessage(a)).join(' ');\n appendFileSync(logFilePath, `[${timestamp}] ${msg}\\n`);\n } catch {\n // Silently ignore logging failures to avoid masking original errors\n }\n}\n\nexport function debug(...args: unknown[]) {\n if (!debugEnabled) {\n return;\n }\n\n const msg = args.map((a) => prepareMessage(a)).join(' ');\n\n getUI().log.info(chalk.dim(msg));\n}\n\nexport function enableDebugLogs() {\n debugEnabled = true;\n}\n"]}
1
+ {"version":3,"file":"debug.js","sourceRoot":"","sources":["../../../src/utils/debug.ts"],"names":[],"mappings":";;AAQA,wCAEC;AAMD,4CAMC;AAOD,kCAUC;AAOD,8BASC;AAED,sBAQC;AAED,0CAEC;AArED,2BAAoC;AACpC,uCAA2C;AAC3C,8BAA8B;AAE9B,IAAI,YAAY,GAAG,KAAK,CAAC;AACzB,IAAI,WAAW,GAAG,yBAAyB,CAAC;AAC5C,IAAI,UAAU,GAAG,IAAI,CAAC;AAEtB,SAAgB,cAAc;IAC5B,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,IAGhC;IACC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;QAAE,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC;IACrD,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;QAAE,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC;AAC5D,CAAC;AAED;;;;GAIG;AACH,SAAgB,WAAW;IACzB,IAAI,CAAC,UAAU;QAAE,OAAO;IACxB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,KAAK,GAAG,CAAC,MAAM,CAC5B,EAAE,CACH,yBAAyB,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC;QAC1E,IAAA,mBAAc,EAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,4CAA4C;IAC9C,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,SAAS,CAAC,GAAG,IAAe;IAC1C,IAAI,CAAC,UAAU;QAAE,OAAO;IACxB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,wBAAc,EAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzD,IAAA,mBAAc,EAAC,WAAW,EAAE,IAAI,SAAS,KAAK,GAAG,IAAI,CAAC,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;IACtE,CAAC;AACH,CAAC;AAED,SAAgB,KAAK,CAAC,GAAG,IAAe;IACtC,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,wBAAc,EAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEzD,IAAA,UAAK,GAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACxB,CAAC;AAED,SAAgB,eAAe;IAC7B,YAAY,GAAG,IAAI,CAAC;AACtB,CAAC","sourcesContent":["import { appendFileSync } from 'fs';\nimport { prepareMessage } from './logging';\nimport { getUI } from '../ui';\n\nlet debugEnabled = false;\nlet logFilePath = '/tmp/posthog-wizard.log';\nlet logEnabled = true;\n\nexport function getLogFilePath(): string {\n return logFilePath;\n}\n\n/**\n * Configure the log file path and enable/disable state.\n * Call before initLogFile() to override defaults.\n */\nexport function configureLogFile(opts: {\n path?: string;\n enabled?: boolean;\n}): void {\n if (opts.path !== undefined) logFilePath = opts.path;\n if (opts.enabled !== undefined) logEnabled = opts.enabled;\n}\n\n/**\n * Initialize the log file with a run header.\n * Call this at the start of each wizard run.\n * Fails silently to avoid crashing the wizard.\n */\nexport function initLogFile() {\n if (!logEnabled) return;\n try {\n const header = `\\n${'='.repeat(\n 60,\n )}\\nPostHog Wizard Run: ${new Date().toISOString()}\\n${'='.repeat(60)}\\n`;\n appendFileSync(logFilePath, header);\n } catch {\n // Silently ignore - logging is non-critical\n }\n}\n\n/**\n * Log a message to the log file.\n * Always writes regardless of debug flag (when logging is enabled).\n * Fails silently to avoid masking errors in catch blocks.\n */\nexport function logToFile(...args: unknown[]) {\n if (!logEnabled) return;\n try {\n const timestamp = new Date().toISOString();\n const msg = args.map((a) => prepareMessage(a)).join(' ');\n appendFileSync(logFilePath, `[${timestamp}] ${msg}\\n`);\n } catch {\n // Silently ignore logging failures to avoid masking original errors\n }\n}\n\nexport function debug(...args: unknown[]) {\n if (!debugEnabled) {\n return;\n }\n\n const msg = args.map((a) => prepareMessage(a)).join(' ');\n\n getUI().log.info(msg);\n}\n\nexport function enableDebugLogs() {\n debugEnabled = true;\n}\n"]}
@@ -1,7 +1,4 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.prepareMessage = prepareMessage;
7
4
  exports.l = l;
@@ -12,7 +9,6 @@ exports.dim = dim;
12
9
  exports.yellow = yellow;
13
10
  exports.cyan = cyan;
14
11
  exports.debug = debug;
15
- const chalk_1 = __importDefault(require("chalk"));
16
12
  function prepareMessage(msg) {
17
13
  if (typeof msg === 'string') {
18
14
  return msg;
@@ -30,21 +26,22 @@ function nl() {
30
26
  return l('');
31
27
  }
32
28
  function green(msg) {
33
- return l(chalk_1.default.green(prepareMessage(msg)));
29
+ return l(prepareMessage(msg));
34
30
  }
35
31
  function red(msg) {
36
- return l(chalk_1.default.red(prepareMessage(msg)));
32
+ return l(prepareMessage(msg));
37
33
  }
38
34
  function dim(msg) {
39
- return l(chalk_1.default.dim(prepareMessage(msg)));
35
+ return l(prepareMessage(msg));
40
36
  }
41
37
  function yellow(msg) {
42
- return l(chalk_1.default.yellow(prepareMessage(msg)));
38
+ return l(prepareMessage(msg));
43
39
  }
44
40
  function cyan(msg) {
45
- return l(chalk_1.default.cyan(prepareMessage(msg)));
41
+ return l(prepareMessage(msg));
46
42
  }
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
44
  function debug(msg) {
48
- return l(chalk_1.default.italic.yellow(prepareMessage(msg)));
45
+ return l(prepareMessage(msg));
49
46
  }
50
47
  //# sourceMappingURL=logging.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logging.js","sourceRoot":"","sources":["../../../src/utils/logging.ts"],"names":[],"mappings":";;;;;AAEA,wCAQC;AAED,cAGC;AAED,gBAEC;AAED,sBAEC;AAED,kBAEC;AAED,kBAEC;AAED,wBAEC;AAED,oBAEC;AAED,sBAEC;AA3CD,kDAA0B;AAE1B,SAAgB,cAAc,CAAC,GAAY;IACzC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,OAAO,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;IAC9B,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,SAAgB,CAAC,CAAC,GAAW;IAC3B,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACnB,CAAC;AAED,SAAgB,EAAE;IAChB,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;AACf,CAAC;AAED,SAAgB,KAAK,CAAC,GAAW;IAC/B,OAAO,CAAC,CAAC,eAAK,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,SAAgB,GAAG,CAAC,GAAW;IAC7B,OAAO,CAAC,CAAC,eAAK,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,SAAgB,GAAG,CAAC,GAAW;IAC7B,OAAO,CAAC,CAAC,eAAK,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,SAAgB,MAAM,CAAC,GAAW;IAChC,OAAO,CAAC,CAAC,eAAK,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,SAAgB,IAAI,CAAC,GAAW;IAC9B,OAAO,CAAC,CAAC,eAAK,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,SAAgB,KAAK,CAAC,GAAQ;IAC5B,OAAO,CAAC,CAAC,eAAK,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC","sourcesContent":["import Chalk from 'chalk';\n\nexport function prepareMessage(msg: unknown): string {\n if (typeof msg === 'string') {\n return msg;\n }\n if (msg instanceof Error) {\n return `${msg.stack || ''}`;\n }\n return JSON.stringify(msg, null, '\\t');\n}\n\nexport function l(msg: string): void {\n // eslint-disable-next-line no-console\n console.log(msg);\n}\n\nexport function nl(): void {\n return l('');\n}\n\nexport function green(msg: string): void {\n return l(Chalk.green(prepareMessage(msg)));\n}\n\nexport function red(msg: string): void {\n return l(Chalk.red(prepareMessage(msg)));\n}\n\nexport function dim(msg: string): void {\n return l(Chalk.dim(prepareMessage(msg)));\n}\n\nexport function yellow(msg: string): void {\n return l(Chalk.yellow(prepareMessage(msg)));\n}\n\nexport function cyan(msg: string): void {\n return l(Chalk.cyan(prepareMessage(msg)));\n}\n\nexport function debug(msg: any): void {\n return l(Chalk.italic.yellow(prepareMessage(msg)));\n}\n"]}
1
+ {"version":3,"file":"logging.js","sourceRoot":"","sources":["../../../src/utils/logging.ts"],"names":[],"mappings":";;AAAA,wCAQC;AAED,cAGC;AAED,gBAEC;AAED,sBAEC;AAED,kBAEC;AAED,kBAEC;AAED,wBAEC;AAED,oBAEC;AAGD,sBAEC;AA1CD,SAAgB,cAAc,CAAC,GAAY;IACzC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,OAAO,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;IAC9B,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,SAAgB,CAAC,CAAC,GAAW;IAC3B,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACnB,CAAC;AAED,SAAgB,EAAE;IAChB,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;AACf,CAAC;AAED,SAAgB,KAAK,CAAC,GAAW;IAC/B,OAAO,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,SAAgB,GAAG,CAAC,GAAW;IAC7B,OAAO,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,SAAgB,GAAG,CAAC,GAAW;IAC7B,OAAO,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,SAAgB,MAAM,CAAC,GAAW;IAChC,OAAO,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,SAAgB,IAAI,CAAC,GAAW;IAC9B,OAAO,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,8DAA8D;AAC9D,SAAgB,KAAK,CAAC,GAAQ;IAC5B,OAAO,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;AAChC,CAAC","sourcesContent":["export function prepareMessage(msg: unknown): string {\n if (typeof msg === 'string') {\n return msg;\n }\n if (msg instanceof Error) {\n return `${msg.stack || ''}`;\n }\n return JSON.stringify(msg, null, '\\t');\n}\n\nexport function l(msg: string): void {\n // eslint-disable-next-line no-console\n console.log(msg);\n}\n\nexport function nl(): void {\n return l('');\n}\n\nexport function green(msg: string): void {\n return l(prepareMessage(msg));\n}\n\nexport function red(msg: string): void {\n return l(prepareMessage(msg));\n}\n\nexport function dim(msg: string): void {\n return l(prepareMessage(msg));\n}\n\nexport function yellow(msg: string): void {\n return l(prepareMessage(msg));\n}\n\nexport function cyan(msg: string): void {\n return l(prepareMessage(msg));\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function debug(msg: any): void {\n return l(prepareMessage(msg));\n}\n"]}
@@ -39,8 +39,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.performOAuthFlow = performOAuthFlow;
40
40
  const crypto = __importStar(require("node:crypto"));
41
41
  const http = __importStar(require("node:http"));
42
+ const node_child_process_1 = require("node:child_process");
42
43
  const axios_1 = __importDefault(require("axios"));
43
- const chalk_1 = __importDefault(require("chalk"));
44
+ const debug_1 = require("./debug");
44
45
  const opn_1 = __importDefault(require("opn"));
45
46
  const zod_1 = require("zod");
46
47
  const ui_1 = require("../ui");
@@ -173,6 +174,43 @@ async function startCallbackServer(authUrl, signupUrl) {
173
174
  server.on('error', reject);
174
175
  });
175
176
  }
177
+ function getPortProcessInfo() {
178
+ try {
179
+ const output = (0, node_child_process_1.execSync)(`lsof -i :${constants_1.OAUTH_PORT} -sTCP:LISTEN 2>/dev/null`, {
180
+ encoding: 'utf-8',
181
+ timeout: 3000,
182
+ }).trim();
183
+ const lines = output.split('\n');
184
+ // First line is header, second is the process
185
+ if (lines.length < 2)
186
+ return { command: 'unknown', pid: 'unknown', user: 'unknown' };
187
+ const fields = lines[1].split(/\s+/);
188
+ // lsof columns: COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
189
+ const command = fields[0] ?? 'unknown';
190
+ const pid = fields[1] ?? 'unknown';
191
+ const user = fields[2] ?? 'unknown';
192
+ return { command, pid, user };
193
+ }
194
+ catch {
195
+ return { command: 'unknown', pid: 'unknown', user: 'unknown' };
196
+ }
197
+ }
198
+ async function startCallbackServerWithRetry(authUrl, signupUrl) {
199
+ try {
200
+ return await startCallbackServer(authUrl, signupUrl);
201
+ }
202
+ catch (e) {
203
+ const isPortInUse = e instanceof Error &&
204
+ 'code' in e &&
205
+ e.code === 'EADDRINUSE';
206
+ if (!isPortInUse)
207
+ throw e;
208
+ const processInfo = getPortProcessInfo();
209
+ await (0, ui_1.getUI)().showPortConflict(processInfo);
210
+ // User killed the process — retry once
211
+ return startCallbackServer(authUrl, signupUrl);
212
+ }
213
+ }
176
214
  async function exchangeCodeForToken(code, codeVerifier) {
177
215
  const clientId = constants_1.IS_DEV ? constants_1.POSTHOG_DEV_CLIENT_ID : constants_1.POSTHOG_PROXY_CLIENT_ID;
178
216
  const response = await axios_1.default.post(`${constants_1.POSTHOG_OAUTH_URL}/oauth/token`, {
@@ -205,7 +243,9 @@ async function performOAuthFlow(config) {
205
243
  const localSignupUrl = `http://localhost:${constants_1.OAUTH_PORT}/authorize?signup=true`;
206
244
  const localLoginUrl = `http://localhost:${constants_1.OAUTH_PORT}/authorize`;
207
245
  const urlToOpen = config.signup ? localSignupUrl : localLoginUrl;
208
- const { server, waitForCallback } = await startCallbackServer(authUrl.toString(), signupUrl.toString());
246
+ (0, debug_1.logToFile)('[oauth] starting callback server');
247
+ const { server, waitForCallback } = await startCallbackServerWithRetry(authUrl.toString(), signupUrl.toString());
248
+ (0, debug_1.logToFile)('[oauth] callback server ready, showing login URL');
209
249
  (0, ui_1.getUI)().setLoginUrl(urlToOpen);
210
250
  if (process.env.NODE_ENV !== 'test') {
211
251
  (0, opn_1.default)(urlToOpen, { wait: false }).catch(() => {
@@ -233,10 +273,10 @@ async function performOAuthFlow(config) {
233
273
  (0, ui_1.getUI)().log.error('Authorization timed out. Please try again.');
234
274
  }
235
275
  else if (error.message.includes('access_denied')) {
236
- (0, ui_1.getUI)().log.info(`${chalk_1.default.yellow('Authorization was cancelled.')}\n\nYou denied access to PostHog. To use the wizard, you need to authorize access to your PostHog account.\n\n${chalk_1.default.dim('You can try again by re-running the wizard.')}`);
276
+ (0, ui_1.getUI)().log.info(`Authorization was cancelled.\n\nYou denied access to PostHog. To use the wizard, you need to authorize access to your PostHog account.\n\nYou can try again by re-running the wizard.`);
237
277
  }
238
278
  else {
239
- (0, ui_1.getUI)().log.error(`${chalk_1.default.red('Authorization failed:')}\n\n${error.message}\n\n${chalk_1.default.dim(`If you think this is a bug in the PostHog wizard, please create an issue:\n${constants_1.ISSUES_URL}`)}`);
279
+ (0, ui_1.getUI)().log.error(`Authorization failed:\n\n${error.message}\n\nIf you think this is a bug in the PostHog wizard, please create an issue:\n${constants_1.ISSUES_URL}`);
240
280
  }
241
281
  analytics_1.analytics.captureException(error, {
242
282
  step: 'oauth_flow',