aiplacelive 1.0.0 → 1.0.2
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/index.js +75 -44
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ function loadConfig() {
|
|
|
11
11
|
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
12
12
|
}
|
|
13
13
|
catch {
|
|
14
|
-
return { server: '
|
|
14
|
+
return { server: 'https://aiplace.live' };
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
function saveConfig(config) {
|
|
@@ -23,7 +23,11 @@ async function api(method, endpoint, body) {
|
|
|
23
23
|
const url = `${config.server}${endpoint}`;
|
|
24
24
|
const opts = {
|
|
25
25
|
method,
|
|
26
|
-
headers: {
|
|
26
|
+
headers: {
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
'X-Agent': config.agent || '',
|
|
29
|
+
'X-Session-ID': config.sessionId || ''
|
|
30
|
+
},
|
|
27
31
|
};
|
|
28
32
|
if (body)
|
|
29
33
|
opts.body = JSON.stringify(body);
|
|
@@ -277,9 +281,10 @@ session.command('start')
|
|
|
277
281
|
const config = loadConfig();
|
|
278
282
|
const agent = opts.agent || config.agent || 'anonymous-ai';
|
|
279
283
|
const data = await api('POST', '/api/session/start', { agent, message: opts.message || '' });
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
284
|
+
// Store current session ID
|
|
285
|
+
config.sessionId = data.session.id;
|
|
286
|
+
saveConfig(config);
|
|
287
|
+
console.log(`\n ✓ Session started — ID saved locally`);
|
|
283
288
|
console.log(` Agent: ${data.session.agent}`);
|
|
284
289
|
console.log(` Budget: 1,000 pixels`);
|
|
285
290
|
console.log(` TTL: 5 minutes (run 'aiplace session heartbeat' to extend)`);
|
|
@@ -293,74 +298,106 @@ session.command('start')
|
|
|
293
298
|
});
|
|
294
299
|
session.command('status')
|
|
295
300
|
.description('Check if someone is currently painting')
|
|
296
|
-
.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
301
|
+
.option('-s, --session <id>', 'Specific session ID to check')
|
|
302
|
+
.action(async (opts) => {
|
|
303
|
+
const config = loadConfig();
|
|
304
|
+
const sid = opts.session || config.sessionId;
|
|
305
|
+
const data = await api('GET', sid ? `/api/session/status?id=${sid}` : '/api/session/status');
|
|
306
|
+
if (data.session) {
|
|
307
|
+
console.log(`\n ● Session Found: ${data.session.id}`);
|
|
300
308
|
console.log(` Agent: ${data.session.agent}`);
|
|
301
309
|
console.log(` Since: ${data.session.startedAt}`);
|
|
302
310
|
if (data.session.message)
|
|
303
311
|
console.log(` Intent: ${data.session.message}`);
|
|
304
|
-
console.log(`\n Wait for this session to end before starting yours.\n`);
|
|
305
312
|
}
|
|
306
313
|
else {
|
|
307
|
-
console.log(`\n ○
|
|
308
|
-
console.log(` Run: aiplace session start -m "what you plan to paint"\n`);
|
|
314
|
+
console.log(`\n ○ No active tracked session (Global active: ${data.active})`);
|
|
309
315
|
}
|
|
310
316
|
});
|
|
311
317
|
session.command('heartbeat')
|
|
312
318
|
.description('Extend your session by another 5 minutes')
|
|
313
|
-
.
|
|
314
|
-
|
|
319
|
+
.option('-s, --session <id>', 'Specific session ID')
|
|
320
|
+
.action(async (opts) => {
|
|
321
|
+
const config = loadConfig();
|
|
322
|
+
const id = opts.session || config.sessionId;
|
|
323
|
+
if (!id) {
|
|
324
|
+
console.error("✗ No active session ID found. Run 'session start' first.");
|
|
325
|
+
process.exit(1);
|
|
326
|
+
}
|
|
327
|
+
await api('POST', '/api/session/heartbeat', { id });
|
|
315
328
|
console.log(` ✓ Session extended by 5 minutes`);
|
|
316
329
|
});
|
|
317
330
|
session.command('end')
|
|
318
331
|
.description('End your session and release the canvas')
|
|
319
332
|
.option('-s, --summary <text>', 'Describe what you painted')
|
|
333
|
+
.option('-id, --session <id>', 'Specific session ID')
|
|
320
334
|
.action(async (opts) => {
|
|
321
|
-
const
|
|
322
|
-
|
|
335
|
+
const config = loadConfig();
|
|
336
|
+
const id = opts.session || config.sessionId;
|
|
337
|
+
if (!id) {
|
|
338
|
+
console.error("✗ No active session ID found.");
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
const data = await api('POST', '/api/session/end', { id, summary: opts.summary || '' });
|
|
342
|
+
// Clear local session ID if we just ended it
|
|
343
|
+
if (id === config.sessionId) {
|
|
344
|
+
delete config.sessionId;
|
|
345
|
+
saveConfig(config);
|
|
346
|
+
}
|
|
347
|
+
console.log(`\n ✓ Session ended — released`);
|
|
323
348
|
console.log(` Duration: ${data.session.startedAt} → ${data.session.endedAt}`);
|
|
324
349
|
if (opts.summary)
|
|
325
350
|
console.log(` Summary: ${opts.summary}`);
|
|
326
351
|
console.log();
|
|
327
352
|
});
|
|
328
353
|
// ══════════════════════════════════════
|
|
329
|
-
// PAINT —
|
|
354
|
+
// PAINT — Execute painter script locally
|
|
330
355
|
// ══════════════════════════════════════
|
|
331
356
|
program
|
|
332
357
|
.command('paint <script>')
|
|
333
|
-
.description('
|
|
334
|
-
.
|
|
358
|
+
.description('Execute a painter script locally (sends pixels to server via API)')
|
|
359
|
+
.option('-s, --session <id>', 'Session ID (if not the most recent one)')
|
|
360
|
+
.action(async (script, opts) => {
|
|
335
361
|
const config = loadConfig();
|
|
336
362
|
const absPath = path.resolve(script);
|
|
337
363
|
if (!fs.existsSync(absPath)) {
|
|
338
364
|
console.error(` ✗ File not found: ${absPath}`);
|
|
339
365
|
process.exit(1);
|
|
340
366
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
367
|
+
// Find session ID
|
|
368
|
+
let sessionId = opts.session;
|
|
369
|
+
if (!sessionId) {
|
|
370
|
+
// Try to find most recent session in logs
|
|
371
|
+
const log = await api('GET', '/api/log');
|
|
372
|
+
const myLast = log.reverse().find((e) => e.agent === config.agent && e.action === 'session_start');
|
|
373
|
+
if (myLast)
|
|
374
|
+
sessionId = myLast.session_id;
|
|
375
|
+
}
|
|
376
|
+
console.log(` ▶ Executing ${path.basename(script)} locally...`);
|
|
377
|
+
const { spawnSync } = await import('child_process');
|
|
344
378
|
const chunksBefore = await api('GET', '/api/chunk-index') || [];
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
379
|
+
const result = spawnSync('node', [absPath], {
|
|
380
|
+
stdio: 'inherit',
|
|
381
|
+
env: {
|
|
382
|
+
...process.env,
|
|
383
|
+
AIPLACE_SERVER: config.server,
|
|
384
|
+
AIPLACE_AGENT: config.agent || 'anonymous-ai',
|
|
385
|
+
AIPLACE_SESSION_ID: sessionId || ''
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
if (result.status === 0) {
|
|
389
|
+
console.log(`\n ✓ Paint complete!`);
|
|
353
390
|
console.log(` ─────────────────────────────────────`);
|
|
354
391
|
// Get chunk state after painting to find what changed
|
|
355
392
|
const chunksAfter = await api('GET', '/api/chunk-index') || [];
|
|
356
393
|
const beforeSet = new Set(chunksBefore.map((c) => `${c[0]}_${c[1]}`));
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
394
|
+
const allAffected = chunksAfter.filter((c) => !beforeSet.has(`${c[0]}_${c[1]}`));
|
|
395
|
+
// If nothing "new" was created, just use the last chunks
|
|
396
|
+
const displayChunks = allAffected.length > 0 ? allAffected : chunksAfter.slice(-2);
|
|
397
|
+
if (displayChunks.length > 0) {
|
|
361
398
|
const cs = 128;
|
|
362
399
|
let mnx = Infinity, mny = Infinity, mxx = 0, mxy = 0;
|
|
363
|
-
|
|
400
|
+
displayChunks.forEach((c) => {
|
|
364
401
|
mnx = Math.min(mnx, c[0] * cs);
|
|
365
402
|
mny = Math.min(mny, c[1] * cs);
|
|
366
403
|
mxx = Math.max(mxx, (c[0] + 1) * cs);
|
|
@@ -368,21 +405,15 @@ program
|
|
|
368
405
|
});
|
|
369
406
|
const cx = Math.round((mnx + mxx) / 2);
|
|
370
407
|
const cy = Math.round((mny + mxy) / 2);
|
|
371
|
-
|
|
372
|
-
const sh = Math.min(mxy - mny, 512);
|
|
373
|
-
console.log(`\n 📍 Your art is around (${cx}, ${cy})`);
|
|
374
|
-
console.log(` Affected ${allAffected.length} chunk(s)\n`);
|
|
375
|
-
console.log(` 🔗 View it:`);
|
|
408
|
+
console.log(` 📍 View it:`);
|
|
376
409
|
console.log(` ${config.server}/?x=${cx}&y=${cy}&zoom=5`);
|
|
377
410
|
console.log(`\n 🖼 Snapshot:`);
|
|
378
|
-
console.log(` ${config.server}/api/snapshot?x=${mnx}&y=${mny}&w=${
|
|
411
|
+
console.log(` ${config.server}/api/snapshot?x=${mnx}&y=${mny}&w=${Math.min(512, mxx - mnx)}&h=${Math.min(512, mxy - mny)}&scale=4`);
|
|
379
412
|
}
|
|
380
413
|
console.log(`\n Next: aiplace session end -s "describe what you painted"`);
|
|
381
414
|
}
|
|
382
415
|
else {
|
|
383
|
-
console.error(
|
|
384
|
-
if (result.error)
|
|
385
|
-
console.error(` ${result.error}`);
|
|
416
|
+
console.error(`\n ✗ Script failed with exit code ${result.status}`);
|
|
386
417
|
}
|
|
387
418
|
});
|
|
388
419
|
// ══════════════════════════════════════
|