@autoship/react 0.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.
- package/dist/AutoshipButton.d.ts +7 -0
- package/dist/AutoshipButton.d.ts.map +1 -0
- package/dist/AutoshipButton.js +67 -0
- package/dist/AutoshipProvider.d.ts +15 -0
- package/dist/AutoshipProvider.d.ts.map +1 -0
- package/dist/AutoshipProvider.js +15 -0
- package/dist/QuestionDialog.d.ts +9 -0
- package/dist/QuestionDialog.d.ts.map +1 -0
- package/dist/QuestionDialog.js +85 -0
- package/dist/SnapdevButton.d.ts +7 -0
- package/dist/SnapdevButton.d.ts.map +1 -0
- package/dist/SnapdevButton.js +67 -0
- package/dist/SnapdevProvider.d.ts +15 -0
- package/dist/SnapdevProvider.d.ts.map +1 -0
- package/dist/SnapdevProvider.js +15 -0
- package/dist/TaskDetailDialog.d.ts +9 -0
- package/dist/TaskDetailDialog.d.ts.map +1 -0
- package/dist/TaskDetailDialog.js +172 -0
- package/dist/TaskDialog.d.ts +7 -0
- package/dist/TaskDialog.d.ts.map +1 -0
- package/dist/TaskDialog.js +85 -0
- package/dist/TaskList.d.ts +23 -0
- package/dist/TaskList.d.ts.map +1 -0
- package/dist/TaskList.js +126 -0
- package/dist/cli/autoship.d.ts +3 -0
- package/dist/cli/autoship.d.ts.map +1 -0
- package/dist/cli/autoship.js +37 -0
- package/dist/cli/init.d.ts +2 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +281 -0
- package/dist/cli/setup.d.ts +3 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +284 -0
- package/dist/cli/snapdev.d.ts +3 -0
- package/dist/cli/snapdev.d.ts.map +1 -0
- package/dist/cli/snapdev.js +42 -0
- package/dist/hooks/useAutoship.d.ts +18 -0
- package/dist/hooks/useAutoship.d.ts.map +1 -0
- package/dist/hooks/useAutoship.js +23 -0
- package/dist/hooks/useSnapdev.d.ts +18 -0
- package/dist/hooks/useSnapdev.d.ts.map +1 -0
- package/dist/hooks/useSnapdev.js +23 -0
- package/dist/hooks/useTasks.d.ts +8 -0
- package/dist/hooks/useTasks.d.ts.map +1 -0
- package/dist/hooks/useTasks.js +57 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/migrations/20250118000000_initial_schema.sql +143 -0
- package/package.json +46 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface Question {
|
|
3
|
+
id: string;
|
|
4
|
+
question: string;
|
|
5
|
+
answer: string | null;
|
|
6
|
+
asked_at: string;
|
|
7
|
+
answered_at: string | null;
|
|
8
|
+
}
|
|
9
|
+
export interface Task {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
status: "pending" | "in_progress" | "complete" | "failed" | "blocked" | "needs_info";
|
|
14
|
+
branch_name: string | null;
|
|
15
|
+
pr_url: string | null;
|
|
16
|
+
task_questions: Question[] | null;
|
|
17
|
+
created_at: string;
|
|
18
|
+
}
|
|
19
|
+
export interface TaskListProps {
|
|
20
|
+
onBack: () => void;
|
|
21
|
+
}
|
|
22
|
+
export declare function TaskList({ onBack }: TaskListProps): React.ReactElement;
|
|
23
|
+
//# sourceMappingURL=TaskList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaskList.d.ts","sourceRoot":"","sources":["../src/TaskList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;IACrF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,cAAc,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,wBAAgB,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,aAAa,GAAG,KAAK,CAAC,YAAY,CAsNtE"}
|
package/dist/TaskList.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { useAutoshipContext } from "./AutoshipProvider";
|
|
4
|
+
import { TaskDetailDialog } from "./TaskDetailDialog";
|
|
5
|
+
export function TaskList({ onBack }) {
|
|
6
|
+
const { supabase, userId } = useAutoshipContext();
|
|
7
|
+
const [tasks, setTasks] = useState([]);
|
|
8
|
+
const [loading, setLoading] = useState(true);
|
|
9
|
+
const [selectedTask, setSelectedTask] = useState(null);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
loadTasks();
|
|
12
|
+
}, []);
|
|
13
|
+
const loadTasks = async () => {
|
|
14
|
+
setLoading(true);
|
|
15
|
+
try {
|
|
16
|
+
// Fetch tasks with their related questions from task_questions table
|
|
17
|
+
let query = supabase
|
|
18
|
+
.from("agent_tasks")
|
|
19
|
+
.select(`
|
|
20
|
+
*,
|
|
21
|
+
task_questions (
|
|
22
|
+
id,
|
|
23
|
+
question,
|
|
24
|
+
answer,
|
|
25
|
+
asked_at,
|
|
26
|
+
answered_at
|
|
27
|
+
)
|
|
28
|
+
`)
|
|
29
|
+
.order("created_at", { ascending: false });
|
|
30
|
+
if (userId) {
|
|
31
|
+
query = query.eq("submitted_by", userId);
|
|
32
|
+
}
|
|
33
|
+
const { data, error } = await query;
|
|
34
|
+
if (error)
|
|
35
|
+
throw error;
|
|
36
|
+
setTasks(data || []);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
console.error("Failed to load tasks:", err);
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
setLoading(false);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const statusColors = {
|
|
46
|
+
pending: "#f59e0b",
|
|
47
|
+
in_progress: "#3b82f6",
|
|
48
|
+
complete: "#10b981",
|
|
49
|
+
failed: "#ef4444",
|
|
50
|
+
blocked: "#f59e0b",
|
|
51
|
+
needs_info: "#8b5cf6",
|
|
52
|
+
};
|
|
53
|
+
const statusLabels = {
|
|
54
|
+
pending: "Pending",
|
|
55
|
+
in_progress: "In Progress",
|
|
56
|
+
complete: "Complete",
|
|
57
|
+
failed: "Failed",
|
|
58
|
+
blocked: "Blocked",
|
|
59
|
+
needs_info: "Needs Info",
|
|
60
|
+
};
|
|
61
|
+
if (selectedTask) {
|
|
62
|
+
return (_jsx(TaskDetailDialog, { task: selectedTask, onBack: () => {
|
|
63
|
+
setSelectedTask(null);
|
|
64
|
+
loadTasks();
|
|
65
|
+
}, onUpdated: loadTasks }));
|
|
66
|
+
}
|
|
67
|
+
return (_jsxs("div", { children: [_jsxs("div", { style: { display: "flex", alignItems: "center", marginBottom: 16 }, children: [_jsx("button", { type: "button", onClick: onBack, style: {
|
|
68
|
+
marginRight: 12,
|
|
69
|
+
background: "none",
|
|
70
|
+
border: "none",
|
|
71
|
+
fontSize: 20,
|
|
72
|
+
cursor: "pointer",
|
|
73
|
+
padding: 4,
|
|
74
|
+
}, children: "\u2190" }), _jsx("h2", { style: { margin: 0 }, children: "My Requests" })] }), loading ? (_jsx("p", { style: { color: "#666" }, children: "Loading..." })) : tasks.length === 0 ? (_jsx("p", { style: { color: "#666" }, children: "No requests yet." })) : (_jsx("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: tasks.map((task) => {
|
|
75
|
+
const questions = task.task_questions || [];
|
|
76
|
+
const hasUnansweredQuestions = questions.some((q) => !q.answer);
|
|
77
|
+
const hasQuestions = questions.length > 0;
|
|
78
|
+
return (_jsxs("div", { style: {
|
|
79
|
+
padding: 12,
|
|
80
|
+
border: "1px solid #e5e7eb",
|
|
81
|
+
borderRadius: 8,
|
|
82
|
+
cursor: "pointer",
|
|
83
|
+
backgroundColor: hasUnansweredQuestions ? "#ecfdf5" : "white",
|
|
84
|
+
transition: "background-color 0.15s ease",
|
|
85
|
+
}, onClick: () => setSelectedTask(task), onMouseEnter: (e) => {
|
|
86
|
+
if (!hasUnansweredQuestions) {
|
|
87
|
+
e.currentTarget.style.backgroundColor = "#f9fafb";
|
|
88
|
+
}
|
|
89
|
+
}, onMouseLeave: (e) => {
|
|
90
|
+
e.currentTarget.style.backgroundColor = hasUnansweredQuestions
|
|
91
|
+
? "#ecfdf5"
|
|
92
|
+
: "white";
|
|
93
|
+
}, children: [_jsxs("div", { style: {
|
|
94
|
+
display: "flex",
|
|
95
|
+
justifyContent: "space-between",
|
|
96
|
+
alignItems: "start",
|
|
97
|
+
gap: 12,
|
|
98
|
+
}, children: [_jsx("h4", { style: { margin: 0, fontSize: 16 }, children: task.title }), _jsx("span", { style: {
|
|
99
|
+
backgroundColor: statusColors[task.status] || "#9ca3af",
|
|
100
|
+
color: "white",
|
|
101
|
+
padding: "2px 8px",
|
|
102
|
+
borderRadius: 12,
|
|
103
|
+
fontSize: 12,
|
|
104
|
+
flexShrink: 0,
|
|
105
|
+
}, children: statusLabels[task.status] || task.status })] }), _jsx("p", { style: {
|
|
106
|
+
margin: "8px 0",
|
|
107
|
+
fontSize: 14,
|
|
108
|
+
color: "#666",
|
|
109
|
+
lineHeight: 1.4,
|
|
110
|
+
}, children: task.description.length > 100
|
|
111
|
+
? task.description.slice(0, 100) + "..."
|
|
112
|
+
: task.description }), _jsxs("div", { style: {
|
|
113
|
+
display: "flex",
|
|
114
|
+
alignItems: "center",
|
|
115
|
+
gap: 12,
|
|
116
|
+
marginTop: 4,
|
|
117
|
+
}, children: [hasUnansweredQuestions && (_jsx("span", { style: {
|
|
118
|
+
fontSize: 12,
|
|
119
|
+
color: "#059669",
|
|
120
|
+
fontWeight: 500,
|
|
121
|
+
}, children: "Needs your response" })), hasQuestions && !hasUnansweredQuestions && (_jsx("span", { style: {
|
|
122
|
+
fontSize: 12,
|
|
123
|
+
color: "#6b7280",
|
|
124
|
+
}, children: "Has feedback" })), task.pr_url && (_jsx("a", { href: task.pr_url, target: "_blank", rel: "noopener noreferrer", style: { fontSize: 12, color: "#10b981" }, onClick: (e) => e.stopPropagation(), children: "View PR" }))] })] }, task.id));
|
|
125
|
+
}) }))] }));
|
|
126
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autoship.d.ts","sourceRoot":"","sources":["../../src/cli/autoship.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { run as init } from "./init.js";
|
|
3
|
+
const commands = {
|
|
4
|
+
init,
|
|
5
|
+
};
|
|
6
|
+
function printHelp() {
|
|
7
|
+
console.log(`
|
|
8
|
+
autoship - CLI for @autoship/react
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
npx autoship <command> [options]
|
|
12
|
+
|
|
13
|
+
Commands:
|
|
14
|
+
init Initialize Autoship database schema
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
-h, --help Show this help message
|
|
18
|
+
|
|
19
|
+
Run 'npx autoship <command> --help' for more information on a command.
|
|
20
|
+
`);
|
|
21
|
+
}
|
|
22
|
+
async function main() {
|
|
23
|
+
const args = process.argv.slice(2);
|
|
24
|
+
const command = args[0];
|
|
25
|
+
if (!command || command === "-h" || command === "--help") {
|
|
26
|
+
printHelp();
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
const commandFn = commands[command];
|
|
30
|
+
if (!commandFn) {
|
|
31
|
+
console.error(`\n Unknown command: ${command}`);
|
|
32
|
+
printHelp();
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
await commandFn(args.slice(1));
|
|
36
|
+
}
|
|
37
|
+
main();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAgTA,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAcvD"}
|
package/dist/cli/init.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { createClient } from "@supabase/supabase-js";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as readline from "readline";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
function loadMigrations() {
|
|
9
|
+
// Migrations are copied to dist/migrations/ at build time
|
|
10
|
+
const migrationsDir = path.join(__dirname, "..", "migrations");
|
|
11
|
+
if (!fs.existsSync(migrationsDir)) {
|
|
12
|
+
console.error("\n Error: Migrations directory not found.");
|
|
13
|
+
console.error(" Expected at:", migrationsDir);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
const migrationFiles = fs.readdirSync(migrationsDir)
|
|
17
|
+
.filter(f => f.endsWith(".sql"))
|
|
18
|
+
.sort(); // Sort to ensure correct order (files are named with timestamps)
|
|
19
|
+
if (migrationFiles.length === 0) {
|
|
20
|
+
console.error("\n Error: No migration files found in", migrationsDir);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
// Concatenate all migrations in order
|
|
24
|
+
const migrations = migrationFiles.map(file => {
|
|
25
|
+
const filePath = path.join(migrationsDir, file);
|
|
26
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
27
|
+
return `-- Migration: ${file}\n${content}`;
|
|
28
|
+
}).join("\n\n");
|
|
29
|
+
return migrations;
|
|
30
|
+
}
|
|
31
|
+
function parseArgs(args) {
|
|
32
|
+
const options = {};
|
|
33
|
+
for (let i = 0; i < args.length; i++) {
|
|
34
|
+
const arg = args[i];
|
|
35
|
+
if (arg === "--db-url" && args[i + 1]) {
|
|
36
|
+
options.supabaseUrl = args[++i];
|
|
37
|
+
}
|
|
38
|
+
else if (arg === "--service-key" && args[i + 1]) {
|
|
39
|
+
options.supabaseServiceKey = args[++i];
|
|
40
|
+
}
|
|
41
|
+
else if (arg === "--non-interactive" || arg === "-y") {
|
|
42
|
+
options.nonInteractive = true;
|
|
43
|
+
}
|
|
44
|
+
else if (arg === "--help" || arg === "-h") {
|
|
45
|
+
printHelp();
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return options;
|
|
50
|
+
}
|
|
51
|
+
function printHelp() {
|
|
52
|
+
console.log(`
|
|
53
|
+
autoship init - Initialize Autoship database schema
|
|
54
|
+
|
|
55
|
+
Usage:
|
|
56
|
+
npx autoship init [options]
|
|
57
|
+
|
|
58
|
+
Options:
|
|
59
|
+
--db-url <url> Supabase project URL
|
|
60
|
+
--service-key <key> Supabase service role key
|
|
61
|
+
-y, --non-interactive Skip confirmation prompts
|
|
62
|
+
-h, --help Show this help message
|
|
63
|
+
|
|
64
|
+
Environment Variables:
|
|
65
|
+
SUPABASE_URL Supabase project URL (fallback)
|
|
66
|
+
SUPABASE_SERVICE_KEY Supabase service role key (fallback)
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
# Interactive mode (prompts for credentials)
|
|
70
|
+
npx autoship init
|
|
71
|
+
|
|
72
|
+
# With command line arguments
|
|
73
|
+
npx autoship init --db-url https://xxx.supabase.co --service-key eyJ...
|
|
74
|
+
|
|
75
|
+
# Using environment variables
|
|
76
|
+
SUPABASE_URL=https://xxx.supabase.co SUPABASE_SERVICE_KEY=eyJ... npx autoship init
|
|
77
|
+
`);
|
|
78
|
+
}
|
|
79
|
+
function createReadlineInterface() {
|
|
80
|
+
return readline.createInterface({
|
|
81
|
+
input: process.stdin,
|
|
82
|
+
output: process.stdout,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async function prompt(rl, question) {
|
|
86
|
+
return new Promise((resolve) => {
|
|
87
|
+
rl.question(question, (answer) => {
|
|
88
|
+
resolve(answer.trim());
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async function promptSecret(rl, question) {
|
|
93
|
+
return new Promise((resolve) => {
|
|
94
|
+
process.stdout.write(question);
|
|
95
|
+
const stdin = process.stdin;
|
|
96
|
+
const wasRaw = stdin.isRaw;
|
|
97
|
+
if (stdin.isTTY) {
|
|
98
|
+
stdin.setRawMode(true);
|
|
99
|
+
}
|
|
100
|
+
let input = "";
|
|
101
|
+
const onData = (char) => {
|
|
102
|
+
const c = char.toString();
|
|
103
|
+
if (c === "\n" || c === "\r") {
|
|
104
|
+
if (stdin.isTTY) {
|
|
105
|
+
stdin.setRawMode(wasRaw ?? false);
|
|
106
|
+
}
|
|
107
|
+
stdin.removeListener("data", onData);
|
|
108
|
+
process.stdout.write("\n");
|
|
109
|
+
resolve(input);
|
|
110
|
+
}
|
|
111
|
+
else if (c === "\u0003") {
|
|
112
|
+
// Ctrl+C
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
else if (c === "\u007F" || c === "\b") {
|
|
116
|
+
// Backspace
|
|
117
|
+
if (input.length > 0) {
|
|
118
|
+
input = input.slice(0, -1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
input += c;
|
|
123
|
+
process.stdout.write("*");
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
stdin.on("data", onData);
|
|
127
|
+
stdin.resume();
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
async function getCredentials(options) {
|
|
131
|
+
let url = options.supabaseUrl || process.env.SUPABASE_URL || "";
|
|
132
|
+
let serviceKey = options.supabaseServiceKey || process.env.SUPABASE_SERVICE_KEY || "";
|
|
133
|
+
if (url && serviceKey) {
|
|
134
|
+
return { url, serviceKey };
|
|
135
|
+
}
|
|
136
|
+
const rl = createReadlineInterface();
|
|
137
|
+
try {
|
|
138
|
+
console.log("\n Autoship Database Setup\n");
|
|
139
|
+
console.log(" This will create the required tables in your Supabase database.\n");
|
|
140
|
+
if (!url) {
|
|
141
|
+
url = await prompt(rl, " Supabase URL: ");
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
console.log(` Supabase URL: ${url}`);
|
|
145
|
+
}
|
|
146
|
+
if (!serviceKey) {
|
|
147
|
+
serviceKey = await promptSecret(rl, " Supabase Service Key: ");
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
console.log(" Supabase Service Key: [provided]");
|
|
151
|
+
}
|
|
152
|
+
return { url, serviceKey };
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
rl.close();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function validateCredentials(url, serviceKey) {
|
|
159
|
+
if (!url) {
|
|
160
|
+
console.error("\n Error: Supabase URL is required");
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
if (!serviceKey) {
|
|
164
|
+
console.error("\n Error: Supabase Service Key is required");
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
new URL(url);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
console.error("\n Error: Invalid Supabase URL format");
|
|
172
|
+
process.exit(1);
|
|
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.");
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async function runMigration(url, serviceKey, migrationSql) {
|
|
181
|
+
console.log("\n Connecting to Supabase...");
|
|
182
|
+
const supabase = createClient(url, serviceKey, {
|
|
183
|
+
auth: {
|
|
184
|
+
autoRefreshToken: false,
|
|
185
|
+
persistSession: false,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
console.log(" Checking database schema...\n");
|
|
189
|
+
// First, let's verify the connection by trying to query
|
|
190
|
+
const { error: connectionError } = await supabase
|
|
191
|
+
.from("agent_tasks")
|
|
192
|
+
.select("id")
|
|
193
|
+
.limit(1);
|
|
194
|
+
if (connectionError && connectionError.code === "42P01") {
|
|
195
|
+
// Table doesn't exist - we need to create it
|
|
196
|
+
// Since we can't run arbitrary SQL via the REST API, we'll provide instructions
|
|
197
|
+
console.log(" Tables don't exist yet.\n");
|
|
198
|
+
console.log(" ============================================================");
|
|
199
|
+
console.log(" Supabase REST API doesn't support direct SQL execution.");
|
|
200
|
+
console.log(" Please run the migration manually using one of these options:");
|
|
201
|
+
console.log(" ============================================================\n");
|
|
202
|
+
console.log(" Option 1: Supabase Dashboard");
|
|
203
|
+
console.log(" 1. Go to your Supabase project dashboard");
|
|
204
|
+
console.log(" 2. Navigate to SQL Editor");
|
|
205
|
+
console.log(" 3. Copy and paste the contents of: ./autoship-migration.sql\n");
|
|
206
|
+
console.log(" Option 2: Supabase CLI");
|
|
207
|
+
console.log(" 1. Install Supabase CLI: npm install -g supabase");
|
|
208
|
+
console.log(" 2. Link your project: supabase link --project-ref YOUR_PROJECT_REF");
|
|
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;
|
|
231
|
+
}
|
|
232
|
+
else if (error) {
|
|
233
|
+
console.log(` [?] ${table} - Error: ${error.message}`);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
console.log(` [x] ${table}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (allTablesExist) {
|
|
240
|
+
console.log("\n All tables exist. Your database is ready!\n");
|
|
241
|
+
console.log(" Next steps:");
|
|
242
|
+
console.log(" 1. Add SUPABASE_URL and SUPABASE_ANON_KEY to your app's environment");
|
|
243
|
+
console.log(" 2. Wrap your app with <AutoshipProvider>");
|
|
244
|
+
console.log(" 3. Add the <AutoshipButton /> component\n");
|
|
245
|
+
console.log(" Example:");
|
|
246
|
+
console.log(" import { AutoshipProvider, AutoshipButton } from '@autoship/react';");
|
|
247
|
+
console.log("");
|
|
248
|
+
console.log(" function App() {");
|
|
249
|
+
console.log(" return (");
|
|
250
|
+
console.log(" <AutoshipProvider");
|
|
251
|
+
console.log(" supabaseUrl={process.env.SUPABASE_URL}");
|
|
252
|
+
console.log(" supabaseAnonKey={process.env.SUPABASE_ANON_KEY}");
|
|
253
|
+
console.log(" >");
|
|
254
|
+
console.log(" <YourApp />");
|
|
255
|
+
console.log(" <AutoshipButton />");
|
|
256
|
+
console.log(" </AutoshipProvider>");
|
|
257
|
+
console.log(" );");
|
|
258
|
+
console.log(" }\n");
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
console.log("\n Some tables are missing. Please run the migration SQL.");
|
|
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);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
export async function run(args) {
|
|
269
|
+
const options = parseArgs(args);
|
|
270
|
+
try {
|
|
271
|
+
// Load migrations from the bundled files
|
|
272
|
+
const migrationSql = loadMigrations();
|
|
273
|
+
const { url, serviceKey } = await getCredentials(options);
|
|
274
|
+
validateCredentials(url, serviceKey);
|
|
275
|
+
await runMigration(url, serviceKey, migrationSql);
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
console.error("\n Unexpected error:", error);
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":""}
|