@embeddables/cli 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.
Files changed (49) hide show
  1. package/.cursor/rules/embeddables-cli.md +679 -0
  2. package/README.md +37 -7
  3. package/dist/auth/index.d.ts +1 -1
  4. package/dist/auth/index.d.ts.map +1 -1
  5. package/dist/auth/index.js +5 -3
  6. package/dist/cli.js +42 -6
  7. package/dist/commands/branch.d.ts +4 -0
  8. package/dist/commands/branch.d.ts.map +1 -0
  9. package/dist/commands/branch.js +46 -0
  10. package/dist/commands/dev.d.ts +1 -1
  11. package/dist/commands/dev.d.ts.map +1 -1
  12. package/dist/commands/dev.js +48 -9
  13. package/dist/commands/init.d.ts +5 -0
  14. package/dist/commands/init.d.ts.map +1 -0
  15. package/dist/commands/init.js +245 -0
  16. package/dist/commands/pull.d.ts +1 -1
  17. package/dist/commands/pull.d.ts.map +1 -1
  18. package/dist/commands/pull.js +104 -3
  19. package/dist/commands/save.d.ts +8 -0
  20. package/dist/commands/save.d.ts.map +1 -0
  21. package/dist/commands/save.js +269 -0
  22. package/dist/compiler/index.d.ts.map +1 -1
  23. package/dist/compiler/index.js +4 -0
  24. package/dist/compiler/reverse.d.ts.map +1 -1
  25. package/dist/compiler/reverse.js +4 -10
  26. package/dist/config/index.d.ts +23 -0
  27. package/dist/config/index.d.ts.map +1 -0
  28. package/dist/config/index.js +42 -0
  29. package/dist/constants.d.ts +7 -0
  30. package/dist/constants.d.ts.map +1 -0
  31. package/dist/constants.js +6 -0
  32. package/dist/helpers/dates.d.ts +5 -0
  33. package/dist/helpers/dates.d.ts.map +1 -0
  34. package/dist/helpers/dates.js +7 -0
  35. package/dist/prompts/branches.d.ts +20 -0
  36. package/dist/prompts/branches.d.ts.map +1 -0
  37. package/dist/prompts/branches.js +89 -0
  38. package/dist/prompts/embeddables.d.ts +41 -0
  39. package/dist/prompts/embeddables.d.ts.map +1 -0
  40. package/dist/prompts/embeddables.js +161 -0
  41. package/dist/prompts/index.d.ts +7 -0
  42. package/dist/prompts/index.d.ts.map +1 -0
  43. package/dist/prompts/index.js +4 -0
  44. package/dist/prompts/projects.d.ts +22 -0
  45. package/dist/prompts/projects.d.ts.map +1 -0
  46. package/dist/prompts/projects.js +85 -0
  47. package/dist/proxy/server.d.ts.map +1 -1
  48. package/dist/proxy/server.js +10 -4
  49. package/package.json +6 -5
