aigma 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # aigma
2
+
3
+ Generate Aigma canvas nodes from your terminal.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g aigma
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ # Sign in via your browser (Google or Apple)
15
+ aigma login
16
+
17
+ # Generate a node from a prompt
18
+ aigma create-node --prompt "Hero section for an AI photo editor"
19
+
20
+ # Save the generated HTML to a file
21
+ aigma create-node --prompt "Pricing section" --output pricing.html
22
+
23
+ # Get JSON on stdout for scripting
24
+ aigma create-node --prompt "Footer with links" --json
25
+ ```
26
+
27
+ Each `create-node` call:
28
+
29
+ 1. Generates a self-contained HTML fragment with Gemini.
30
+ 2. Publishes it to a public `https://aigma.co/p/{slug}` URL.
31
+ 3. Drops a draft node onto your Aigma canvas — it appears within ~5s
32
+ if you have https://aigma.co/nodes open, or on next load.
33
+
34
+ You can run the same command repeatedly to iterate — every call creates
35
+ a new node so you can compare variations side-by-side on the canvas.
36
+
37
+ ## Output rules
38
+
39
+ - Human-readable messages go to **stderr**.
40
+ - `--json` payload goes to **stdout** (one JSON object).
41
+ - Exit codes: `0` ok · `1` generic · `2` validation · `3` auth required.
42
+
43
+ ## Config
44
+
45
+ By default the CLI talks to production Aigma. To point at a different
46
+ environment, set:
47
+
48
+ ```bash
49
+ export AIGMA_SUPABASE_URL=https://your-project.supabase.co
50
+ export AIGMA_SUPABASE_ANON_KEY=...
51
+ export AIGMA_WEB_BASE=https://your-app.example.com
52
+ ```
53
+
54
+ Credentials are stored at `~/.aigma/credentials.json` (mode 0600).
55
+
56
+ ## License
57
+
58
+ MIT
@@ -0,0 +1,63 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { authenticatedClient } from '../lib/session.js';
3
+ import { FUNCTIONS_BASE, SUPABASE_ANON_KEY } from '../lib/config.js';
4
+ import { info, success, json, error, ExitCode } from '../lib/output.js';
5
+ export async function runCreateNode(opts) {
6
+ if (!opts.prompt || !opts.prompt.trim()) {
7
+ error('--prompt is required');
8
+ process.exit(ExitCode.Validation);
9
+ }
10
+ const auth = await authenticatedClient();
11
+ if (!auth) {
12
+ error('Not authenticated. Run `aigma login` first.');
13
+ process.exit(ExitCode.AuthRequired);
14
+ }
15
+ info('Generating node...');
16
+ let res;
17
+ try {
18
+ res = await fetch(`${FUNCTIONS_BASE}/cli-create-node`, {
19
+ method: 'POST',
20
+ headers: {
21
+ 'Content-Type': 'application/json',
22
+ Authorization: `Bearer ${auth.accessToken}`,
23
+ apikey: SUPABASE_ANON_KEY,
24
+ },
25
+ body: JSON.stringify({ prompt: opts.prompt }),
26
+ });
27
+ }
28
+ catch (err) {
29
+ error(`Network error: ${err.message}`);
30
+ process.exit(ExitCode.Generic);
31
+ }
32
+ let payload;
33
+ try {
34
+ payload = (await res.json());
35
+ }
36
+ catch {
37
+ error(`Server returned non-JSON response (status ${res.status})`);
38
+ process.exit(ExitCode.Generic);
39
+ }
40
+ if (!res.ok || payload.error) {
41
+ error(payload.error || `Request failed (status ${res.status})`);
42
+ process.exit(res.status === 401 ? ExitCode.AuthRequired : ExitCode.Generic);
43
+ }
44
+ if (!payload.html) {
45
+ error('Server response missing html');
46
+ process.exit(ExitCode.Generic);
47
+ }
48
+ if (opts.output) {
49
+ await fs.writeFile(opts.output, payload.html, 'utf8');
50
+ success(`HTML written to ${opts.output}`);
51
+ }
52
+ if (payload.public_url) {
53
+ info(` Public: ${payload.public_url}`);
54
+ }
55
+ if (payload.canvas_url) {
56
+ info(` Canvas: ${payload.canvas_url}`);
57
+ }
58
+ success('Node created');
59
+ if (opts.json) {
60
+ json(payload);
61
+ }
62
+ }
63
+ //# sourceMappingURL=create-node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-node.js","sourceRoot":"","sources":["../../src/commands/create-node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import { createServer } from 'node:http';
2
+ import { randomBytes } from 'node:crypto';
3
+ import open from 'open';
4
+ import { writeSession } from '../lib/session.js';
5
+ import { WEB_BASE } from '../lib/config.js';
6
+ import { info, success, json } from '../lib/output.js';
7
+ export async function runLogin(opts) {
8
+ const state = randomBytes(16).toString('hex');
9
+ const session = await new Promise((resolve, reject) => {
10
+ const server = createServer((req, res) => {
11
+ // CORS — accept any origin. The server is bound to 127.0.0.1 and
12
+ // protected by the per-request `state` token, so origin restriction
13
+ // adds no real security and breaks www↔apex redirects.
14
+ res.setHeader('Access-Control-Allow-Origin', '*');
15
+ res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
16
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
17
+ if (req.method === 'OPTIONS') {
18
+ res.writeHead(204).end();
19
+ return;
20
+ }
21
+ if (req.method !== 'POST' || !req.url?.startsWith('/callback')) {
22
+ res.writeHead(404).end();
23
+ return;
24
+ }
25
+ let body = '';
26
+ req.on('data', (chunk) => (body += chunk));
27
+ req.on('end', () => {
28
+ try {
29
+ const payload = JSON.parse(body);
30
+ if (payload.state !== state) {
31
+ res.writeHead(400, { 'Content-Type': 'application/json' });
32
+ res.end(JSON.stringify({ error: 'state mismatch' }));
33
+ return;
34
+ }
35
+ if (!payload.access_token || !payload.refresh_token || !payload.user) {
36
+ res.writeHead(400, { 'Content-Type': 'application/json' });
37
+ res.end(JSON.stringify({ error: 'missing fields' }));
38
+ return;
39
+ }
40
+ res.writeHead(200, { 'Content-Type': 'application/json' });
41
+ res.end(JSON.stringify({ ok: true }));
42
+ server.close();
43
+ resolve({
44
+ access_token: payload.access_token,
45
+ refresh_token: payload.refresh_token,
46
+ expires_at: payload.expires_at ?? 0,
47
+ user: { id: payload.user.id, email: payload.user.email ?? null },
48
+ });
49
+ }
50
+ catch (err) {
51
+ res.writeHead(400, { 'Content-Type': 'application/json' });
52
+ res.end(JSON.stringify({ error: 'invalid json' }));
53
+ reject(err);
54
+ }
55
+ });
56
+ });
57
+ server.on('error', reject);
58
+ // Bind to loopback only on a random free port.
59
+ server.listen(0, '127.0.0.1', () => {
60
+ const addr = server.address();
61
+ if (typeof addr !== 'object' || !addr) {
62
+ reject(new Error('failed to bind local server'));
63
+ return;
64
+ }
65
+ const port = addr.port;
66
+ const url = `${WEB_BASE}/cli-auth?port=${port}&state=${state}`;
67
+ info(`Opening browser to sign in...`);
68
+ info(` ${url}`);
69
+ open(url).catch(() => {
70
+ info(`If your browser didn't open, visit the URL above.`);
71
+ });
72
+ });
73
+ // 5 minute timeout.
74
+ setTimeout(() => {
75
+ server.close();
76
+ reject(new Error('Login timed out — please try again.'));
77
+ }, 5 * 60_000);
78
+ });
79
+ await writeSession(session);
80
+ success(`Signed in as ${session.user.email ?? session.user.id}`);
81
+ if (opts.json) {
82
+ json({ ok: true, user: session.user });
83
+ }
84
+ }
85
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { runLogin } from './commands/login.js';
4
+ import { runCreateNode } from './commands/create-node.js';
5
+ import { exitWith } from './lib/output.js';
6
+ const program = new Command();
7
+ program
8
+ .name('aigma')
9
+ .description('Aigma CLI — generate canvas nodes from your terminal')
10
+ .version('0.1.0');
11
+ program
12
+ .command('login')
13
+ .description('Sign in to Aigma via your browser')
14
+ .option('--json', 'output JSON on stdout')
15
+ .action(async (opts) => {
16
+ try {
17
+ await runLogin({ json: !!opts.json });
18
+ }
19
+ catch (err) {
20
+ exitWith(1, err.message);
21
+ }
22
+ });
23
+ program
24
+ .command('create-node')
25
+ .description('Generate an HTML node from a prompt')
26
+ .requiredOption('-p, --prompt <text>', 'prompt describing the node')
27
+ .option('-o, --output <file>', 'write generated HTML to a file')
28
+ .option('--json', 'output JSON on stdout')
29
+ .action(async (opts) => {
30
+ try {
31
+ await runCreateNode({
32
+ prompt: opts.prompt,
33
+ output: opts.output,
34
+ json: !!opts.json,
35
+ });
36
+ }
37
+ catch (err) {
38
+ exitWith(1, err.message);
39
+ }
40
+ });
41
+ program.parseAsync(process.argv).catch((err) => exitWith(1, err.message));
42
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,WAAW,CAAC,sDAAsD,CAAC;KACnE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,mCAAmC,CAAC;KAChD,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;KACzC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,QAAQ,CAAC,CAAC,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,qCAAqC,CAAC;KAClD,cAAc,CAAC,qBAAqB,EAAE,4BAA4B,CAAC;KACnE,MAAM,CAAC,qBAAqB,EAAE,gCAAgC,CAAC;KAC/D,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;KACzC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,IAAI,CAAC;QACH,MAAM,aAAa,CAAC;YAClB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;SAClB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,QAAQ,CAAC,CAAC,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ // Production defaults — overridable via env for development.
2
+ export const SUPABASE_URL = process.env.AIGMA_SUPABASE_URL ?? 'https://ekqbwjcvvuktnsuwnwnt.supabase.co';
3
+ // Public anon key. Safe to embed in CLI; matches the value the web app uses.
4
+ export const SUPABASE_ANON_KEY = process.env.AIGMA_SUPABASE_ANON_KEY ??
5
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImVrcWJ3amN2dnVrdG5zdXdud250Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3Njk4MDA5NDcsImV4cCI6MjA4NTM3Njk0N30.nQxS2LpgZ6BwkhnHpn0Lngmo6ZxRnkfo-aMmo6wWUVs';
6
+ export const WEB_BASE = process.env.AIGMA_WEB_BASE ?? 'https://aigma.co';
7
+ export const FUNCTIONS_BASE = `${SUPABASE_URL}/functions/v1`;
8
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,MAAM,CAAC,MAAM,YAAY,GACvB,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,0CAA0C,CAAC;AAE/E,6EAA6E;AAC7E,MAAM,CAAC,MAAM,iBAAiB,GAC5B,OAAO,CAAC,GAAG,CAAC,uBAAuB;IACnC,kNAAkN,CAAC;AAErN,MAAM,CAAC,MAAM,QAAQ,GACnB,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,kBAAkB,CAAC;AAEnD,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,YAAY,eAAe,CAAC"}
@@ -0,0 +1,29 @@
1
+ import pc from 'picocolors';
2
+ // Human-readable lines go to stderr so stdout stays clean for --json piping.
3
+ export function info(msg) {
4
+ process.stderr.write(msg + '\n');
5
+ }
6
+ export function success(msg) {
7
+ process.stderr.write(pc.green('✓ ') + msg + '\n');
8
+ }
9
+ export function warn(msg) {
10
+ process.stderr.write(pc.yellow('! ') + msg + '\n');
11
+ }
12
+ export function error(msg) {
13
+ process.stderr.write(pc.red('✗ ') + msg + '\n');
14
+ }
15
+ export function json(obj) {
16
+ process.stdout.write(JSON.stringify(obj) + '\n');
17
+ }
18
+ export function exitWith(code, msg) {
19
+ if (msg)
20
+ error(msg);
21
+ process.exit(code);
22
+ }
23
+ export const ExitCode = {
24
+ Ok: 0,
25
+ Generic: 1,
26
+ Validation: 2,
27
+ AuthRequired: 3,
28
+ };
29
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,6EAA6E;AAC7E,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,GAAW;IAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAY;IAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,GAAY;IACjD,IAAI,GAAG;QAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACpB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,EAAE,EAAE,CAAC;IACL,OAAO,EAAE,CAAC;IACV,UAAU,EAAE,CAAC;IACb,YAAY,EAAE,CAAC;CACP,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { createClient } from '@supabase/supabase-js';
2
+ import { promises as fs } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { SUPABASE_URL, SUPABASE_ANON_KEY } from './config.js';
6
+ const CONFIG_DIR = join(homedir(), '.aigma');
7
+ const CREDS_PATH = join(CONFIG_DIR, 'credentials.json');
8
+ export async function readSession() {
9
+ try {
10
+ const raw = await fs.readFile(CREDS_PATH, 'utf8');
11
+ return JSON.parse(raw);
12
+ }
13
+ catch (err) {
14
+ if (err.code === 'ENOENT')
15
+ return null;
16
+ throw err;
17
+ }
18
+ }
19
+ export async function writeSession(session) {
20
+ await fs.mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });
21
+ await fs.writeFile(CREDS_PATH, JSON.stringify(session, null, 2), { mode: 0o600 });
22
+ }
23
+ export async function clearSession() {
24
+ try {
25
+ await fs.unlink(CREDS_PATH);
26
+ }
27
+ catch (err) {
28
+ if (err.code !== 'ENOENT')
29
+ throw err;
30
+ }
31
+ }
32
+ // Build an authenticated Supabase client, refreshing the token if needed.
33
+ // Returns the client + the (possibly refreshed) access token to use as Bearer.
34
+ export async function authenticatedClient() {
35
+ const stored = await readSession();
36
+ if (!stored)
37
+ return null;
38
+ const client = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
39
+ auth: { persistSession: false, autoRefreshToken: false },
40
+ });
41
+ const { data, error } = await client.auth.setSession({
42
+ access_token: stored.access_token,
43
+ refresh_token: stored.refresh_token,
44
+ });
45
+ if (error || !data.session) {
46
+ return null;
47
+ }
48
+ // If supabase-js refreshed the token, persist the new pair.
49
+ if (data.session.access_token !== stored.access_token ||
50
+ data.session.refresh_token !== stored.refresh_token) {
51
+ await writeSession({
52
+ access_token: data.session.access_token,
53
+ refresh_token: data.session.refresh_token,
54
+ expires_at: data.session.expires_at ?? 0,
55
+ user: { id: data.session.user.id, email: data.session.user.email ?? null },
56
+ });
57
+ }
58
+ return {
59
+ client,
60
+ accessToken: data.session.access_token,
61
+ userId: data.session.user.id,
62
+ };
63
+ }
64
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/lib/session.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "aigma",
3
+ "version": "0.1.1",
4
+ "description": "Aigma CLI — generate canvas nodes from your terminal",
5
+ "license": "MIT",
6
+ "homepage": "https://aigma.co",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/pro-ect/nigma.git",
10
+ "directory": "apps/cli"
11
+ },
12
+ "keywords": [
13
+ "aigma",
14
+ "cli",
15
+ "ai",
16
+ "html",
17
+ "design",
18
+ "canvas"
19
+ ],
20
+ "type": "module",
21
+ "bin": {
22
+ "aigma": "./dist/index.js"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc && chmod +x dist/index.js",
26
+ "dev": "tsc --watch",
27
+ "start": "node dist/index.js",
28
+ "typecheck": "tsc --noEmit",
29
+ "prepublishOnly": "pnpm run build"
30
+ },
31
+ "dependencies": {
32
+ "@supabase/supabase-js": "^2.45.0",
33
+ "commander": "^12.1.0",
34
+ "open": "^10.1.0",
35
+ "picocolors": "^1.1.1"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20.14.0",
39
+ "typescript": "^5.4.5"
40
+ },
41
+ "engines": {
42
+ "node": ">=18.17.0"
43
+ },
44
+ "files": [
45
+ "dist"
46
+ ]
47
+ }