@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.
Files changed (50) hide show
  1. package/dist/AutoshipButton.d.ts +7 -0
  2. package/dist/AutoshipButton.d.ts.map +1 -0
  3. package/dist/AutoshipButton.js +67 -0
  4. package/dist/AutoshipProvider.d.ts +15 -0
  5. package/dist/AutoshipProvider.d.ts.map +1 -0
  6. package/dist/AutoshipProvider.js +15 -0
  7. package/dist/QuestionDialog.d.ts +9 -0
  8. package/dist/QuestionDialog.d.ts.map +1 -0
  9. package/dist/QuestionDialog.js +85 -0
  10. package/dist/SnapdevButton.d.ts +7 -0
  11. package/dist/SnapdevButton.d.ts.map +1 -0
  12. package/dist/SnapdevButton.js +67 -0
  13. package/dist/SnapdevProvider.d.ts +15 -0
  14. package/dist/SnapdevProvider.d.ts.map +1 -0
  15. package/dist/SnapdevProvider.js +15 -0
  16. package/dist/TaskDetailDialog.d.ts +9 -0
  17. package/dist/TaskDetailDialog.d.ts.map +1 -0
  18. package/dist/TaskDetailDialog.js +172 -0
  19. package/dist/TaskDialog.d.ts +7 -0
  20. package/dist/TaskDialog.d.ts.map +1 -0
  21. package/dist/TaskDialog.js +85 -0
  22. package/dist/TaskList.d.ts +23 -0
  23. package/dist/TaskList.d.ts.map +1 -0
  24. package/dist/TaskList.js +126 -0
  25. package/dist/cli/autoship.d.ts +3 -0
  26. package/dist/cli/autoship.d.ts.map +1 -0
  27. package/dist/cli/autoship.js +37 -0
  28. package/dist/cli/init.d.ts +2 -0
  29. package/dist/cli/init.d.ts.map +1 -0
  30. package/dist/cli/init.js +281 -0
  31. package/dist/cli/setup.d.ts +3 -0
  32. package/dist/cli/setup.d.ts.map +1 -0
  33. package/dist/cli/setup.js +284 -0
  34. package/dist/cli/snapdev.d.ts +3 -0
  35. package/dist/cli/snapdev.d.ts.map +1 -0
  36. package/dist/cli/snapdev.js +42 -0
  37. package/dist/hooks/useAutoship.d.ts +18 -0
  38. package/dist/hooks/useAutoship.d.ts.map +1 -0
  39. package/dist/hooks/useAutoship.js +23 -0
  40. package/dist/hooks/useSnapdev.d.ts +18 -0
  41. package/dist/hooks/useSnapdev.d.ts.map +1 -0
  42. package/dist/hooks/useSnapdev.js +23 -0
  43. package/dist/hooks/useTasks.d.ts +8 -0
  44. package/dist/hooks/useTasks.d.ts.map +1 -0
  45. package/dist/hooks/useTasks.js +57 -0
  46. package/dist/index.d.ts +17 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +8 -0
  49. package/dist/migrations/20250118000000_initial_schema.sql +143 -0
  50. package/package.json +46 -0
