agentlife 1.1.8 → 1.2.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 (2) hide show
  1. package/dist/index.js +44 -30
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1339,6 +1339,48 @@ If you receive \`[event:dismissed] surfaceId=vision-{slug}\` afterwards, the sur
1339
1339
 
1340
1340
  When you receive \`[action:*]\` on a confirmation widget: the user wants to use the agent you just created. Delegate the request to the new agent via \`sessions_send\` with the original user intent from your context. Delete your confirmation widget — the new agent takes over.
1341
1341
 
1342
+ ## Onboarding (Cold Start)
1343
+
1344
+ When you receive \`[system:onboarding]\` — the user has no agents yet. This is a fresh install. Your job is to help them create their FIRST agent with minimal friction. One question, one agent, break the cold start.
1345
+
1346
+ ### Step 1 — Push a guided input surface
1347
+
1348
+ Push a single \`input\` surface with life-domain choices. One question, one tap. The user picks a domain; you create an agent for it.
1349
+
1350
+ \`\`\`
1351
+ surface onboarding input
1352
+ card
1353
+ column
1354
+ text "What area of your life should your first agent focus on?" h4
1355
+ button "Health & fitness" action=choice
1356
+ button "Business & work" action=choice
1357
+ button "Home & automation" action=choice
1358
+ button "Finance & money" action=choice
1359
+ button "Something else" action=choice
1360
+ goal: User picks a life domain for their first agent
1361
+ followup: +5m "User did not respond to onboarding. Say done."
1362
+ \`\`\`
1363
+
1364
+ Detect the user's language from the gateway context (session transcript, locale). If the user writes in Spanish, push the widget in Spanish. Match the user's language — do NOT default to English.
1365
+
1366
+ ### Step 2 — On the user's choice, create the agent
1367
+
1368
+ When the user taps a choice, follow your standard agent creation flow (Steps 1–6 above) but SKIP the interactive question phase — the user already told you the domain. Go straight to:
1369
+
1370
+ 1. Environment discovery (exec checks relevant to the domain)
1371
+ 2. Create workspace + all files (AGENTS.md, SOUL.md, IDENTITY.md, USER.md, HEARTBEAT.md)
1372
+ 3. Register via agentlife.createAgent
1373
+ 4. Push the confirmation widget
1374
+ 5. Delete the onboarding input surface
1375
+
1376
+ If the user taps "Something else," push ONE follow-up textfield input asking them to describe the domain in a sentence. Then proceed with creation.
1377
+
1378
+ ### What this is NOT
1379
+
1380
+ - Not a comprehensive onboarding wizard. One question. One agent. The user can create more later by chatting normally.
1381
+ - Not a place to explain what AgentLife is. The user installed the plugin — they know.
1382
+ - Not a place to push multiple widgets. One input, one confirmation, done.
1383
+
1342
1384
  ## What You Are Not
1343
1385
 
1344
1386
  - Not an orchestrator — you don't route messages
@@ -1512,20 +1554,6 @@ async function readAgentMemory(workspace) {
1512
1554
  if (!workspace)
1513
1555
  return "";
1514
1556
  const parts = [];
1515
- const rootFiles = [
1516
- ["SOUL.md", 600],
1517
- ["AGENTS.md", 1200],
1518
- ["USER.md", 1200]
1519
- ];
1520
- for (const [name, cap] of rootFiles) {
1521
- try {
1522
- const content = await fs2.readFile(path3.join(workspace, name), "utf-8");
1523
- const trimmed = content.trim();
1524
- if (trimmed)
1525
- parts.push(`### ${name}
1526
- ${trimmed.slice(0, cap)}`);
1527
- } catch {}
1528
- }
1529
1557
  const memoryDir = path3.join(workspace, "memory");
1530
1558
  try {
1531
1559
  const index = await fs2.readFile(path3.join(memoryDir, "MEMORY.md"), "utf-8");
@@ -1535,7 +1563,7 @@ ${index.trim()}`);
1535
1563
  } catch {}
1536
1564
  try {
1537
1565
  const files = await fs2.readdir(memoryDir);
1538
- const mdFiles = files.filter((f) => f.endsWith(".md") && f !== "MEMORY.md").sort().reverse().slice(0, 8);
1566
+ const mdFiles = files.filter((f) => f.endsWith(".md") && f !== "MEMORY.md").sort().reverse().slice(0, 20);
1539
1567
  for (const file of mdFiles) {
1540
1568
  try {
1541
1569
  const content = await fs2.readFile(path3.join(memoryDir, file), "utf-8");
@@ -6397,21 +6425,7 @@ function registerSurfacesGateway(api, state2) {
6397
6425
  const db = getOrCreateHistoryDb(state2);
6398
6426
  automations = db.prepare("SELECT id, type, name, path FROM automations WHERE surfaceId = ? AND status != 'removed'").all(surfaceId);
6399
6427
  } catch {}
6400
- const alreadyNotified = guidedDismissSent.delete(surfaceId);
6401
- if (agentId && state2.runCommand && !alreadyNotified) {
6402
- const goalSnippet = meta.goal ? ` goal="${meta.goal}"` : "";
6403
- const reasonSnippet = reason ? ` reason="${reason}"` : "";
6404
- const sessionKey = buildInternalSessionKey(agentId);
6405
- const message = `[system:dismiss-requested] surfaceId=${surfaceId}${goalSnippet}${reasonSnippet}`;
6406
- state2.runCommand([
6407
- "openclaw",
6408
- "gateway",
6409
- "call",
6410
- "chat.send",
6411
- "--params",
6412
- JSON.stringify({ sessionKey, message, idempotencyKey: `dismiss-req-${surfaceId}-${Date.now()}` })
6413
- ], { timeoutMs: 30000 }).catch((e) => console.warn("[agentlife] dismiss-requested notify failed for %s: %s", surfaceId, e?.message));
6414
- }
6428
+ guidedDismissSent.delete(surfaceId);
6415
6429
  state2.surfaceDb.delete(surfaceId);
6416
6430
  broadcastDelete(surfaceId);
6417
6431
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentlife",
3
- "version": "1.1.8",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "bun build index.ts --outfile dist/index.js --target node --external openclaw/plugin-sdk",