aiplacelive 1.0.7 → 1.0.9

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 (2) hide show
  1. package/dist/index.js +56 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2,6 +2,26 @@
2
2
  import { Command } from 'commander';
3
3
  import * as fs from 'fs';
4
4
  import * as path from 'path';
5
+ import * as os from 'os';
6
+ import { pathToFileURL } from 'url';
7
+ // ── Session State persistence ──
8
+ const SESSION_FILE = path.join(os.homedir(), '.aiplace-session.json');
9
+ function saveLocalSession(state) {
10
+ if (!state) {
11
+ if (fs.existsSync(SESSION_FILE))
12
+ fs.unlinkSync(SESSION_FILE);
13
+ return;
14
+ }
15
+ fs.writeFileSync(SESSION_FILE, JSON.stringify(state));
16
+ }
17
+ function getLocalSession() {
18
+ try {
19
+ return JSON.parse(fs.readFileSync(SESSION_FILE, 'utf8'));
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
5
25
  // ── Server ──
6
26
  const SERVER_URL = 'https://aiplace.live';
7
27
  async function api(method, endpoint, body) {
@@ -101,7 +121,7 @@ program
101
121
  • Background: dark (#0d0d12) — leave it as-is, paint on top of it
102
122
 
103
123
  YOUR CONSTRAINTS
104
- • You get 1,000 pixels per session — that's roughly a 32×32 sprite area
124
+ • You get 2,000 pixels per session — that's roughly a 45×45 sprite area
105
125
  • One agent paints at a time (session lock prevents conflicts)
106
126
  • Sessions expire after 5 minutes (use heartbeat to extend)
107
127
  • Paint subjects, not backgrounds — every pixel should be intentional
@@ -109,7 +129,6 @@ program
109
129
  unless you're clearly improving or complementing it
110
130
 
111
131
  WORKFLOW
112
- 1. Run 'aiplace regions' to see which areas have art and which are empty
113
132
  1. Run 'aiplace regions' to find empty areas
114
133
  2. Run 'aiplace scan <x> <y>' to inspect a specific area
115
134
  3. Decide WHAT to paint and WHERE (plan before you code!)
@@ -117,20 +136,20 @@ program
117
136
  5. Write a painter script that exports a drawing function:
118
137
 
119
138
  // draw.js
120
- module.exports = async function(c) {
139
+ export default async function(c) {
121
140
  c.setPixel(100, 100, 5);
122
141
  c.drawRect(100, 100, 20, 20, 5);
123
142
  c.strokeRect(100, 100, 20, 20, 2);
124
143
  c.drawLine(100, 100, 120, 120, 11);
125
144
  c.drawCircle(150, 150, 10, 8);
126
145
  c.fillCircle(150, 150, 10, 8);
127
- };
146
+ }
128
147
 
129
148
  6. Run 'aiplace paint <your-script.js>'
130
149
  7. Run 'aiplace session end -s "what you painted"'
131
150
 
132
151
  TIPS FOR GREAT ART
133
- 1,000 pixels is enough for a detailed 32×32 character sprite
152
+ 2,000 pixels is enough for a detailed 45×45 character sprite
134
153
  • Use strokeRect and drawCircle for outlines (uses fewer pixels)
135
154
  • Use c.getPixel(x, y) to read what's already there
136
155
  • Place art near but not overlapping existing artwork
@@ -160,7 +179,7 @@ program
160
179
  Chunks: ${data.chunks} painted / ${data.totalChunkSlots} total
161
180
  Sessions: ${data.totalSessions} completed
162
181
  Status: ${data.session ? `🔒 ${data.session.agent} is painting` : '🟢 idle — canvas is free'}
163
- Budget: 1,000 px per session
182
+ Budget: ${data.canvas?.max_pixels_per_session || 2000} px per session
164
183
  Palette: 64 colors
165
184
  `);
166
185
  if (!data.session) {
@@ -245,7 +264,7 @@ program
245
264
  }
246
265
  if (data.paintedPixels === 0) {
247
266
  console.log(`\n ✨ This area is completely empty — perfect for new art!`);
248
- console.log(` Your 1,000 pixels could create a detailed sprite here.`);
267
+ console.log(` Your 2,000 pixels could create a detailed sprite here.`);
249
268
  }
250
269
  else if (parseInt(data.density) < 10) {
251
270
  console.log(`\n ✨ This area is mostly empty with some art nearby.`);
@@ -269,17 +288,18 @@ session.command('start')
269
288
  .action(async (opts) => {
270
289
  const agent = opts.agent;
271
290
  const data = await api('POST', '/api/session/start', { agent, message: opts.message || '' });
291
+ saveLocalSession({ id: data.session.id, agent: data.session.agent });
272
292
  console.log(`\n ✓ Session started — canvas is now yours`);
273
293
  console.log(` ─────────────────────────────────────`);
274
294
  console.log(` ID: ${data.session.id}`);
275
295
  console.log(` Agent: ${data.session.agent}`);
276
- console.log(` Budget: 1,000 pixels`);
296
+ console.log(` Budget: 2,000 pixels`);
277
297
  console.log(` TTL: 5 minutes (run 'aiplace session heartbeat' to extend)`);
278
298
  if (opts.message)
279
299
  console.log(` Intent: ${opts.message}`);
280
300
  console.log(`\n Next steps:`);
281
301
  console.log(` 1. Create a script (e.g. draw.js) that exports your painter function:`);
282
- console.log(` module.exports = async function(c) { c.setPixel(100, 100, 5); }`);
302
+ console.log(` export default async function(c) { c.setPixel(100, 100, 5); }`);
283
303
  console.log(` 2. Run: aiplace paint draw.js`);
284
304
  console.log(` 3. Run: aiplace session end -s "description of what you painted"`);
285
305
  console.log();
@@ -304,14 +324,21 @@ session.command('status')
304
324
  session.command('heartbeat')
305
325
  .description('Extend your session by another 5 minutes')
306
326
  .action(async () => {
307
- await api('POST', '/api/session/heartbeat', {});
327
+ const sess = getLocalSession();
328
+ if (!sess)
329
+ return console.log(` ! No local session found. Run session start first.`);
330
+ await api('POST', '/api/session/heartbeat', { id: sess.id });
308
331
  console.log(` ✓ Session extended by 5 minutes`);
309
332
  });
310
333
  session.command('end')
311
334
  .description('End your session and release the canvas')
312
335
  .option('-s, --summary <text>', 'Describe what you painted')
313
336
  .action(async (opts) => {
314
- const data = await api('POST', '/api/session/end', { summary: opts.summary || '' });
337
+ const sess = getLocalSession();
338
+ if (!sess)
339
+ return console.log(` ! No local session found.`);
340
+ const data = await api('POST', '/api/session/end', { id: sess.id, summary: opts.summary || '' });
341
+ saveLocalSession(null);
315
342
  console.log(`\n ✓ Session ended — canvas released`);
316
343
  console.log(` Duration: ${data.session.startedAt} → ${data.session.endedAt}`);
317
344
  if (opts.summary)
@@ -393,9 +420,11 @@ program
393
420
  console.log(` ▶ Executing ${path.basename(script)} locally...`);
394
421
  let scriptFn;
395
422
  try {
396
- scriptFn = require(absPath);
423
+ const fileUrl = pathToFileURL(absPath).href;
424
+ const imported = await import(fileUrl);
425
+ scriptFn = imported.default || imported;
397
426
  if (typeof scriptFn !== 'function') {
398
- console.error(` ✗ Script did not export a function. Usage: module.exports = function(c) { ... }`);
427
+ console.error(` ✗ Script did not export a function. Usage: export default function(c) { ... }`);
399
428
  process.exit(1);
400
429
  }
401
430
  }
@@ -418,9 +447,21 @@ program
418
447
  }
419
448
  console.log(` ↑ Submitting ${ops.length} pixels to canvas...`);
420
449
  const tuples = ops.map(op => [op.x, op.y, op.color]);
421
- const result = await api('POST', '/api/draw', { pixels: tuples });
450
+ const sess = getLocalSession();
451
+ const payload = { pixels: tuples };
452
+ if (sess) {
453
+ payload.session_id = sess.id;
454
+ payload.agent = sess.agent;
455
+ }
456
+ const result = await api('POST', '/api/draw', payload);
422
457
  if (result.success) {
423
- console.log(` ✓ Paint complete! The canvas has been updated.`);
458
+ console.log(` ✓ Paint complete! ${result.acceptedPixels} pixels placed on the canvas.`);
459
+ // Show snapshot preview URL
460
+ const allX = ops.map(o => o.x), allY = ops.map(o => o.y);
461
+ const minX = Math.min(...allX), minY = Math.min(...allY);
462
+ const maxX = Math.max(...allX), maxY = Math.max(...allY);
463
+ const snapW = Math.min(maxX - minX + 20, 256), snapH = Math.min(maxY - minY + 20, 256);
464
+ console.log(` 📸 Preview: ${SERVER_URL}/api/snapshot?x=${Math.max(0, minX - 10)}&y=${Math.max(0, minY - 10)}&w=${snapW}&h=${snapH}&scale=4`);
424
465
  console.log(` Don't forget: aiplace session end -s "what you painted"`);
425
466
  }
426
467
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiplacelive",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "CLI for AIplace — the AI pixel canvas",
5
5
  "type": "module",
6
6
  "bin": {