-
Notifications
You must be signed in to change notification settings - Fork 51
Expand file tree
/
Copy pathbin.ts
More file actions
120 lines (112 loc) · 4.8 KB
/
Copy pathbin.ts
File metadata and controls
120 lines (112 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env node
import { satisfies } from 'semver';
import { Agent, setGlobalDispatcher } from 'undici';
import { ErrorCodes } from './src/lib/errors/codes.js';
import { emitWizardError } from './src/lib/errors/emit.js';
// Keep in sync with `engines.node` in package.json. npx does not enforce
// engines, so this preflight is the only thing standing between an old Node
// runtime and a cryptic dependency crash (e.g. undici's markAsUncloneable
// TypeError on Node < 22.10).
const NODE_VERSION_RANGE = '>=22.22.0';
/*
* TODO(#1198): remove when fetch over HTTP/2 is safe on Node 26. Remove when all
* of these are true:
* - nodejs/node no longer creates an orphan ClientHttp2Stream when a client
* session gets HEADERS for a stream id it already reset. Repro: abort a fetch
* before its response headers, then idle 4s on Node 26. Fixed when the
* process survives.
* - modelcontextprotocol/typescript-sdk#2526 is closed.
* - pi-coding-agent's CLI drops `allowH2: false` from its http-dispatcher.
* Same workaround as pi's CLI and typescript-sdk#2526: HTTP/1.1 only.
*/
setGlobalDispatcher(new Agent({ allowH2: false }));
// Have to run this above the other imports because they are importing clack that
// has the problematic imports.
if (!satisfies(process.version, NODE_VERSION_RANGE)) {
// eslint-disable-next-line no-console
console.log(
[
`The PostHog wizard needs a newer version of Node.js to run.`,
``,
` You have: ${process.version}`,
` You need: v${NODE_VERSION_RANGE.replace('>=', '')} or later`,
``,
`To update Node.js:`,
``,
` Download the latest version from https://nodejs.org/en/download`,
` Or, if you use nvm, run: nvm install 22 && nvm use 22`,
``,
`Then run the wizard again. Stuck? Email wizard@posthog.com and we'll help.`,
].join('\n'),
);
emitWizardError({
code: ErrorCodes.CliNodeVersion,
message: `Node ${process.version} is below the required range ${NODE_VERSION_RANGE}`,
});
process.exit(1);
}
// Test mock server — only loaded when NODE_ENV is 'test'.
// In production builds, tsdown replaces process.env.NODE_ENV with 'production',
// making this block dead code.
if (process.env.NODE_ENV === 'test') {
void (async () => {
try {
const { server } = await import('./e2e-tests/mocks/server.js');
server.listen({
onUnhandledRequest: 'bypass',
});
} catch (error) {
// Mock server import failed - this can happen during non-E2E tests
}
})();
}
import { Wizard } from './src/wizard';
import { basicIntegrationCommand } from './src/commands/basic-integration';
import { mcpCommand } from './src/commands/mcp';
import { mcpAnalyticsCommand } from './src/commands/mcp-analytics';
import { replayVisionCommand } from './src/commands/replay-vision';
import { aiObservabilityCommand } from './src/commands/ai-observability';
import { metricsCommand } from './src/commands/metrics';
import { auditCommand } from './src/commands/audit';
import { doctorCommand } from './src/commands/doctor';
import { migrateCommand } from './src/commands/migrate';
import { revenueCommand } from './src/commands/revenue';
import { warehouseCommand } from './src/commands/warehouse';
import { selfDrivingCommand } from './src/commands/self-driving';
import { slackCommand } from './src/commands/slack';
import { uploadSourcemapsCommand } from './src/commands/upload-sourcemaps';
import { errorTrackingCommand } from './src/commands/error-tracking';
import { skillCommand } from './src/commands/skill';
import { cliCommand } from './src/commands/cli';
import { recoverOrphanedSettingsBackups } from './src/lib/agent/claude-settings';
// Heal any .claude/settings backup a previous interrupted run left orphaned,
// before anything else reads Claude settings — conflict detection, OAuth, and
// the agent all need to see the user's real settings file. The install dir is
// read directly from argv/env because yargs hasn't parsed yet.
recoverOrphanedSettingsBackups(resolveInstallDir());
function resolveInstallDir(): string {
const args = process.argv.slice(2);
const flagIndex = args.indexOf('--install-dir');
if (flagIndex !== -1 && args[flagIndex + 1]) return args[flagIndex + 1];
const inline = args.find((a) => a.startsWith('--install-dir='));
if (inline) return inline.slice('--install-dir='.length);
return process.env.POSTHOG_WIZARD_INSTALL_DIR ?? process.cwd();
}
Wizard.use(basicIntegrationCommand)
.use(mcpCommand)
.use(mcpAnalyticsCommand)
.use(replayVisionCommand)
.use(aiObservabilityCommand)
.use(metricsCommand)
.use(cliCommand)
.use(auditCommand)
.use(doctorCommand)
.use(migrateCommand)
.use(revenueCommand)
.use(warehouseCommand)
.use(selfDrivingCommand)
.use(slackCommand)
.use(uploadSourcemapsCommand)
.use(errorTrackingCommand)
.use(skillCommand)
.init();