memoir-cli 3.2.2 → 3.3.1
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.
- package/.github/ISSUE_TEMPLATE/bug_report.md +26 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +16 -0
- package/CONTRIBUTING.md +47 -0
- package/LICENSE +21 -0
- package/README.md +27 -3
- package/bin/memoir.js +69 -17
- package/package.json +1 -1
- package/server.json +2 -2
- package/src/cloud/auth.js +81 -2
- package/src/cloud/constants.js +2 -2
- package/src/cloud/storage.js +24 -4
- package/src/commands/init.js +79 -50
- package/src/commands/login.js +108 -28
- package/src/commands/upgrade.js +47 -25
- package/GAMEPLAN.md +0 -235
- package/LAUNCH_POSTS.md +0 -247
- package/MARKETING.md +0 -143
- package/POSTS-READY-TO-GO.md +0 -215
- package/VISION.md +0 -722
- package/landing-page-v2.html +0 -690
- package/mcp-publisher +0 -0
package/src/commands/login.js
CHANGED
|
@@ -2,9 +2,9 @@ import chalk from 'chalk';
|
|
|
2
2
|
import boxen from 'boxen';
|
|
3
3
|
import gradient from 'gradient-string';
|
|
4
4
|
import inquirer from 'inquirer';
|
|
5
|
-
import { signIn, signUp, saveSession, getSession, logout, getSubscription } from '../cloud/auth.js';
|
|
5
|
+
import { signIn, signUp, saveSession, getSession, logout, getSubscription, resetPassword, deleteAccount } from '../cloud/auth.js';
|
|
6
6
|
|
|
7
|
-
export async function loginCommand() {
|
|
7
|
+
export async function loginCommand(options = {}) {
|
|
8
8
|
// Check if already logged in
|
|
9
9
|
const existing = await getSession();
|
|
10
10
|
if (existing) {
|
|
@@ -18,32 +18,44 @@ export async function loginCommand() {
|
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
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
|
-
|
|
21
|
+
let action, email, password;
|
|
22
|
+
|
|
23
|
+
// Support non-interactive login via flags
|
|
24
|
+
if (options.email && options.password) {
|
|
25
|
+
action = options.signup ? 'signup' : 'signin';
|
|
26
|
+
email = options.email;
|
|
27
|
+
password = options.password;
|
|
28
|
+
} else {
|
|
29
|
+
console.log();
|
|
30
|
+
|
|
31
|
+
const actionAnswer = await inquirer.prompt([{
|
|
32
|
+
type: 'list',
|
|
33
|
+
name: 'action',
|
|
34
|
+
message: 'Sign in or create account?',
|
|
35
|
+
choices: [
|
|
36
|
+
{ name: 'Sign in (existing account)', value: 'signin' },
|
|
37
|
+
{ name: 'Create account', value: 'signup' },
|
|
38
|
+
],
|
|
39
|
+
}]);
|
|
40
|
+
action = actionAnswer.action;
|
|
41
|
+
|
|
42
|
+
const emailAnswer = await inquirer.prompt([{
|
|
43
|
+
type: 'input',
|
|
44
|
+
name: 'email',
|
|
45
|
+
message: 'Email:',
|
|
46
|
+
validate: v => v.includes('@') ? true : 'Enter a valid email',
|
|
47
|
+
}]);
|
|
48
|
+
email = emailAnswer.email;
|
|
49
|
+
|
|
50
|
+
const passwordAnswer = await inquirer.prompt([{
|
|
51
|
+
type: 'password',
|
|
52
|
+
name: 'password',
|
|
53
|
+
message: 'Password:',
|
|
54
|
+
mask: '*',
|
|
55
|
+
validate: v => v.length >= 6 ? true : 'Password must be at least 6 characters',
|
|
56
|
+
}]);
|
|
57
|
+
password = passwordAnswer.password;
|
|
58
|
+
}
|
|
47
59
|
|
|
48
60
|
try {
|
|
49
61
|
let session;
|
|
@@ -84,6 +96,34 @@ export async function loginCommand() {
|
|
|
84
96
|
}
|
|
85
97
|
}
|
|
86
98
|
|
|
99
|
+
export async function forgotPasswordCommand(options = {}) {
|
|
100
|
+
let email = options.email;
|
|
101
|
+
|
|
102
|
+
if (!email) {
|
|
103
|
+
const emailAnswer = await inquirer.prompt([{
|
|
104
|
+
type: 'input',
|
|
105
|
+
name: 'email',
|
|
106
|
+
message: 'Email:',
|
|
107
|
+
validate: v => v.includes('@') ? true : 'Enter a valid email',
|
|
108
|
+
}]);
|
|
109
|
+
email = emailAnswer.email;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
await resetPassword(email);
|
|
114
|
+
console.log('\n' + boxen(
|
|
115
|
+
chalk.green('✔ Password reset email sent!') + '\n\n' +
|
|
116
|
+
chalk.white('Check ') + chalk.cyan(email) + chalk.white(' for a reset link.'),
|
|
117
|
+
{ padding: 1, borderStyle: 'round', borderColor: 'green', dimBorder: true }
|
|
118
|
+
) + '\n');
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.log('\n' + boxen(
|
|
121
|
+
chalk.red('✖ ' + error.message),
|
|
122
|
+
{ padding: 1, borderStyle: 'round', borderColor: 'red' }
|
|
123
|
+
) + '\n');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
87
127
|
export async function logoutCommand() {
|
|
88
128
|
await logout();
|
|
89
129
|
console.log('\n' + boxen(
|
|
@@ -91,3 +131,43 @@ export async function logoutCommand() {
|
|
|
91
131
|
{ padding: 1, borderStyle: 'round', borderColor: 'green', dimBorder: true }
|
|
92
132
|
) + '\n');
|
|
93
133
|
}
|
|
134
|
+
|
|
135
|
+
export async function deleteAccountCommand(options = {}) {
|
|
136
|
+
const session = await getSession();
|
|
137
|
+
if (!session) {
|
|
138
|
+
console.log('\n' + boxen(
|
|
139
|
+
chalk.red('✖ Not logged in. Run ') + chalk.cyan('memoir login') + chalk.red(' first.'),
|
|
140
|
+
{ padding: 1, borderStyle: 'round', borderColor: 'red' }
|
|
141
|
+
) + '\n');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!options.confirm) {
|
|
146
|
+
const answer = await inquirer.prompt([{
|
|
147
|
+
type: 'input',
|
|
148
|
+
name: 'confirmation',
|
|
149
|
+
message: 'Type DELETE to confirm account deletion:',
|
|
150
|
+
}]);
|
|
151
|
+
|
|
152
|
+
if (answer.confirmation !== 'DELETE') {
|
|
153
|
+
console.log('\n' + chalk.gray(' Account deletion cancelled.') + '\n');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
await deleteAccount(session);
|
|
160
|
+
|
|
161
|
+
console.log('\n' + boxen(
|
|
162
|
+
gradient.pastel(' memoir cloud ') + '\n\n' +
|
|
163
|
+
chalk.green('✔ Account deleted.') + '\n' +
|
|
164
|
+
chalk.gray('All backups, shared links, and data have been removed.'),
|
|
165
|
+
{ padding: 1, borderStyle: 'round', borderColor: 'green', dimBorder: true }
|
|
166
|
+
) + '\n');
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.log('\n' + boxen(
|
|
169
|
+
chalk.red('✖ ' + error.message),
|
|
170
|
+
{ padding: 1, borderStyle: 'round', borderColor: 'red' }
|
|
171
|
+
) + '\n');
|
|
172
|
+
}
|
|
173
|
+
}
|
package/src/commands/upgrade.js
CHANGED
|
@@ -1,7 +1,30 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import boxen from 'boxen';
|
|
3
3
|
import gradient from 'gradient-string';
|
|
4
|
-
import
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import { getSession, getSubscription, supaFetch } from '../cloud/auth.js';
|
|
6
|
+
import { SUPABASE_URL } from '../cloud/constants.js';
|
|
7
|
+
|
|
8
|
+
async function createCheckoutSession(session) {
|
|
9
|
+
const res = await fetch(`${SUPABASE_URL}/functions/v1/stripe-checkout`, {
|
|
10
|
+
method: 'POST',
|
|
11
|
+
headers: {
|
|
12
|
+
'Authorization': `Bearer ${session.access_token}`,
|
|
13
|
+
'Content-Type': 'application/json',
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
const data = await res.json();
|
|
17
|
+
if (!res.ok) throw new Error(data.error || 'Failed to create checkout session');
|
|
18
|
+
return data.url;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function openUrl(url) {
|
|
22
|
+
const { exec } = require('child_process');
|
|
23
|
+
const platform = process.platform;
|
|
24
|
+
if (platform === 'darwin') exec(`open "${url}"`);
|
|
25
|
+
else if (platform === 'win32') exec(`start "" "${url}"`);
|
|
26
|
+
else exec(`xdg-open "${url}"`);
|
|
27
|
+
}
|
|
5
28
|
|
|
6
29
|
export async function upgradeCommand() {
|
|
7
30
|
const session = await getSession();
|
|
@@ -23,7 +46,6 @@ export async function upgradeCommand() {
|
|
|
23
46
|
const col2 = 22;
|
|
24
47
|
|
|
25
48
|
const pad = (str, width) => {
|
|
26
|
-
// Strip ANSI for length calculation
|
|
27
49
|
const stripped = str.replace(/\u001b\[[0-9;]*m/g, '');
|
|
28
50
|
const diff = width - stripped.length;
|
|
29
51
|
return diff > 0 ? str + ' '.repeat(diff) : str;
|
|
@@ -75,32 +97,32 @@ export async function upgradeCommand() {
|
|
|
75
97
|
{ padding: 1, borderStyle: 'round', borderColor: 'cyan', dimBorder: true }
|
|
76
98
|
));
|
|
77
99
|
|
|
78
|
-
// If free and logged in, open
|
|
100
|
+
// If free and logged in, open Stripe checkout
|
|
79
101
|
if (session && currentPlan === 'free') {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const { exec } = await import('child_process');
|
|
83
|
-
const url = 'https://memoir.sh/pricing';
|
|
84
|
-
|
|
85
|
-
const platform = process.platform;
|
|
86
|
-
let cmd;
|
|
87
|
-
if (platform === 'darwin') {
|
|
88
|
-
cmd = `open "${url}"`;
|
|
89
|
-
} else if (platform === 'win32') {
|
|
90
|
-
cmd = `start "${url}"`;
|
|
91
|
-
} else {
|
|
92
|
-
cmd = `xdg-open "${url}"`;
|
|
93
|
-
}
|
|
102
|
+
const spinner = ora(chalk.cyan(' Creating checkout session...')).start();
|
|
94
103
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
104
|
+
try {
|
|
105
|
+
const url = await createCheckoutSession(session);
|
|
106
|
+
spinner.succeed(chalk.green(' Opening Stripe checkout...'));
|
|
107
|
+
|
|
108
|
+
const { exec } = await import('child_process');
|
|
109
|
+
const platform = process.platform;
|
|
110
|
+
if (platform === 'darwin') exec(`open "${url}"`);
|
|
111
|
+
else if (platform === 'win32') exec(`start "" "${url}"`);
|
|
112
|
+
else exec(`xdg-open "${url}"`);
|
|
113
|
+
|
|
114
|
+
console.log(
|
|
115
|
+
'\n' + chalk.gray(' Complete payment in your browser.') + '\n' +
|
|
116
|
+
chalk.gray(' Your plan updates automatically — run ') +
|
|
117
|
+
chalk.cyan('memoir upgrade') +
|
|
118
|
+
chalk.gray(' again to verify.') + '\n'
|
|
119
|
+
);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
spinner.fail(chalk.red(' ' + err.message));
|
|
122
|
+
console.log(chalk.gray('\n Fallback: visit ') + chalk.cyan('https://memoir.sh/pricing') + '\n');
|
|
123
|
+
}
|
|
102
124
|
} else if (!session) {
|
|
103
|
-
console.log('\n' + chalk.gray('
|
|
125
|
+
console.log('\n' + chalk.gray(' Run ') + chalk.cyan('memoir login') + chalk.gray(' to create an account, then ') + chalk.cyan('memoir upgrade') + chalk.gray(' to subscribe.') + '\n');
|
|
104
126
|
} else {
|
|
105
127
|
console.log();
|
|
106
128
|
}
|
package/GAMEPLAN.md
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
# Memoir Business Game Plan
|
|
2
|
-
**Date:** March 25, 2026 | **Status:** Pre-revenue | **Author:** Boardroom consensus + CEO directive
|
|
3
|
-
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
## Current State
|
|
7
|
-
|
|
8
|
-
| Metric | Value |
|
|
9
|
-
|--------|-------|
|
|
10
|
-
| Version | 3.1.2 (npm) |
|
|
11
|
-
| Revenue | $0 |
|
|
12
|
-
| Users | ~50 npm downloads |
|
|
13
|
-
| AI Tools Supported | 11 (Claude, Gemini, Cursor, Copilot, Windsurf, Zed, Cline, Continue, Aider, Codex, ChatGPT) |
|
|
14
|
-
| Cloud Backend | Supabase (auth + storage + PostgreSQL) |
|
|
15
|
-
| Landing Page | memoir.sh (Vercel, 13 blog posts, no email capture) |
|
|
16
|
-
| Blog Posts | 13 SEO-targeted articles |
|
|
17
|
-
| Analytics | None (CLI or website) |
|
|
18
|
-
| Payment Processing | None |
|
|
19
|
-
| Team Features | None |
|
|
20
|
-
| Shareable Links | None |
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## What's Already Built (Don't Rebuild)
|
|
25
|
-
|
|
26
|
-
- **CLI core** — push, restore, snapshot, resume, migrate, diff, profiles, doctor
|
|
27
|
-
- **Cloud sync** — Supabase auth (email/password), gzipped bundles in Storage, PostgreSQL metadata
|
|
28
|
-
- **Free/Pro tiers** — enforced in code (Free: 3 backups, Pro: 50) — but no way to pay for Pro
|
|
29
|
-
- **Version history** — cloud backups versioned, restore from any version
|
|
30
|
-
- **E2E encryption** — AES-256-GCM, async scrypt (just fixed), client-side before upload
|
|
31
|
-
- **Workspace sync** — clones git repos, bundles non-git projects, applies uncommitted patches
|
|
32
|
-
- **Session handoff** — snapshot current session, resume on another machine
|
|
33
|
-
- **Landing page** — memoir.sh with animated terminal demo, tool marquee, FAQ, competitor comparison
|
|
34
|
-
- **13 SEO blog posts** — sync guides for each tool, comparisons, setup guides
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## The Plan: 4 Phases
|
|
39
|
-
|
|
40
|
-
### Phase 1: Monetization Foundation (Week 1-2)
|
|
41
|
-
> **Goal:** Accept money. Capture emails. Track usage.
|
|
42
|
-
|
|
43
|
-
| Task | Priority | Effort | Details |
|
|
44
|
-
|------|----------|--------|---------|
|
|
45
|
-
| Add Stripe integration | P0 | 1 day | Connect to Pro tier ($15/mo individual, already priced in competitor comparison) |
|
|
46
|
-
| `memoir upgrade` command | P0 | 0.5 day | Opens Stripe checkout from CLI, activates Pro |
|
|
47
|
-
| Add pricing page to memoir.sh | P0 | 0.5 day | Free vs Pro vs Teams (coming soon) |
|
|
48
|
-
| Add email capture / waitlist | P0 | 0.5 day | "Get notified for Teams" — collect emails on memoir.sh |
|
|
49
|
-
| Add PostHog analytics to CLI | P1 | 0.5 day | Anonymous: commands used, tool count, machine OS, cloud vs local |
|
|
50
|
-
| Add PostHog to memoir.sh | P1 | 0.5 day | Page views, blog reads, install clicks |
|
|
51
|
-
| `memoir doctor` completion | P2 | 0.5 day | Finish the stubbed diagnostics command |
|
|
52
|
-
|
|
53
|
-
**Phase 1 deliverable:** People can pay. We know who's using what.
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
### Phase 2: Viral Loop + Shareability (Week 3-4)
|
|
58
|
-
> **Goal:** Every user brings one more user.
|
|
59
|
-
|
|
60
|
-
| Task | Priority | Effort | Details |
|
|
61
|
-
|------|----------|--------|---------|
|
|
62
|
-
| Shareable context links | P0 | 2 days | `memoir share` → generates encrypted link (Supabase signed URL, 24hr expiry). Recipient runs `memoir restore --from <link>` |
|
|
63
|
-
| Share landing page | P0 | 0.5 day | When link is opened in browser (not CLI), show "Install memoir to restore this context" with one-click copy |
|
|
64
|
-
| Team invite flow | P1 | 1 day | `memoir team create`, `memoir team invite <email>` — shared backup namespace in Supabase |
|
|
65
|
-
| Onboarding context | P1 | 0.5 day | `memoir push --share` generates a restore link printed to terminal. Copy-paste to Slack |
|
|
66
|
-
| "Synced with memoir" badge | P2 | 0.5 day | Auto-append to CLAUDE.md / .cursorrules when synced — passive discovery |
|
|
67
|
-
|
|
68
|
-
**Phase 2 deliverable:** Sharing is the viral loop. Every shared link = a new install prompt.
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
### Phase 3: Teams Tier (Week 5-8)
|
|
73
|
-
> **Goal:** $29/seat/month revenue from dev teams.
|
|
74
|
-
|
|
75
|
-
| Task | Priority | Effort | Details |
|
|
76
|
-
|------|----------|--------|---------|
|
|
77
|
-
| Organizations in Supabase | P0 | 2 days | `organizations` table, `org_members` table, role-based (admin/member) |
|
|
78
|
-
| Shared team backups | P0 | 2 days | `memoir push --team` syncs to org namespace. All members can restore team context |
|
|
79
|
-
| Team dashboard (web) | P1 | 3 days | memoir.sh/dashboard — see team members, backup history, storage usage |
|
|
80
|
-
| Seat-based billing | P0 | 1 day | Stripe per-seat subscription, enforce in CLI |
|
|
81
|
-
| Context inheritance | P1 | 1 day | `memoir restore --from <teammate>` — pull specific teammate's context with permission |
|
|
82
|
-
| Audit log | P2 | 1 day | Who pushed, who restored, when — enterprise compliance checkbox |
|
|
83
|
-
| SSO (Google/GitHub) | P2 | 1 day | Enterprise teams expect OAuth, not email/password |
|
|
84
|
-
|
|
85
|
-
**Phase 3 deliverable:** Teams can buy seats, share context, see a dashboard.
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
### Phase 4: Enterprise + Moat (Week 9-12)
|
|
90
|
-
> **Goal:** First $5k MRR. Lock-in through history depth.
|
|
91
|
-
|
|
92
|
-
| Task | Priority | Effort | Details |
|
|
93
|
-
|------|----------|--------|---------|
|
|
94
|
-
| Context time-travel | P1 | 3 days | `memoir restore --version 5 --tool claude` — restore any tool to any point in history |
|
|
95
|
-
| Diff between versions | P1 | 1 day | `memoir diff v3 v7` — show what changed in AI context between versions |
|
|
96
|
-
| Context quality scoring | P2 | 2 days | Auto-tag backups: files changed, decisions made, session length. Surface "important" snapshots |
|
|
97
|
-
| Enterprise pricing page | P1 | 0.5 day | $99/seat/month with SLA, priority support, SSO, audit logs |
|
|
98
|
-
| SOC2 narrative | P2 | 1 day | Document E2E encryption, zero-knowledge architecture, audit trail for compliance conversations |
|
|
99
|
-
| API for integrations | P2 | 3 days | REST API: programmatic backup/restore for CI/CD pipelines, onboarding scripts |
|
|
100
|
-
|
|
101
|
-
**Phase 4 deliverable:** Enterprise-ready product with deep history moat.
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## Pricing Structure
|
|
106
|
-
|
|
107
|
-
| Tier | Price | Limits | Target |
|
|
108
|
-
|------|-------|--------|--------|
|
|
109
|
-
| **Free** | $0/forever | 3 cloud backups, local unlimited, 1 machine | Solo devs trying it out |
|
|
110
|
-
| **Pro** | $15/month | 50 cloud backups, unlimited machines, version history | Power users, multi-machine devs |
|
|
111
|
-
| **Teams** | $29/seat/month | Shared team context, dashboard, audit log, 200 backups/team | Dev teams (5-20 people) |
|
|
112
|
-
| **Enterprise** | $99/seat/month | SSO, SLA, API access, compliance docs, unlimited backups | Companies (20+) |
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## Positioning
|
|
117
|
-
|
|
118
|
-
| Audience | Message |
|
|
119
|
-
|----------|---------|
|
|
120
|
-
| Individual dev | "Never lose your AI context again" |
|
|
121
|
-
| Dev team lead | "Onboard devs in 60 seconds with full AI context" |
|
|
122
|
-
| Enterprise buyer | "SOC2-ready AI workflow continuity" |
|
|
123
|
-
| SEO / content | "Git for your AI setup" |
|
|
124
|
-
|
|
125
|
-
**One-liner:** memoir syncs your AI memory across every machine and every teammate.
|
|
126
|
-
|
|
127
|
-
**Anti-positioning (what we're NOT):** Not a dotfiles manager. Not VS Code Sync. Not a cloud IDE. We sync the AI layer — the conversations, decisions, and context that make your tools smart.
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## First 100 Users Plan
|
|
132
|
-
|
|
133
|
-
| Week | Action | Target |
|
|
134
|
-
|------|--------|--------|
|
|
135
|
-
| 1 | Ship Stripe + pricing page | Accept payments |
|
|
136
|
-
| 2 | Post on r/programming, r/neovim, r/cursor, Hacker News | 500 page views |
|
|
137
|
-
| 3 | Cold DM 50 developers who tweet about Claude/Cursor context loss | 10 installs |
|
|
138
|
-
| 4 | Ship shareable links, post demo video on X/Twitter | 20 shares |
|
|
139
|
-
| 5-6 | Reach out to 10 companies using Cursor (check their GitHub for .cursorrules) | 3 team pilots |
|
|
140
|
-
| 7-8 | Ship Teams tier, convert pilots to paid | First $290 MRR |
|
|
141
|
-
| 9-12 | Content marketing: "How Company X onboards devs in 60s" case study | 100 users, $1k+ MRR |
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## Supabase Schema Changes Needed
|
|
146
|
-
|
|
147
|
-
```sql
|
|
148
|
-
-- Organizations
|
|
149
|
-
CREATE TABLE organizations (
|
|
150
|
-
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
151
|
-
name TEXT NOT NULL,
|
|
152
|
-
slug TEXT UNIQUE NOT NULL,
|
|
153
|
-
owner_id UUID REFERENCES auth.users(id),
|
|
154
|
-
plan TEXT DEFAULT 'teams',
|
|
155
|
-
stripe_customer_id TEXT,
|
|
156
|
-
stripe_subscription_id TEXT,
|
|
157
|
-
created_at TIMESTAMPTZ DEFAULT now()
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
-- Org members
|
|
161
|
-
CREATE TABLE org_members (
|
|
162
|
-
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
163
|
-
org_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
|
164
|
-
user_id UUID REFERENCES auth.users(id),
|
|
165
|
-
role TEXT DEFAULT 'member' CHECK (role IN ('admin', 'member')),
|
|
166
|
-
invited_by UUID REFERENCES auth.users(id),
|
|
167
|
-
joined_at TIMESTAMPTZ DEFAULT now(),
|
|
168
|
-
UNIQUE(org_id, user_id)
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
-- Shared links
|
|
172
|
-
CREATE TABLE shared_links (
|
|
173
|
-
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
174
|
-
backup_id UUID REFERENCES backups(id),
|
|
175
|
-
created_by UUID REFERENCES auth.users(id),
|
|
176
|
-
token TEXT UNIQUE NOT NULL,
|
|
177
|
-
expires_at TIMESTAMPTZ NOT NULL,
|
|
178
|
-
max_uses INT DEFAULT 1,
|
|
179
|
-
use_count INT DEFAULT 0,
|
|
180
|
-
created_at TIMESTAMPTZ DEFAULT now()
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
-- Add org_id to backups for team backups
|
|
184
|
-
ALTER TABLE backups ADD COLUMN org_id UUID REFERENCES organizations(id);
|
|
185
|
-
|
|
186
|
-
-- Add stripe fields to subscriptions
|
|
187
|
-
ALTER TABLE subscriptions ADD COLUMN stripe_customer_id TEXT;
|
|
188
|
-
ALTER TABLE subscriptions ADD COLUMN stripe_subscription_id TEXT;
|
|
189
|
-
ALTER TABLE subscriptions ADD COLUMN seats INT DEFAULT 1;
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
---
|
|
193
|
-
|
|
194
|
-
## New CLI Commands Summary
|
|
195
|
-
|
|
196
|
-
```
|
|
197
|
-
memoir upgrade # Open Stripe checkout, activate Pro
|
|
198
|
-
memoir share # Generate encrypted shareable link
|
|
199
|
-
memoir team create # Create a team organization
|
|
200
|
-
memoir team invite # Invite teammate by email
|
|
201
|
-
memoir team list # List team members
|
|
202
|
-
memoir push --team # Push to team namespace
|
|
203
|
-
memoir restore --from # Restore from shared link or teammate
|
|
204
|
-
memoir history --diff # Diff between backup versions
|
|
205
|
-
memoir analytics # Show your usage stats (local)
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
|
-
## Risk Register
|
|
211
|
-
|
|
212
|
-
| Risk | Likelihood | Impact | Mitigation |
|
|
213
|
-
|------|-----------|--------|------------|
|
|
214
|
-
| AI tools change config paths | High | Medium | Version-gated path detection, community PRs for new tools |
|
|
215
|
-
| Supabase costs spike with users | Medium | Medium | Gzip compression (already done), enforce tier limits, monitor |
|
|
216
|
-
| Nobody pays for Pro | High | High | Validate with shareable links first (free viral), watch conversion |
|
|
217
|
-
| Enterprise competitor (JetBrains, GitHub) builds this | Medium | High | Move fast, own the CLI mindshare, community moat |
|
|
218
|
-
| ToS violations syncing AI configs | Low | High | Only sync user-owned files (configs, not conversations). Document clearly |
|
|
219
|
-
| Data breach of cloud backups | Low | Critical | E2E encryption means we literally can't read user data. Zero-knowledge by design |
|
|
220
|
-
|
|
221
|
-
---
|
|
222
|
-
|
|
223
|
-
## This Week's Checklist
|
|
224
|
-
|
|
225
|
-
- [ ] Stripe account setup + integration in CLI
|
|
226
|
-
- [ ] `memoir upgrade` command
|
|
227
|
-
- [ ] Pricing page on memoir.sh
|
|
228
|
-
- [ ] Email capture for Teams waitlist on memoir.sh
|
|
229
|
-
- [ ] PostHog analytics on CLI (anonymous, opt-out available)
|
|
230
|
-
- [ ] PostHog analytics on memoir.sh
|
|
231
|
-
- [ ] Post in 3 subreddits about memoir
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
*"The CLI is the funnel. Cloud is the product. Teams is the business."*
|