Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/install-flow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ describe('hwip install', () => {
expect(logs.join('\n')).toContain('Done! Restart your agents.');
});

it('points a new user at the phone app with campaign links, after the closing line', async () => {
expect(await install({ key: 'ak_1' })).toBe(0);
const out = logs.join('\n');
expect(out).toContain(' Get the app: https://apps.apple.com/app/id6818053606?ct=cli-install\n');
expect(out).toContain(' Android: https://play.google.com/store/apps/details?id=app.hwip&referrer=utm_source%3Dcli-install\n');
expect(out.indexOf('Done! Restart your agents.')).toBeLessThan(out.indexOf('Get the app:'));
expect(out.indexOf('Get the app:')).toBeLessThan(out.indexOf('Notifications now fire'));
});

// C107: a config.json that is not JSON used to load as {}; the install then replaced it with the new key alone.
it('leaves a config.json it cannot read as JSON alone, and says so before asking anything', async () => {
const { mkdirSync, writeFileSync } = await import('node:fs');
Expand Down
7 changes: 7 additions & 0 deletions src/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ export const closingLine = (failed: number): string => {
return `Done, but ${steps} you: see the lines marked "-" above. Then restart your agents.`;
};

/** Where the install's last screen sends a new user for the phone app. `ct`/`utm_source` name this surface. */
export const APP_STORE_URL = 'https://apps.apple.com/app/id6818053606?ct=cli-install';
export const PLAY_STORE_URL = 'https://play.google.com/store/apps/details?id=app.hwip&referrer=utm_source%3Dcli-install';

/** An edit that would lose a comment of the user's names the file, like every other refusal. */
const namingFile = <T>(filePath: string, edit: () => T): T => {
try {
Expand Down Expand Up @@ -881,6 +885,9 @@ export const handleInstall = async (args: Record<string, string | boolean>): Pro

console.log(`\n ${closingLine(failedSteps)}\n`);

console.log(` Get the app: ${APP_STORE_URL}`);
console.log(` Android: ${PLAY_STORE_URL}\n`);

// The single most-reported surprise: pushes are not scoped to `hwip cc`.
// Hooks fire for every session of every configured agent, so say it here —
// at the moment the hooks get installed — together with the volume dials.
Expand Down
Loading