@autoship/react 0.1.0 → 0.3.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.
- package/dist/README.md +166 -0
- package/dist/cli/autoship.js +0 -0
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +182 -122
- package/package.json +4 -3
package/dist/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Autoship
|
|
2
|
+
|
|
3
|
+
A drop-in autonomous coding agent that records tasks in your app and implements them in a Github Action.
|
|
4
|
+
|
|
5
|
+
## How It Works
|
|
6
|
+
|
|
7
|
+
1. Users submit tasks via React components (or directly via Supabase)
|
|
8
|
+
2. A GitHub Action wakes up periodically and runs Claude Code
|
|
9
|
+
3. Claude picks up the highest priority task, implements it, and creates a PR
|
|
10
|
+
4. If Claude needs clarification, it asks a question and blocks the task until you answer
|
|
11
|
+
5. You review the PR and merge
|
|
12
|
+
|
|
13
|
+
## Packages
|
|
14
|
+
|
|
15
|
+
- **`@autoship/react`** - React components and CLI for task submission
|
|
16
|
+
- **`mcp-servers/autoship-mcp`** - MCP server for Claude Code integration
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
### 1. Create Supabase Project
|
|
21
|
+
|
|
22
|
+
Create a new Supabase project (or use an existing one). Get the SUPABASE_URL and your database password.
|
|
23
|
+
|
|
24
|
+
### 2. Set Up Supabase Database
|
|
25
|
+
|
|
26
|
+
Run the migrations using the CLI:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx @autoship init
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The CLI will prompt you for credentials. You can provide them in two ways:
|
|
33
|
+
|
|
34
|
+
**Option A: Full DATABASE_URL**
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Find this in Supabase Dashboard > Project Settings > Database > Connection string > URI
|
|
38
|
+
npx @autoship init --database-url "postgresql://postgres.xxx:password@aws-0-region.pooler.supabase.com:6543/postgres"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Option B: Supabase URL + Database Password**
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx @autoship init --supabase-url https://xxx.supabase.co --db-password yourpassword
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Using environment variables:**
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Option A
|
|
51
|
+
DATABASE_URL="postgresql://..." npx @autoship init
|
|
52
|
+
|
|
53
|
+
# Option B
|
|
54
|
+
SUPABASE_URL="https://xxx.supabase.co" DB_PASSWORD="yourpassword" npx @autoship/react init
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 3. Add React Components (Optional)
|
|
58
|
+
|
|
59
|
+
Install the package:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install @autoship/react
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Add the provider and button to your app:
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import { AutoshipProvider, AutoshipButton } from "@autoship/react";
|
|
69
|
+
|
|
70
|
+
function App() {
|
|
71
|
+
return (
|
|
72
|
+
<AutoshipProvider
|
|
73
|
+
supabaseUrl={process.env.SUPABASE_URL}
|
|
74
|
+
supabaseAnonKey={process.env.SUPABASE_ANON_KEY}
|
|
75
|
+
userId="optional-user-id"
|
|
76
|
+
>
|
|
77
|
+
<YourApp />
|
|
78
|
+
<AutoshipButton />
|
|
79
|
+
</AutoshipProvider>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Available components:
|
|
85
|
+
|
|
86
|
+
- `AutoshipProvider` - Context provider for Supabase connection
|
|
87
|
+
- `AutoshipButton` - Floating button to open task submission dialog
|
|
88
|
+
- `TaskDialog` - Modal for submitting new tasks
|
|
89
|
+
- `TaskList` - List of submitted tasks with status
|
|
90
|
+
- `TaskDetailDialog` - View task details and answer questions
|
|
91
|
+
- `QuestionDialog` - Answer clarifying questions from Claude
|
|
92
|
+
|
|
93
|
+
### 4. Set Up GitHub Actions
|
|
94
|
+
|
|
95
|
+
Copy these files into your project:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
mcp-servers/autoship-mcp/ # The MCP server
|
|
99
|
+
.mcp.json # MCP configuration
|
|
100
|
+
.github/workflows/claude-agent.yml # GitHub Actions workflow
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Add GitHub Secrets (Settings > Secrets and variables > Actions):
|
|
104
|
+
|
|
105
|
+
| Secret | Description |
|
|
106
|
+
| ---------------------- | ----------------------------------------------------------- |
|
|
107
|
+
| `ANTHROPIC_API_KEY` | Your Anthropic API key |
|
|
108
|
+
| `SUPABASE_URL` | Your Supabase project URL (e.g., `https://xxx.supabase.co`) |
|
|
109
|
+
| `SUPABASE_SERVICE_KEY` | Supabase service role key (not the anon key) |
|
|
110
|
+
|
|
111
|
+
### 5. Test Locally (Optional)
|
|
112
|
+
|
|
113
|
+
Build the MCP server:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
cd mcp-servers/autoship-mcp && npm install && npm run build
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# Set environment variables
|
|
121
|
+
export SUPABASE_URL="https://your-project.supabase.co"
|
|
122
|
+
export SUPABASE_SERVICE_KEY="your-service-key"
|
|
123
|
+
|
|
124
|
+
# Test the MCP tools
|
|
125
|
+
claude "Use the autoship-mcp tools to list pending tasks"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Manual Trigger
|
|
129
|
+
|
|
130
|
+
You can manually trigger the agent from the GitHub Actions tab, optionally with a custom prompt:
|
|
131
|
+
|
|
132
|
+
1. Go to Actions > Claude Agent
|
|
133
|
+
2. Click "Run workflow"
|
|
134
|
+
3. Optionally enter a custom prompt
|
|
135
|
+
4. Click "Run workflow"
|
|
136
|
+
|
|
137
|
+
## Monitoring
|
|
138
|
+
|
|
139
|
+
### GitHub Actions Logs
|
|
140
|
+
|
|
141
|
+
Check the Actions tab in your repository to see Claude's output for each run.
|
|
142
|
+
|
|
143
|
+
## Available MCP Tools
|
|
144
|
+
|
|
145
|
+
| Tool | Description |
|
|
146
|
+
| -------------------------- | ---------------------------------------------------- |
|
|
147
|
+
| `list_pending_tasks` | List all pending tasks by priority |
|
|
148
|
+
| `get_task` | Get full details including categories and questions |
|
|
149
|
+
| `claim_task` | Mark a task as in_progress |
|
|
150
|
+
| `complete_task` | Mark as complete with branch name |
|
|
151
|
+
| `fail_task` | Mark as failed with error message |
|
|
152
|
+
| `add_task` | Create new tasks |
|
|
153
|
+
| `list_categories` | List all categories |
|
|
154
|
+
| `create_category` | Create a new category |
|
|
155
|
+
| `assign_category` | Tag a task with a category |
|
|
156
|
+
| `ask_question` | Ask a clarifying question (marks task as needs_info) |
|
|
157
|
+
| `get_unanswered_questions` | List all unanswered questions |
|
|
158
|
+
| `check_answered_questions` | Check answers for a specific task |
|
|
159
|
+
| `resume_task` | Move a needs_info task back to pending |
|
|
160
|
+
|
|
161
|
+
## Cost Estimation
|
|
162
|
+
|
|
163
|
+
- Each run uses API tokens based on context length and task complexity
|
|
164
|
+
- A typical task costs $0.10-$1.00
|
|
165
|
+
- With 4 runs/day, expect ~$10-30/month (varies by task complexity)
|
|
166
|
+
- Monitor usage at console.anthropic.com
|
package/dist/cli/autoship.js
CHANGED
|
File without changes
|
package/dist/cli/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AA6WA,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAcvD"}
|
package/dist/cli/init.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import postgres from "postgres";
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import * as readline from "readline";
|
|
@@ -32,11 +32,14 @@ function parseArgs(args) {
|
|
|
32
32
|
const options = {};
|
|
33
33
|
for (let i = 0; i < args.length; i++) {
|
|
34
34
|
const arg = args[i];
|
|
35
|
-
if (arg === "--
|
|
35
|
+
if (arg === "--database-url" && args[i + 1]) {
|
|
36
|
+
options.databaseUrl = args[++i];
|
|
37
|
+
}
|
|
38
|
+
else if (arg === "--supabase-url" && args[i + 1]) {
|
|
36
39
|
options.supabaseUrl = args[++i];
|
|
37
40
|
}
|
|
38
|
-
else if (arg === "--
|
|
39
|
-
options.
|
|
41
|
+
else if (arg === "--db-password" && args[i + 1]) {
|
|
42
|
+
options.dbPassword = args[++i];
|
|
40
43
|
}
|
|
41
44
|
else if (arg === "--non-interactive" || arg === "-y") {
|
|
42
45
|
options.nonInteractive = true;
|
|
@@ -56,24 +59,36 @@ Usage:
|
|
|
56
59
|
npx autoship init [options]
|
|
57
60
|
|
|
58
61
|
Options:
|
|
59
|
-
--
|
|
60
|
-
--
|
|
62
|
+
--database-url <url> Full PostgreSQL connection URL (includes password)
|
|
63
|
+
--supabase-url <url> Supabase project URL (used to construct DATABASE_URL)
|
|
64
|
+
--db-password <pwd> Database password (used with --supabase-url)
|
|
61
65
|
-y, --non-interactive Skip confirmation prompts
|
|
62
66
|
-h, --help Show this help message
|
|
63
67
|
|
|
64
68
|
Environment Variables:
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
DATABASE_URL Full PostgreSQL connection URL (preferred)
|
|
70
|
+
SUPABASE_URL Supabase project URL (fallback, requires DB_PASSWORD)
|
|
71
|
+
DB_PASSWORD Database password (used with SUPABASE_URL)
|
|
72
|
+
|
|
73
|
+
Connection Methods:
|
|
74
|
+
1. Provide DATABASE_URL directly (recommended):
|
|
75
|
+
DATABASE_URL=postgresql://postgres.xxx:[password]@aws-0-region.pooler.supabase.com:6543/postgres
|
|
76
|
+
|
|
77
|
+
2. Provide SUPABASE_URL + DB_PASSWORD:
|
|
78
|
+
The CLI will construct the DATABASE_URL from your Supabase project URL.
|
|
67
79
|
|
|
68
80
|
Examples:
|
|
69
81
|
# Interactive mode (prompts for credentials)
|
|
70
82
|
npx autoship init
|
|
71
83
|
|
|
72
|
-
# With
|
|
73
|
-
npx autoship init --
|
|
84
|
+
# With full database URL
|
|
85
|
+
npx autoship init --database-url "postgresql://postgres.xxx:password@aws-0-region.pooler.supabase.com:6543/postgres"
|
|
86
|
+
|
|
87
|
+
# With Supabase URL + password
|
|
88
|
+
npx autoship init --supabase-url https://xxx.supabase.co --db-password mypassword
|
|
74
89
|
|
|
75
90
|
# Using environment variables
|
|
76
|
-
|
|
91
|
+
DATABASE_URL="postgresql://..." npx autoship init
|
|
77
92
|
`);
|
|
78
93
|
}
|
|
79
94
|
function createReadlineInterface() {
|
|
@@ -127,142 +142,187 @@ async function promptSecret(rl, question) {
|
|
|
127
142
|
stdin.resume();
|
|
128
143
|
});
|
|
129
144
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Constructs a DATABASE_URL from a Supabase project URL and password.
|
|
147
|
+
*
|
|
148
|
+
* Supabase URL format: https://[project-ref].supabase.co
|
|
149
|
+
* Database URL format: postgresql://postgres.[project-ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres
|
|
150
|
+
*
|
|
151
|
+
* Note: We use the transaction pooler (port 6543) for compatibility.
|
|
152
|
+
* The region is detected from the Supabase URL or defaults to us-east-1.
|
|
153
|
+
*/
|
|
154
|
+
function constructDatabaseUrl(supabaseUrl, password) {
|
|
155
|
+
const url = new URL(supabaseUrl);
|
|
156
|
+
const hostname = url.hostname; // e.g., "xxx.supabase.co"
|
|
157
|
+
const projectRef = hostname.split(".")[0];
|
|
158
|
+
if (!projectRef) {
|
|
159
|
+
throw new Error("Could not extract project reference from Supabase URL");
|
|
160
|
+
}
|
|
161
|
+
// Supabase uses different regional pooler endpoints
|
|
162
|
+
// Default to us-east-1, but this can be adjusted
|
|
163
|
+
// The actual region is embedded in the project, but we can't easily detect it
|
|
164
|
+
// Users can provide DATABASE_URL directly if they need a specific region
|
|
165
|
+
const region = "us-east-1";
|
|
166
|
+
const encodedPassword = encodeURIComponent(password);
|
|
167
|
+
return `postgresql://postgres.${projectRef}:${encodedPassword}@aws-0-${region}.pooler.supabase.com:6543/postgres`;
|
|
168
|
+
}
|
|
169
|
+
async function getConnectionUrl(options) {
|
|
170
|
+
// Priority: CLI args > env vars > interactive prompt
|
|
171
|
+
// Check for direct DATABASE_URL first
|
|
172
|
+
let databaseUrl = options.databaseUrl || process.env.DATABASE_URL;
|
|
173
|
+
if (databaseUrl) {
|
|
174
|
+
return databaseUrl;
|
|
175
|
+
}
|
|
176
|
+
// Check for SUPABASE_URL + DB_PASSWORD combination
|
|
177
|
+
let supabaseUrl = options.supabaseUrl || process.env.SUPABASE_URL;
|
|
178
|
+
let dbPassword = options.dbPassword || process.env.DB_PASSWORD;
|
|
179
|
+
if (supabaseUrl && dbPassword) {
|
|
180
|
+
return constructDatabaseUrl(supabaseUrl, dbPassword);
|
|
135
181
|
}
|
|
182
|
+
// Interactive mode
|
|
136
183
|
const rl = createReadlineInterface();
|
|
137
184
|
try {
|
|
138
185
|
console.log("\n Autoship Database Setup\n");
|
|
139
186
|
console.log(" This will create the required tables in your Supabase database.\n");
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
187
|
+
console.log(" You can provide credentials in two ways:");
|
|
188
|
+
console.log(" 1. Full DATABASE_URL (includes password)");
|
|
189
|
+
console.log(" 2. Supabase URL + database password\n");
|
|
190
|
+
const choice = await prompt(rl, " Enter (1) for DATABASE_URL or (2) for Supabase URL + password: ");
|
|
191
|
+
if (choice === "1") {
|
|
192
|
+
console.log("\n Find your DATABASE_URL in Supabase Dashboard:");
|
|
193
|
+
console.log(" Project Settings > Database > Connection string > URI\n");
|
|
194
|
+
databaseUrl = await promptSecret(rl, " DATABASE_URL: ");
|
|
195
|
+
return databaseUrl;
|
|
148
196
|
}
|
|
149
197
|
else {
|
|
150
|
-
|
|
198
|
+
if (!supabaseUrl) {
|
|
199
|
+
supabaseUrl = await prompt(rl, "\n Supabase URL (e.g., https://xxx.supabase.co): ");
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
console.log(`\n Supabase URL: ${supabaseUrl}`);
|
|
203
|
+
}
|
|
204
|
+
if (!dbPassword) {
|
|
205
|
+
console.log("\n Find your database password in Supabase Dashboard:");
|
|
206
|
+
console.log(" Project Settings > Database > Database password\n");
|
|
207
|
+
dbPassword = await promptSecret(rl, " Database password: ");
|
|
208
|
+
}
|
|
209
|
+
return constructDatabaseUrl(supabaseUrl, dbPassword);
|
|
151
210
|
}
|
|
152
|
-
return { url, serviceKey };
|
|
153
211
|
}
|
|
154
212
|
finally {
|
|
155
213
|
rl.close();
|
|
156
214
|
}
|
|
157
215
|
}
|
|
158
|
-
function
|
|
159
|
-
if (!
|
|
160
|
-
console.error("\n Error:
|
|
161
|
-
process.exit(1);
|
|
162
|
-
}
|
|
163
|
-
if (!serviceKey) {
|
|
164
|
-
console.error("\n Error: Supabase Service Key is required");
|
|
216
|
+
function validateDatabaseUrl(databaseUrl) {
|
|
217
|
+
if (!databaseUrl) {
|
|
218
|
+
console.error("\n Error: Database connection URL is required");
|
|
165
219
|
process.exit(1);
|
|
166
220
|
}
|
|
167
221
|
try {
|
|
168
|
-
new URL(
|
|
222
|
+
const url = new URL(databaseUrl);
|
|
223
|
+
if (!url.protocol.startsWith("postgres")) {
|
|
224
|
+
throw new Error("Not a PostgreSQL URL");
|
|
225
|
+
}
|
|
169
226
|
}
|
|
170
227
|
catch {
|
|
171
|
-
console.error("\n Error: Invalid
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
if (!serviceKey.startsWith("eyJ")) {
|
|
175
|
-
console.error("\n Error: Service key should be a JWT (starts with 'eyJ')");
|
|
176
|
-
console.error(" Make sure you're using the service_role key, not the anon key.");
|
|
228
|
+
console.error("\n Error: Invalid DATABASE_URL format");
|
|
229
|
+
console.error(" Expected format: postgresql://user:password@host:port/database");
|
|
177
230
|
process.exit(1);
|
|
178
231
|
}
|
|
179
232
|
}
|
|
180
|
-
async function runMigration(
|
|
181
|
-
console.log("\n Connecting to
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
persistSession: false,
|
|
186
|
-
},
|
|
233
|
+
async function runMigration(databaseUrl, migrationSql) {
|
|
234
|
+
console.log("\n Connecting to database...");
|
|
235
|
+
const sql = postgres(databaseUrl, {
|
|
236
|
+
ssl: "require",
|
|
237
|
+
connect_timeout: 10,
|
|
187
238
|
});
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
.
|
|
192
|
-
.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
//
|
|
197
|
-
console.log("
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
console.log(" 3. Copy autoship-migration.sql to supabase/migrations/");
|
|
210
|
-
console.log(" 4. Run: supabase db push\n");
|
|
211
|
-
// Write the migration file locally for convenience
|
|
212
|
-
const outputPath = path.join(process.cwd(), "autoship-migration.sql");
|
|
213
|
-
fs.writeFileSync(outputPath, migrationSql.trim());
|
|
214
|
-
console.log(` Migration SQL saved to: ${outputPath}\n`);
|
|
215
|
-
console.log(" After running the migration, run this setup command again to verify.\n");
|
|
216
|
-
process.exit(0);
|
|
217
|
-
}
|
|
218
|
-
else if (connectionError) {
|
|
219
|
-
console.error(`\n Error connecting to Supabase: ${connectionError.message}`);
|
|
220
|
-
process.exit(1);
|
|
221
|
-
}
|
|
222
|
-
// Tables exist - verify the schema
|
|
223
|
-
console.log(" Verifying database schema...\n");
|
|
224
|
-
const tables = ["agent_tasks", "task_categories", "task_category_assignments", "task_questions"];
|
|
225
|
-
let allTablesExist = true;
|
|
226
|
-
for (const table of tables) {
|
|
227
|
-
const { error } = await supabase.from(table).select("*").limit(0);
|
|
228
|
-
if (error && error.code === "42P01") {
|
|
229
|
-
console.log(` [ ] ${table} - NOT FOUND`);
|
|
230
|
-
allTablesExist = false;
|
|
239
|
+
try {
|
|
240
|
+
// Test the connection
|
|
241
|
+
await sql `SELECT 1`;
|
|
242
|
+
console.log(" Connected successfully.\n");
|
|
243
|
+
console.log(" Running migrations...\n");
|
|
244
|
+
// Execute the migration SQL
|
|
245
|
+
await sql.unsafe(migrationSql);
|
|
246
|
+
console.log(" Migrations completed successfully!\n");
|
|
247
|
+
// Verify the schema
|
|
248
|
+
console.log(" Verifying database schema...\n");
|
|
249
|
+
const tables = ["agent_tasks", "task_categories", "task_category_assignments", "task_questions"];
|
|
250
|
+
let allTablesExist = true;
|
|
251
|
+
for (const table of tables) {
|
|
252
|
+
try {
|
|
253
|
+
await sql.unsafe(`SELECT 1 FROM ${table} LIMIT 0`);
|
|
254
|
+
console.log(` [x] ${table}`);
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
console.log(` [ ] ${table} - NOT FOUND`);
|
|
258
|
+
allTablesExist = false;
|
|
259
|
+
}
|
|
231
260
|
}
|
|
232
|
-
|
|
233
|
-
console.log(
|
|
261
|
+
if (allTablesExist) {
|
|
262
|
+
console.log("\n All tables created. Your database is ready!\n");
|
|
263
|
+
console.log(" Next steps:");
|
|
264
|
+
console.log(" 1. Add SUPABASE_URL and SUPABASE_ANON_KEY to your app's environment");
|
|
265
|
+
console.log(" 2. Wrap your app with <AutoshipProvider>");
|
|
266
|
+
console.log(" 3. Add the <AutoshipButton /> component\n");
|
|
267
|
+
console.log(" Example:");
|
|
268
|
+
console.log(" import { AutoshipProvider, AutoshipButton } from '@autoship/react';");
|
|
269
|
+
console.log("");
|
|
270
|
+
console.log(" function App() {");
|
|
271
|
+
console.log(" return (");
|
|
272
|
+
console.log(" <AutoshipProvider");
|
|
273
|
+
console.log(" supabaseUrl={process.env.SUPABASE_URL}");
|
|
274
|
+
console.log(" supabaseAnonKey={process.env.SUPABASE_ANON_KEY}");
|
|
275
|
+
console.log(" >");
|
|
276
|
+
console.log(" <YourApp />");
|
|
277
|
+
console.log(" <AutoshipButton />");
|
|
278
|
+
console.log(" </AutoshipProvider>");
|
|
279
|
+
console.log(" );");
|
|
280
|
+
console.log(" }\n");
|
|
234
281
|
}
|
|
235
282
|
else {
|
|
236
|
-
console.log(
|
|
283
|
+
console.log("\n Warning: Some tables may not have been created correctly.");
|
|
284
|
+
console.log(" Please check the migration output above for errors.\n");
|
|
285
|
+
process.exit(1);
|
|
237
286
|
}
|
|
238
287
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
288
|
+
catch (error) {
|
|
289
|
+
const err = error;
|
|
290
|
+
if (err.code === "28P01") {
|
|
291
|
+
console.error("\n Error: Authentication failed. Check your database password.");
|
|
292
|
+
}
|
|
293
|
+
else if (err.code === "ENOTFOUND" || err.code === "ECONNREFUSED") {
|
|
294
|
+
console.error("\n Error: Could not connect to database. Check your connection URL.");
|
|
295
|
+
}
|
|
296
|
+
else if (err.message?.includes("already exists")) {
|
|
297
|
+
console.log("\n Schema already exists. Verifying tables...\n");
|
|
298
|
+
// Verify existing schema
|
|
299
|
+
const tables = ["agent_tasks", "task_categories", "task_category_assignments", "task_questions"];
|
|
300
|
+
let allTablesExist = true;
|
|
301
|
+
for (const table of tables) {
|
|
302
|
+
try {
|
|
303
|
+
await sql.unsafe(`SELECT 1 FROM ${table} LIMIT 0`);
|
|
304
|
+
console.log(` [x] ${table}`);
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
console.log(` [ ] ${table} - NOT FOUND`);
|
|
308
|
+
allTablesExist = false;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (allTablesExist) {
|
|
312
|
+
console.log("\n All tables exist. Your database is ready!\n");
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
console.log("\n Some tables are missing. You may need to run migrations manually.\n");
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
console.error(`\n Error: ${err.message}`);
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
259
323
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const outputPath = path.join(process.cwd(), "autoship-migration.sql");
|
|
263
|
-
fs.writeFileSync(outputPath, migrationSql.trim());
|
|
264
|
-
console.log(` Migration SQL saved to: ${outputPath}\n`);
|
|
265
|
-
process.exit(1);
|
|
324
|
+
finally {
|
|
325
|
+
await sql.end();
|
|
266
326
|
}
|
|
267
327
|
}
|
|
268
328
|
export async function run(args) {
|
|
@@ -270,9 +330,9 @@ export async function run(args) {
|
|
|
270
330
|
try {
|
|
271
331
|
// Load migrations from the bundled files
|
|
272
332
|
const migrationSql = loadMigrations();
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
await runMigration(
|
|
333
|
+
const databaseUrl = await getConnectionUrl(options);
|
|
334
|
+
validateDatabaseUrl(databaseUrl);
|
|
335
|
+
await runMigration(databaseUrl, migrationSql);
|
|
276
336
|
}
|
|
277
337
|
catch (error) {
|
|
278
338
|
console.error("\n Unexpected error:", error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autoship/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -17,13 +17,14 @@
|
|
|
17
17
|
"dist"
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "tsc && npm run copy-migrations",
|
|
20
|
+
"build": "tsc && cp ../../README.md dist/ && npm run copy-migrations",
|
|
21
21
|
"copy-migrations": "mkdir -p dist/migrations && cp ../../supabase/migrations/*.sql dist/migrations/",
|
|
22
22
|
"dev": "tsc --watch",
|
|
23
23
|
"cli": "node dist/cli/autoship.js"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@supabase/supabase-js": "^2.90.1"
|
|
26
|
+
"@supabase/supabase-js": "^2.90.1",
|
|
27
|
+
"postgres": "^3.4.5"
|
|
27
28
|
},
|
|
28
29
|
"peerDependencies": {
|
|
29
30
|
"react": "^18.0.0 || ^19.0.0"
|