@@ -0,0 +1,89 @@
1
+ import pc from 'picocolors';
2
+ import prompts from 'prompts';
3
+ import { getAuthenticatedSupabaseClient } from '../auth/index.js';
4
+ import { BranchStatus } from '../constants.js';
5
+ import { formatDate } from '../helpers/dates.js';
6
+ /**
7
+ * Fetch all branches for an embeddable from Supabase
8
+ */
9
+ export async function fetchBranches(flowId) {
10
+ const supabase = await getAuthenticatedSupabaseClient();
11
+ if (!supabase) {
12
+ return [];
13
+ }
14
+ try {
15
+ const { data, error } = await supabase
16
+ .from('branches')
17
+ .select('id, name, status, created_at, origin_version, origin_branch')
18
+ .eq('flow_id', flowId)
19
+ .order('created_at', { ascending: false });
20
+ if (error) {
21
+ console.warn(pc.yellow(`Could not fetch branches: ${error.message}`));
22
+ return [];
23
+ }
24
+ return (data || []).map((row) => ({
25
+ id: row.id,
26
+ name: row.name,
27
+ status: row.status,
28
+ created_at: row.created_at,
29
+ origin_version: row.origin_version,
30
+ origin_branch: row.origin_branch,
31
+ }));
32
+ }
33
+ catch (err) {
34
+ console.warn(pc.yellow(`Could not fetch branches: ${err}`));
35
+ return [];
36
+ }
37
+ }
38
+ /**
39
+ * Prompt the user to select a branch
40
+ * Returns null if user selects "main" or cancels
41
+ * The "main" option is always included at the top
42
+ */
43
+ export async function promptForBranch(branches) {
44
+ // Separate active and merged branches
45
+ const activeBranches = branches.filter((b) => b.status === BranchStatus.ACTIVE);
46
+ const mergedBranches = branches.filter((b) => b.status === BranchStatus.MERGED);
47
+ const choices = [];
48
+ // Add "main" option first
49
+ choices.push({
50
+ title: pc.bold('main'),
51
+ value: 'main',
52
+ description: 'Latest published version',
53
+ });
54
+ // Add active branches
55
+ for (const branch of activeBranches) {
56
+ const date = formatDate(branch.created_at);
57
+ choices.push({
58
+ title: branch.name,
59
+ value: branch.id,
60
+ description: `Active · Created ${date}`,
61
+ });
62
+ }
63
+ // Add merged branches (dimmed)
64
+ for (const branch of mergedBranches) {
65
+ const date = formatDate(branch.created_at);
66
+ choices.push({
67
+ title: pc.dim(branch.name),
68
+ value: branch.id,
69
+ description: pc.dim(`Merged · Created ${date}`),
70
+ });
71
+ }
72
+ const response = await prompts({
73
+ type: 'autocomplete',
74
+ name: 'branchId',
75
+ message: 'Select a branch:',
76
+ choices,
77
+ suggest: (input, choices) => Promise.resolve(choices.filter((c) => c.value === 'main' ||
78
+ (c.title?.toLowerCase().includes(input.toLowerCase()) ?? false) ||
79
+ String(c.value).toLowerCase().includes(input.toLowerCase()))),
80
+ }, {
81
+ onCancel: () => {
82
+ process.exit(0);
83
+ },
84
+ });
85
+ if (!response.branchId || response.branchId === 'main') {
86
+ return null;
87
+ }
88
+ return branches.find((b) => b.id === response.branchId) || null;
89
+ }
@@ -0,0 +1,41 @@
1
+ export interface EmbeddableInfo {
2
+ id: string;
3
+ title: string | null;
4
+ }
5
+ export interface EmbeddableMetadata {
6
+ title: string | null;
7
+ archived: boolean;
8
+ created_at: string | null;
9
+ }
10
+ export interface LocalEmbeddable {
11
+ id: string;
12
+ title: string | null;
13
+ }
14
+ export interface PromptForEmbeddableOptions {
15
+ /** Custom message for the prompt */
16
+ message?: string;
17
+ }
18
+ /**
19
+ * Fetch all embeddables for a project from Supabase
20
+ */
21
+ export declare function fetchProjectEmbeddables(projectId: string): Promise<EmbeddableInfo[]>;
22
+ /**
23
+ * Fetch metadata for a single embeddable from the flows table.
24
+ * Returns title, archived, and created_at from the DB (not from the version-specific embeddable.json).
25
+ */
26
+ export declare function fetchEmbeddableMetadata(embeddableId: string): Promise<EmbeddableMetadata | null>;
27
+ /**
28
+ * Prompt the user to select an embeddable from a project
29
+ * Returns null if no embeddables found or user cancels
30
+ */
31
+ export declare function promptForEmbeddable(projectId: string, options?: PromptForEmbeddableOptions): Promise<string | null>;
32
+ /**
33
+ * Discover embeddables in the local embeddables/ directory
34
+ */
35
+ export declare function discoverLocalEmbeddables(): Promise<LocalEmbeddable[]>;
36
+ /**
37
+ * Prompt the user to select a local embeddable
38
+ * Returns null if no embeddables found or user cancels
39
+ */
40
+ export declare function promptForLocalEmbeddable(options?: PromptForEmbeddableOptions): Promise<string | null>;
41
+ //# sourceMappingURL=embeddables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddables.d.ts","sourceRoot":"","sources":["../../src/prompts/embeddables.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAED,MAAM,WAAW,0BAA0B;IACzC,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA0B1F;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA2BpC;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuCxB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAqC3E;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuCxB"}
@@ -0,0 +1,161 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import pc from 'picocolors';
4
+ import prompts from 'prompts';
5
+ import { getAuthenticatedSupabaseClient } from '../auth/index.js';
6
+ /**
7
+ * Fetch all embeddables for a project from Supabase
8
+ */
9
+ export async function fetchProjectEmbeddables(projectId) {
10
+ const supabase = await getAuthenticatedSupabaseClient();
11
+ if (!supabase) {
12
+ return [];
13
+ }
14
+ try {
15
+ const { data, error } = await supabase
16
+ .from('flows')
17
+ .select('id, title')
18
+ .eq('project_id', projectId)
19
+ .order('title', { ascending: true });
20
+ if (error) {
21
+ console.warn(pc.yellow(`Could not fetch embeddables: ${error.message}`));
22
+ return [];
23
+ }
24
+ return (data || []).map((row) => ({
25
+ id: row.id,
26
+ title: row.title || null,
27
+ }));
28
+ }
29
+ catch (err) {
30
+ console.warn(pc.yellow(`Could not fetch embeddables: ${err}`));
31
+ return [];
32
+ }
33
+ }
34
+ /**
35
+ * Fetch metadata for a single embeddable from the flows table.
36
+ * Returns title, archived, and created_at from the DB (not from the version-specific embeddable.json).
37
+ */
38
+ export async function fetchEmbeddableMetadata(embeddableId) {
39
+ const supabase = await getAuthenticatedSupabaseClient();
40
+ if (!supabase) {
41
+ return null;
42
+ }
43
+ try {
44
+ const { data, error } = await supabase
45
+ .from('flows')
46
+ .select('title, archived, created_at')
47
+ .eq('id', embeddableId)
48
+ .single();
49
+ if (error) {
50
+ console.warn(pc.yellow(`Could not fetch embeddable metadata: ${error.message}`));
51
+ return null;
52
+ }
53
+ return {
54
+ title: data.title || null,
55
+ archived: data.archived ?? false,
56
+ created_at: data.created_at || null,
57
+ };
58
+ }
59
+ catch (err) {
60
+ console.warn(pc.yellow(`Could not fetch embeddable metadata: ${err}`));
61
+ return null;
62
+ }
63
+ }
64
+ /**
65
+ * Prompt the user to select an embeddable from a project
66
+ * Returns null if no embeddables found or user cancels
67
+ */
68
+ export async function promptForEmbeddable(projectId, options = {}) {
69
+ const { message = 'Select an embeddable:' } = options;
70
+ const embeddables = await fetchProjectEmbeddables(projectId);
71
+ if (embeddables.length === 0) {
72
+ console.log(pc.yellow('No embeddables found in this project.'));
73
+ return null;
74
+ }
75
+ const choices = embeddables.map((e) => ({
76
+ title: e.title || e.id,
77
+ description: e.id,
78
+ value: e.id,
79
+ }));
80
+ const response = await prompts({
81
+ type: 'autocomplete',
82
+ name: 'id',
83
+ message,
84
+ choices,
85
+ suggest: (input, choices) => Promise.resolve(choices.filter((c) => (c.title?.toLowerCase().includes(input.toLowerCase()) ?? false) ||
86
+ String(c.value).toLowerCase().includes(input.toLowerCase()))),
87
+ }, {
88
+ onCancel: () => {
89
+ process.exit(0);
90
+ },
91
+ });
92
+ return response.id || null;
93
+ }
94
+ /**
95
+ * Discover embeddables in the local embeddables/ directory
96
+ */
97
+ export async function discoverLocalEmbeddables() {
98
+ const embeddablesDir = 'embeddables';
99
+ if (!fs.existsSync(embeddablesDir)) {
100
+ return [];
101
+ }
102
+ const entries = fs.readdirSync(embeddablesDir, { withFileTypes: true });
103
+ const embeddables = [];
104
+ for (const entry of entries) {
105
+ if (!entry.isDirectory())
106
+ continue;
107
+ const id = entry.name;
108
+ const metadataPath = path.join(embeddablesDir, id, 'metadata.json');
109
+ let title = null;
110
+ if (fs.existsSync(metadataPath)) {
111
+ try {
112
+ const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf-8'));
113
+ title = metadata.title || null;
114
+ }
115
+ catch {
116
+ // Ignore JSON parse errors
117
+ }
118
+ }
119
+ embeddables.push({ id, title });
120
+ }
121
+ // Sort by title first, then by id
122
+ return embeddables.sort((a, b) => {
123
+ if (a.title && !b.title)
124
+ return -1;
125
+ if (!a.title && b.title)
126
+ return 1;
127
+ const aLabel = a.title || a.id;
128
+ const bLabel = b.title || b.id;
129
+ return aLabel.localeCompare(bLabel);
130
+ });
131
+ }
132
+ /**
133
+ * Prompt the user to select a local embeddable
134
+ * Returns null if no embeddables found or user cancels
135
+ */
136
+ export async function promptForLocalEmbeddable(options = {}) {
137
+ const { message = 'Select an embeddable:' } = options;
138
+ const embeddables = await discoverLocalEmbeddables();
139
+ if (embeddables.length === 0) {
140
+ console.error(pc.red('No embeddables found in the embeddables/ directory.'));
141
+ console.log(pc.gray('Run `embeddables pull` to pull an embeddable first.'));
142
+ return null;
143
+ }
144
+ const choices = embeddables.map((e) => ({
145
+ title: e.title ? `${e.title} (${e.id})` : e.id,
146
+ value: e.id,
147
+ }));
148
+ const response = await prompts({
149
+ type: 'autocomplete',
150
+ name: 'id',
151
+ message,
152
+ choices,
153
+ suggest: (input, choices) => Promise.resolve(choices.filter((c) => (c.title?.toLowerCase().includes(input.toLowerCase()) ?? false) ||
154
+ String(c.value).toLowerCase().includes(input.toLowerCase()))),
155
+ }, {
156
+ onCancel: () => {
157
+ process.exit(0);
158
+ },
159
+ });
160
+ return response.id || null;
161
+ }
@@ -0,0 +1,7 @@
1
+ export { fetchProjects, promptForProject } from './projects.js';
2
+ export type { ProjectInfo, PromptForProjectOptions } from './projects.js';
3
+ export { fetchProjectEmbeddables, fetchEmbeddableMetadata, promptForEmbeddable, discoverLocalEmbeddables, promptForLocalEmbeddable, } from './embeddables.js';
4
+ export type { EmbeddableInfo, EmbeddableMetadata, LocalEmbeddable, PromptForEmbeddableOptions, } from './embeddables.js';
5
+ export { fetchBranches, promptForBranch } from './branches.js';
6
+ export type { BranchInfo } from './branches.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAC/D,YAAY,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;AAEzE,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,kBAAkB,CAAA;AACzB,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,0BAA0B,GAC3B,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC9D,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA"}
@@ -0,0 +1,4 @@
1
+ // Centralized prompts for CLI commands
2
+ export { fetchProjects, promptForProject } from './projects.js';
3
+ export { fetchProjectEmbeddables, fetchEmbeddableMetadata, promptForEmbeddable, discoverLocalEmbeddables, promptForLocalEmbeddable, } from './embeddables.js';
4
+ export { fetchBranches, promptForBranch } from './branches.js';
@@ -0,0 +1,22 @@
1
+ export interface ProjectInfo {
2
+ id: string;
3
+ title: string | null;
4
+ org_id: string | null;
5
+ org_title: string | null;
6
+ }
7
+ export interface PromptForProjectOptions {
8
+ /** Include a "Skip for now" option (default: false) */
9
+ allowSkip?: boolean;
10
+ /** Custom message for the prompt (default: "Select a project:") */
11
+ message?: string;
12
+ }
13
+ /**
14
+ * Fetch all non-archived projects from Supabase
15
+ */
16
+ export declare function fetchProjects(): Promise<ProjectInfo[]>;
17
+ /**
18
+ * Prompt the user to select a project from the list
19
+ * Returns null if no projects found, user cancels, or user selects "skip"
20
+ */
21
+ export declare function promptForProject(options?: PromptForProjectOptions): Promise<ProjectInfo | null>;
22
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/prompts/projects.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,WAAW,uBAAuB;IACtC,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAwC5D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAqD7B"}
@@ -0,0 +1,85 @@
1
+ import pc from 'picocolors';
2
+ import prompts from 'prompts';
3
+ import { getAuthenticatedSupabaseClient } from '../auth/index.js';
4
+ /**
5
+ * Fetch all non-archived projects from Supabase
6
+ */
7
+ export async function fetchProjects() {
8
+ const supabase = await getAuthenticatedSupabaseClient();
9
+ if (!supabase) {
10
+ return [];
11
+ }
12
+ try {
13
+ const { data, error } = await supabase
14
+ .from('projects')
15
+ .select(`
16
+ id,
17
+ title,
18
+ group_id,
19
+ groups (
20
+ title
21
+ )
22
+ `)
23
+ .not('archived', 'is', 'true')
24
+ .order('title', { ascending: true });
25
+ if (error) {
26
+ console.warn(pc.yellow(`Could not fetch projects: ${error.message}`));
27
+ return [];
28
+ }
29
+ return (data || []).map((row) => ({
30
+ id: row.id,
31
+ title: row.title || null,
32
+ org_id: row.group_id || null,
33
+ org_title:
34
+ // For some reason, I can't get Supabase typings to return this as an object
35
+ // (not an array of objects) so I have to convert it manually
36
+ row.groups?.title || null,
37
+ }));
38
+ }
39
+ catch (err) {
40
+ console.warn(pc.yellow(`Could not fetch projects: ${err}`));
41
+ return [];
42
+ }
43
+ }
44
+ /**
45
+ * Prompt the user to select a project from the list
46
+ * Returns null if no projects found, user cancels, or user selects "skip"
47
+ */
48
+ export async function promptForProject(options = {}) {
49
+ const { allowSkip = false, message = 'Select a project:' } = options;
50
+ const projects = await fetchProjects();
51
+ if (projects.length === 0) {
52
+ console.log(pc.yellow('No projects found.'));
53
+ return null;
54
+ }
55
+ const choices = projects.map((p) => ({
56
+ title: p.title || p.id,
57
+ description: p.org_title ? `${p.org_title} (${p.id})` : p.id,
58
+ value: p.id,
59
+ }));
60
+ if (allowSkip) {
61
+ choices.push({
62
+ title: pc.dim('Skip for now'),
63
+ description: 'You can set this later',
64
+ value: '__skip__',
65
+ });
66
+ }
67
+ const response = await prompts({
68
+ type: 'autocomplete',
69
+ name: 'id',
70
+ message,
71
+ choices,
72
+ suggest: (input, choices) => Promise.resolve(choices.filter((c) => c.value === '__skip__' ||
73
+ (c.title?.toLowerCase().includes(input.toLowerCase()) ?? false) ||
74
+ String(c.value).toLowerCase().includes(input.toLowerCase()) ||
75
+ c.description?.toLowerCase().includes(input.toLowerCase()))),
76
+ }, {
77
+ onCancel: () => {
78
+ process.exit(0);
79
+ },
80
+ });
81
+ if (!response.id || response.id === '__skip__') {
82
+ return null;
83
+ }
84
+ return projects.find((p) => p.id === response.id) || null;
85
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAcA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;;GAqRA"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAqBA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;;GAqRA"}
@@ -1,6 +1,7 @@
1
1
  import express from 'express';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