@@ -0,0 +1,284 @@
1
+ #!/usr/bin/env node
2
+ import { createClient } from "@supabase/supabase-js";
3
+ import * as fs from "fs";
4
+ import * as path from "path";
5
+ import * as readline from "readline";
6
+ import { fileURLToPath } from "url";
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ function loadMigrations() {
10
+ // Migrations are copied to dist/migrations/ at build time
11
+ const migrationsDir = path.join(__dirname, "..", "migrations");
12
+ if (!fs.existsSync(migrationsDir)) {
13
+ console.error("\n Error: Migrations directory not found.");
14
+ console.error(" Expected at:", migrationsDir);
15
+ process.exit(1);
16
+ }
17
+ const migrationFiles = fs.readdirSync(migrationsDir)
18
+ .filter(f => f.endsWith(".sql"))
19
+ .sort(); // Sort to ensure correct order (files are named with timestamps)
20
+ if (migrationFiles.length === 0) {
21
+ console.error("\n Error: No migration files found in", migrationsDir);
22
+ process.exit(1);
23
+ }
24
+ // Concatenate all migrations in order
25
+ const migrations = migrationFiles.map(file => {
26
+ const filePath = path.join(migrationsDir, file);
27
+ const content = fs.readFileSync(filePath, "utf-8");
28
+ return `-- Migration: ${file}\n${content}`;
29
+ }).join("\n\n");
30
+ return migrations;
31
+ }
32
+ function parseArgs() {
33
+ const args = process.argv.slice(2);
34
+ const options = {};
35
+ for (let i = 0; i < args.length; i++) {
36
+ const arg = args[i];
37
+ if (arg === "--db-url" && args[i + 1]) {
38
+ options.supabaseUrl = args[++i];
39
+ }
40
+ else if (arg === "--service-key" && args[i + 1]) {
41
+ options.supabaseServiceKey = args[++i];
42
+ }
43
+ else if (arg === "--non-interactive" || arg === "-y") {
44
+ options.nonInteractive = true;
45
+ }
46
+ else if (arg === "--help" || arg === "-h") {
47
+ printHelp();
48
+ process.exit(0);
49
+ }
50
+ }
51
+ return options;
52
+ }
53
+ function printHelp() {
54
+ console.log(`
55
+ @snapdev/react setup - Initialize Snapdev database schema
56
+
57
+ Usage:
58
+ npx snapdev-setup [options]
59
+
60
+ Options:
61
+ --db-url <url> Supabase project URL
62
+ --service-key <key> Supabase service role key
63
+ -y, --non-interactive Skip confirmation prompts
64
+ -h, --help Show this help message
65
+
66
+ Environment Variables:
67
+ SUPABASE_URL Supabase project URL (fallback)
68
+ SUPABASE_SERVICE_KEY Supabase service role key (fallback)
69
+
70
+ Examples:
71
+ # Interactive mode (prompts for credentials)
72
+ npx snapdev-setup
73
+
74
+ # With command line arguments
75
+ npx snapdev-setup --db-url https://xxx.supabase.co --service-key eyJ...
76
+
77
+ # Using environment variables
78
+ SUPABASE_URL=https://xxx.supabase.co SUPABASE_SERVICE_KEY=eyJ... npx snapdev-setup
79
+ `);
80
+ }
81
+ function createReadlineInterface() {
82
+ return readline.createInterface({
83
+ input: process.stdin,
84
+ output: process.stdout,
85
+ });
86
+ }
87
+ async function prompt(rl, question) {
88
+ return new Promise((resolve) => {
89
+ rl.question(question, (answer) => {
90
+ resolve(answer.trim());
91
+ });
92
+ });
93
+ }
94
+ async function promptSecret(rl, question) {
95
+ return new Promise((resolve) => {
96
+ process.stdout.write(question);
97
+ const stdin = process.stdin;
98
+ const wasRaw = stdin.isRaw;
99
+ if (stdin.isTTY) {
100
+ stdin.setRawMode(true);
101
+ }
102
+ let input = "";
103
+ const onData = (char) => {
104
+ const c = char.toString();
105
+ if (c === "\n" || c === "\r") {
106
+ if (stdin.isTTY) {
107
+ stdin.setRawMode(wasRaw ?? false);
108
+ }
109
+ stdin.removeListener("data", onData);
110
+ process.stdout.write("\n");
111
+ resolve(input);
112
+ }
113
+ else if (c === "\u0003") {
114
+ // Ctrl+C
115
+ process.exit(1);
116
+ }
117
+ else if (c === "\u007F" || c === "\b") {
118
+ // Backspace
119
+ if (input.length > 0) {
120
+ input = input.slice(0, -1);
121
+ }
122
+ }
123
+ else {
124
+ input += c;
125
+ process.stdout.write("*");
126
+ }
127
+ };
128
+ stdin.on("data", onData);
129
+ stdin.resume();
130
+ });
131
+ }
132
+ async function getCredentials(options) {
133
+ let url = options.supabaseUrl || process.env.SUPABASE_URL || "";
134
+ let serviceKey = options.supabaseServiceKey || process.env.SUPABASE_SERVICE_KEY || "";
135
+ if (url && serviceKey) {
136
+ return { url, serviceKey };
137
+ }
138
+ const rl = createReadlineInterface();
139
+ try {
140
+ console.log("\n Snapdev Database Setup\n");
141
+ console.log(" This will create the required tables in your Supabase database.\n");
142
+ if (!url) {
143
+ url = await prompt(rl, " Supabase URL: ");
144
+ }
145
+ else {
146
+ console.log(` Supabase URL: ${url}`);
147
+ }
148
+ if (!serviceKey) {
149
+ serviceKey = await promptSecret(rl, " Supabase Service Key: ");
150
+ }
151
+ else {
152
+ console.log(" Supabase Service Key: [provided]");
153
+ }
154
+ return { url, serviceKey };
155
+ }
156
+ finally {
157
+ rl.close();
158
+ }
159
+ }
160
+ function validateCredentials(url, serviceKey) {
161
+ if (!url) {
162
+ console.error("\n Error: Supabase URL is required");
163
+ process.exit(1);
164
+ }
165
+ if (!serviceKey) {
166
+ console.error("\n Error: Supabase Service Key is required");
167
+ process.exit(1);
168
+ }
169
+ try {
170
+ new URL(url);
171
+ }
172
+ catch {
173
+ console.error("\n Error: Invalid Supabase URL format");
174
+ process.exit(1);
175
+ }
176
+ if (!serviceKey.startsWith("eyJ")) {
177
+ console.error("\n Error: Service key should be a JWT (starts with 'eyJ')");
178
+ console.error(" Make sure you're using the service_role key, not the anon key.");
179
+ process.exit(1);
180
+ }
181
+ }
182
+ async function runMigration(url, serviceKey, migrationSql) {
183
+ console.log("\n Connecting to Supabase...");
184
+ const supabase = createClient(url, serviceKey, {
185
+ auth: {
186
+ autoRefreshToken: false,
187
+ persistSession: false,
188
+ },
189
+ });
190
+ console.log(" Checking database schema...\n");
191
+ // First, let's verify the connection by trying to query
192
+ const { error: connectionError } = await supabase
193
+ .from("agent_tasks")
194
+ .select("id")
195
+ .limit(1);
196
+ if (connectionError && connectionError.code === "42P01") {
197
+ // Table doesn't exist - we need to create it
198
+ // Since we can't run arbitrary SQL via the REST API, we'll provide instructions
199
+ console.log(" Tables don't exist yet.\n");
200
+ console.log(" ============================================================");
201
+ console.log(" Supabase REST API doesn't support direct SQL execution.");
202
+ console.log(" Please run the migration manually using one of these options:");
203
+ console.log(" ============================================================\n");
204
+ console.log(" Option 1: Supabase Dashboard");
205
+ console.log(" 1. Go to your Supabase project dashboard");
206
+ console.log(" 2. Navigate to SQL Editor");
207
+ console.log(" 3. Copy and paste the contents of: ./snapdev-migration.sql\n");
208
+ console.log(" Option 2: Supabase CLI");
209
+ console.log(" 1. Install Supabase CLI: npm install -g supabase");
210
+ console.log(" 2. Link your project: supabase link --project-ref YOUR_PROJECT_REF");
211
+ console.log(" 3. Copy snapdev-migration.sql to supabase/migrations/");
212
+ console.log(" 4. Run: supabase db push\n");
213
+ // Write the migration file locally for convenience
214
+ const outputPath = path.join(process.cwd(), "snapdev-migration.sql");
215
+ fs.writeFileSync(outputPath, migrationSql.trim());
216
+ console.log(` Migration SQL saved to: ${outputPath}\n`);
217
+ console.log(" After running the migration, run this setup command again to verify.\n");
218
+ process.exit(0);
219
+ }
220
+ else if (connectionError) {
221
+ console.error(`\n Error connecting to Supabase: ${connectionError.message}`);
222
+ process.exit(1);
223
+ }
224
+ // Tables exist - verify the schema
225
+ console.log(" Verifying database schema...\n");
226
+ const tables = ["agent_tasks", "task_categories", "task_category_assignments", "task_questions"];
227
+ let allTablesExist = true;
228
+ for (const table of tables) {
229
+ const { error } = await supabase.from(table).select("*").limit(0);
230
+ if (error && error.code === "42P01") {
231
+ console.log(` [ ] ${table} - NOT FOUND`);
232
+ allTablesExist = false;
233
+ }
234
+ else if (error) {
235
+ console.log(` [?] ${table} - Error: ${error.message}`);
236
+ }
237
+ else {
238
+ console.log(` [x] ${table}`);
239
+ }
240
+ }
241
+ if (allTablesExist) {
242
+ console.log("\n All tables exist. Your database is ready!\n");
243
+ console.log(" Next steps:");
244
+ console.log(" 1. Add SUPABASE_URL and SUPABASE_ANON_KEY to your app's environment");
245
+ console.log(" 2. Wrap your app with <SnapdevProvider>");
246
+ console.log(" 3. Add the <SnapdevButton /> component\n");
247
+ console.log(" Example:");
248
+ console.log(" import { SnapdevProvider, SnapdevButton } from '@snapdev/react';");
249
+ console.log("");
250
+ console.log(" function App() {");
251
+ console.log(" return (");
252
+ console.log(" <SnapdevProvider");
253
+ console.log(" supabaseUrl={process.env.SUPABASE_URL}");
254
+ console.log(" supabaseAnonKey={process.env.SUPABASE_ANON_KEY}");
255
+ console.log(" >");
256
+ console.log(" <YourApp />");
257
+ console.log(" <SnapdevButton />");
258
+ console.log(" </SnapdevProvider>");
259
+ console.log(" );");
260
+ console.log(" }\n");
261
+ }
262
+ else {
263
+ console.log("\n Some tables are missing. Please run the migration SQL.");
264
+ const outputPath = path.join(process.cwd(), "snapdev-migration.sql");
265
+ fs.writeFileSync(outputPath, migrationSql.trim());
266
+ console.log(` Migration SQL saved to: ${outputPath}\n`);
267
+ process.exit(1);
268
+ }
269
+ }
270
+ async function main() {
271
+ const options = parseArgs();
272
+ try {
273
+ // Load migrations from the bundled files
274
+ const migrationSql = loadMigrations();
275
+ const { url, serviceKey } = await getCredentials(options);
276
+ validateCredentials(url, serviceKey);
277
+ await runMigration(url, serviceKey, migrationSql);
278
+ }
279
+ catch (error) {
280
+ console.error("\n Unexpected error:", error);
281
+ process.exit(1);
282
+ }
283
+ }
284
+ main();
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=snapdev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapdev.d.ts","sourceRoot":"","sources":["../../src/cli/snapdev.ts"],"names":[],"mappings":""}
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath } from "url";
3
+ import * as path from "path";
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = path.dirname(__filename);
6
+ function printHelp() {
7
+ console.log(`
8
+ snapdev - CLI for @snapdev/react
9
+
10
+ Usage:
11
+ npx snapdev <command> [options]
12
+
13
+ Commands:
14
+ init Initialize Snapdev database schema in your Supabase project
15
+
16
+ Options:
17
+ -h, --help Show this help message
18
+
19
+ Run 'npx snapdev <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 === "--help" || command === "-h") {
26
+ printHelp();
27
+ process.exit(0);
28
+ }
29
+ switch (command) {
30
+ case "init": {
31
+ // Dynamically import and run the init command
32
+ const initModule = await import("./init.js");
33
+ await initModule.run(args.slice(1));
34
+ break;
35
+ }
36
+ default:
37
+ console.error(`\n Unknown command: ${command}`);
38
+ console.error(` Run 'npx snapdev --help' to see available commands.\n`);
39
+ process.exit(1);
40
+ }
41
+ }
42
+ main();
@@ -0,0 +1,18 @@
1
+ export interface SubmitTaskOptions {
2
+ title: string;
3
+ description: string;
4
+ priority?: number;
5
+ }
6
+ export interface SubmittedTask {
7
+ id: string;
8
+ title: string;
9
+ description: string;
10
+ priority: number;
11
+ status: string;
12
+ submitted_by: string | null;
13
+ created_at: string;
14
+ }
15
+ export declare function useAutoship(): {
16
+ submitTask: ({ title, description, priority, }: SubmitTaskOptions) => Promise<SubmittedTask>;
17
+ };
18
+ //# sourceMappingURL=useAutoship.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAutoship.d.ts","sourceRoot":"","sources":["../../src/hooks/useAutoship.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,WAAW;oDAOtB,iBAAiB,KAAG,OAAO,CAAC,aAAa,CAAC;EAqB9C"}
@@ -0,0 +1,23 @@
1
+ import { useAutoshipContext } from "../AutoshipProvider";
2
+ export function useAutoship() {
3
+ const { supabase, userId } = useAutoshipContext();
4
+ const submitTask = async ({ title, description, priority = 0, }) => {
5
+ const id = `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
6
+ const { data, error } = await supabase
7
+ .from("agent_tasks")
8
+ .insert({
9
+ id,
10
+ title,
11
+ description,
12
+ priority,
13
+ status: "pending",
14
+ submitted_by: userId || null,
15
+ })
16
+ .select()
17
+ .single();
18
+ if (error)
19
+ throw error;
20
+ return data;
21
+ };
22
+ return { submitTask };
23
+ }
@@ -0,0 +1,18 @@
1
+ export interface SubmitTaskOptions {
2
+ title: string;
3
+ description: string;
4
+ priority?: number;
5
+ }
6
+ export interface SubmittedTask {
7
+ id: string;
8
+ title: string;
9
+ description: string;
10
+ priority: number;
11
+ status: string;
12
+ submitted_by: string | null;
13
+ created_at: string;
14
+ }
15
+ export declare function useSnapdev(): {
16
+ submitTask: ({ title, description, priority, }: SubmitTaskOptions) => Promise<SubmittedTask>;
17
+ };
18
+ //# sourceMappingURL=useSnapdev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSnapdev.d.ts","sourceRoot":"","sources":["../../src/hooks/useSnapdev.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,UAAU;oDAOrB,iBAAiB,KAAG,OAAO,CAAC,aAAa,CAAC;EAqB9C"}
@@ -0,0 +1,23 @@
1
+ import { useSnapdevContext } from "../SnapdevProvider";
2
+ export function useSnapdev() {
3
+ const { supabase, userId } = useSnapdevContext();
4
+ const submitTask = async ({ title, description, priority = 0, }) => {
5
+ const id = `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
6
+ const { data, error } = await supabase
7
+ .from("agent_tasks")
8
+ .insert({
9
+ id,
10
+ title,
11
+ description,
12
+ priority,
13
+ status: "pending",
14
+ submitted_by: userId || null,
15
+ })
16
+ .select()
17
+ .single();
18
+ if (error)
19
+ throw error;
20
+ return data;
21
+ };
22
+ return { submitTask };
23
+ }
@@ -0,0 +1,8 @@
1
+ import type { Task } from "../TaskList";
2
+ export interface UseTasksResult {
3
+ tasks: Task[];
4
+ loading: boolean;
5
+ refresh: () => Promise<void>;
6
+ }
7
+ export declare function useTasks(): UseTasksResult;
8
+ //# sourceMappingURL=useTasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTasks.d.ts","sourceRoot":"","sources":["../../src/hooks/useTasks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,wBAAgB,QAAQ,IAAI,cAAc,CA8DzC"}
@@ -0,0 +1,57 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { useAutoshipContext } from "../AutoshipProvider";
3
+ export function useTasks() {
4
+ const { supabase, userId } = useAutoshipContext();
5
+ const [tasks, setTasks] = useState([]);
6
+ const [loading, setLoading] = useState(true);
7
+ const loadTasks = useCallback(async () => {
8
+ setLoading(true);
9
+ try {
10
+ let query = supabase
11
+ .from("agent_tasks")
12
+ .select(`
13
+ *,
14
+ task_questions (
15
+ id,
16
+ question,
17
+ answer,
18
+ asked_at,
19
+ answered_at
20
+ )
21
+ `)
22
+ .order("created_at", { ascending: false });
23
+ if (userId) {
24
+ query = query.eq("submitted_by", userId);
25
+ }
26
+ const { data, error } = await query;
27
+ if (error)
28
+ throw error;
29
+ setTasks(data || []);
30
+ }
31
+ catch (err) {
32
+ console.error("Failed to load tasks:", err);
33
+ }
34
+ finally {
35
+ setLoading(false);
36
+ }
37
+ }, [supabase, userId]);
38
+ useEffect(() => {
39
+ loadTasks();
40
+ // Subscribe to realtime updates
41
+ const channel = supabase
42
+ .channel("agent_tasks_changes")
43
+ .on("postgres_changes", {
44
+ event: "*",
45
+ schema: "public",
46
+ table: "agent_tasks",
47
+ filter: userId ? `submitted_by=eq.${userId}` : undefined,
48
+ }, () => {
49
+ loadTasks();
50
+ })
51
+ .subscribe();
52
+ return () => {
53
+ channel.unsubscribe();
54
+ };
55
+ }, [supabase, userId, loadTasks]);
56
+ return { tasks, loading, refresh: loadTasks };
57
+ }
@@ -0,0 +1,17 @@
1
+ export { AutoshipProvider, useAutoshipContext } from "./AutoshipProvider";
2
+ export type { AutoshipContextValue, AutoshipProviderProps } from "./AutoshipProvider";
3
+ export { AutoshipButton } from "./AutoshipButton";
4
+ export type { AutoshipButtonProps } from "./AutoshipButton";
5
+ export { TaskDialog } from "./TaskDialog";
6
+ export type { TaskDialogProps } from "./TaskDialog";
7
+ export { TaskList } from "./TaskList";
8
+ export type { Question, Task, TaskListProps } from "./TaskList";
9
+ export { TaskDetailDialog } from "./TaskDetailDialog";
10
+ export type { TaskDetailDialogProps } from "./TaskDetailDialog";
11
+ export { QuestionDialog } from "./QuestionDialog";
12
+ export type { QuestionDialogProps } from "./QuestionDialog";
13
+ export { useAutoship } from "./hooks/useAutoship";
14
+ export type { SubmitTaskOptions, SubmittedTask } from "./hooks/useAutoship";
15
+ export { useTasks } from "./hooks/useTasks";
16
+ export type { UseTasksResult } from "./hooks/useTasks";
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEtF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE5E,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { AutoshipProvider, useAutoshipContext } from "./AutoshipProvider";
2
+ export { AutoshipButton } from "./AutoshipButton";
3
+ export { TaskDialog } from "./TaskDialog";
4
+ export { TaskList } from "./TaskList";
5
+ export { TaskDetailDialog } from "./TaskDetailDialog";
6
+ export { QuestionDialog } from "./QuestionDialog";
7
+ export { useAutoship } from "./hooks/useAutoship";
8
+ export { useTasks } from "./hooks/useTasks";
@@ -0,0 +1,143 @@
1
+ -- Autoship MCP Initial Schema
2
+ -- Tables: agent_tasks, task_categories, task_category_assignments, task_questions
3
+
4
+ -- =============================================================================
5
+ -- Categories table (for tagging tasks)
6
+ -- =============================================================================
7
+ CREATE TABLE IF NOT EXISTS task_categories (
8
+ id TEXT PRIMARY KEY,
9
+ name TEXT NOT NULL UNIQUE,
10
+ description TEXT,
11
+ color TEXT, -- Hex color for UI display (e.g., '#FF5733')
12
+ created_at TIMESTAMPTZ DEFAULT NOW()
13
+ );
14
+
15
+ -- =============================================================================
16
+ -- Agent tasks table (main tasks table)
17
+ -- =============================================================================
18
+ CREATE TABLE IF NOT EXISTS agent_tasks (
19
+ id TEXT PRIMARY KEY,
20
+ title TEXT NOT NULL,
21
+ description TEXT NOT NULL,
22
+ priority INTEGER DEFAULT 0, -- Higher = more urgent
23
+ status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'in_progress', 'complete', 'failed', 'blocked', 'needs_info')),
24
+ branch_name TEXT,
25
+ pr_url TEXT,
26
+ notes TEXT,
27
+ error_message TEXT,
28
+ submitted_by TEXT, -- User ID who submitted the task (for React components)
29
+ created_at TIMESTAMPTZ DEFAULT NOW(),
30
+ updated_at TIMESTAMPTZ DEFAULT NOW(),
31
+ started_at TIMESTAMPTZ,
32
+ completed_at TIMESTAMPTZ
33
+ );
34
+
35
+ -- Index for finding pending tasks quickly
36
+ CREATE INDEX idx_agent_tasks_status_priority ON agent_tasks(status, priority DESC);
37
+
38
+ -- Index for user's tasks (React components)
39
+ CREATE INDEX idx_agent_tasks_submitted_by ON agent_tasks(submitted_by);
40
+
41
+ -- =============================================================================
42
+ -- Category assignments (many-to-many relationship)
43
+ -- =============================================================================
44
+ CREATE TABLE IF NOT EXISTS task_category_assignments (
45
+ task_id TEXT NOT NULL REFERENCES agent_tasks(id) ON DELETE CASCADE,
46
+ category_id TEXT NOT NULL REFERENCES task_categories(id) ON DELETE CASCADE,
47
+ created_at TIMESTAMPTZ DEFAULT NOW(),
48
+ PRIMARY KEY (task_id, category_id)
49
+ );
50
+
51
+ CREATE INDEX idx_task_category_assignments_category ON task_category_assignments(category_id);
52
+
53
+ -- =============================================================================
54
+ -- Questions and answers for tasks
55
+ -- =============================================================================
56
+ CREATE TABLE IF NOT EXISTS task_questions (
57
+ id TEXT PRIMARY KEY,
58
+ task_id TEXT NOT NULL REFERENCES agent_tasks(id) ON DELETE CASCADE,
59
+ question TEXT NOT NULL,
60
+ answer TEXT, -- NULL until answered
61
+ asked_by TEXT DEFAULT 'agent', -- 'agent' or 'user'
62
+ asked_at TIMESTAMPTZ DEFAULT NOW(),
63
+ answered_at TIMESTAMPTZ
64
+ );
65
+
66
+ CREATE INDEX idx_task_questions_task ON task_questions(task_id);
67
+ CREATE INDEX idx_task_questions_unanswered ON task_questions(task_id) WHERE answer IS NULL;
68
+
69
+ -- =============================================================================
70
+ -- Trigger to update updated_at on agent_tasks
71
+ -- =============================================================================
72
+ CREATE OR REPLACE FUNCTION update_agent_tasks_updated_at()
73
+ RETURNS TRIGGER AS $$
74
+ BEGIN
75
+ NEW.updated_at = NOW();
76
+ RETURN NEW;
77
+ END;
78
+ $$ LANGUAGE plpgsql;
79
+
80
+ CREATE TRIGGER agent_tasks_updated_at
81
+ BEFORE UPDATE ON agent_tasks
82
+ FOR EACH ROW
83
+ EXECUTE FUNCTION update_agent_tasks_updated_at();
84
+
85
+ -- =============================================================================
86
+ -- Row Level Security
87
+ -- =============================================================================
88
+
89
+ -- Enable RLS on all tables
90
+ ALTER TABLE agent_tasks ENABLE ROW LEVEL SECURITY;
91
+ ALTER TABLE task_categories ENABLE ROW LEVEL SECURITY;
92
+ ALTER TABLE task_category_assignments ENABLE ROW LEVEL SECURITY;
93
+ ALTER TABLE task_questions ENABLE ROW LEVEL SECURITY;
94
+
95
+ -- Service role has full access (used by the MCP server)
96
+ CREATE POLICY "Service role has full access to agent_tasks"
97
+ ON agent_tasks FOR ALL USING (true) WITH CHECK (true);
98
+
99
+ CREATE POLICY "Service role has full access to task_categories"
100
+ ON task_categories FOR ALL USING (true) WITH CHECK (true);
101
+
102
+ CREATE POLICY "Service role has full access to task_category_assignments"
103
+ ON task_category_assignments FOR ALL USING (true) WITH CHECK (true);
104
+
105
+ CREATE POLICY "Service role has full access to task_questions"
106
+ ON task_questions FOR ALL USING (true) WITH CHECK (true);
107
+
108
+ -- =============================================================================
109
+ -- Policies for React components (using anon key)
110
+ -- =============================================================================
111
+
112
+ -- Users can view their own tasks or tasks without a submitter
113
+ CREATE POLICY "Users can view their own tasks"
114
+ ON agent_tasks FOR SELECT
115
+ USING (submitted_by IS NULL OR submitted_by = coalesce(auth.uid()::text, submitted_by));
116
+
117
+ -- Anyone can insert tasks
118
+ CREATE POLICY "Anyone can insert tasks"
119
+ ON agent_tasks FOR INSERT
120
+ WITH CHECK (true);
121
+
122
+ -- Users can update their own tasks (for answering questions)
123
+ CREATE POLICY "Users can update their own tasks"
124
+ ON agent_tasks FOR UPDATE
125
+ USING (submitted_by IS NULL OR submitted_by = coalesce(auth.uid()::text, submitted_by));
126
+
127
+ -- Users can view questions for their tasks
128
+ CREATE POLICY "Users can view questions for their tasks"
129
+ ON task_questions FOR SELECT
130
+ USING (EXISTS (
131
+ SELECT 1 FROM agent_tasks
132
+ WHERE agent_tasks.id = task_questions.task_id
133
+ AND (agent_tasks.submitted_by IS NULL OR agent_tasks.submitted_by = coalesce(auth.uid()::text, agent_tasks.submitted_by))
134
+ ));
135
+
136
+ -- Users can update questions (to provide answers)
137
+ CREATE POLICY "Users can update questions for their tasks"
138
+ ON task_questions FOR UPDATE
139
+ USING (EXISTS (
140
+ SELECT 1 FROM agent_tasks
141
+ WHERE agent_tasks.id = task_questions.task_id
142
+ AND (agent_tasks.submitted_by IS NULL OR agent_tasks.submitted_by = coalesce(auth.uid()::text, agent_tasks.submitted_by))
143
+ ));