4
5
  import { createProxyMiddleware } from 'http-proxy-middleware';
5
6
  import * as esbuild from 'esbuild';
6
7
  import chokidar from 'chokidar';
@@ -11,12 +12,17 @@ import { attachSse } from './sse.js';
11
12
  import { injectWorkbenchHtml } from './injectWorkbench.js';
12
13
  import { injectReloadScript } from './injectReload.js';
13
14
  import { injectApiInterceptor } from './injectApiInterceptor.js';
15
+ // Resolve the CLI package root so workbench paths work regardless of cwd.
16
+ // This file lives at src/proxy/server.ts (or dist/proxy/server.js when compiled),
17
+ // so the package root is two directories up.
18
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
+ const CLI_ROOT = path.resolve(__dirname, '..', '..');
14
20
  export async function startProxyServer(opts) {
15
21
  const app = express();
16
- // Use path relative to project root (where package.json lives)
17
- const workbenchEntry = path.join(process.cwd(), 'src', 'workbench', 'index.tsx');
18
- const workbenchDir = path.join(process.cwd(), 'src', 'workbench');
19
- const workbenchCssEntry = path.join(process.cwd(), 'src', 'workbench', 'workbench.css');
22
+ // Resolve workbench paths relative to the CLI package root, not process.cwd()
23
+ const workbenchEntry = path.join(CLI_ROOT, 'src', 'workbench', 'index.tsx');
24
+ const workbenchDir = path.join(CLI_ROOT, 'src', 'workbench');
25
+ const workbenchCssEntry = path.join(CLI_ROOT, 'src', 'workbench', 'workbench.css');
20
26
  // Build the Workbench bundle. If it fails, we log the error and
21
27
  // keep the proxy running; HTML injection will still happen but the script may 404.
22
28
  let workbenchBundle = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embeddables/cli",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "embeddables": "./bin/embeddables.mjs"
@@ -24,6 +24,7 @@
24
24
  "files": [
25
25
  "bin",
26
26
  "dist",
27
+ ".cursor",
27
28
  "README.md"
28
29
  ],
29
30
  "engines": {
@@ -47,19 +48,22 @@
47
48
  "@babel/parser": "^7.26.0",
48
49
  "@babel/traverse": "^7.26.0",
49
50
  "@supabase/supabase-js": "^2.39.0",
51
+ "@tailwindcss/postcss": "^4.1.18",
52
+ "autoprefixer": "^10.4.23",
50
53
  "chokidar": "^3.6.0",
51
54
  "commander": "^12.1.0",
52
55
  "cssjson": "^2.1.3",
56
+ "esbuild": "^0.25.0",
53
57
  "express": "^4.19.2",
54
58
  "fast-glob": "^3.3.2",
55
59
  "http-proxy-middleware": "^3.0.3",
56
60
  "picocolors": "^1.1.0",
61
+ "postcss": "^8.5.6",
57
62
  "prompts": "^2.4.2",
58
63
  "react": "^19.2.3",
59
64
  "react-dom": "^19.2.3"
60
65
  },
61
66
  "devDependencies": {
62
- "@tailwindcss/postcss": "^4.1.18",
63
67
  "@types/babel__generator": "^7.27.0",
64
68
  "@types/babel__traverse": "^7.28.0",
65
69
  "@types/express": "^4.17.21",
@@ -67,9 +71,6 @@
67
71
  "@types/prompts": "^2.4.9",
68
72
  "@types/react": "^19.2.8",
69
73
  "@vitest/coverage-v8": "^2.1.8",
70
- "autoprefixer": "^10.4.23",
71
- "esbuild": "^0.25.0",
72
- "postcss": "^8.5.6",
73
74
  "prettier": "^3.8.1",
74
75
  "tailwindcss": "^4.1.18",
75
76
  "tsx": "^4.19.2",