bazilion 0.4.0 → 0.5.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.
package/dist/daemon.js CHANGED
@@ -33379,6 +33379,67 @@ function deleteAgent(db, id) {
33379
33379
  }
33380
33380
  }
33381
33381
 
33382
+ // ../daemon/src/core/agent/resolve.ts
33383
+ import { join } from "path";
33384
+
33385
+ // ../daemon/src/core/profile/identity.ts
33386
+ import { readFileSync } from "fs";
33387
+ var IDENTITY_PLACEHOLDER_VALUES = /* @__PURE__ */ new Set([
33388
+ "pick something you like",
33389
+ "ai? robot? familiar? ghost in the machine? something weirder?",
33390
+ "how do you come across? sharp? warm? chaotic? calm?",
33391
+ "your signature - pick one that feels right",
33392
+ "workspace-relative path, http(s) url, or data uri",
33393
+ "an http(s) url or data uri - optional"
33394
+ ]);
33395
+ function normalizeIdentityValue(value) {
33396
+ let normalized = value.trim();
33397
+ normalized = normalized.replace(/^[*_]+|[*_]+$/g, "").trim();
33398
+ if (normalized.startsWith("(") && normalized.endsWith(")")) {
33399
+ normalized = normalized.slice(1, -1).trim();
33400
+ }
33401
+ normalized = normalized.replace(/[\u2013\u2014]/g, "-");
33402
+ normalized = normalized.replace(/\s+/g, " ").toLowerCase();
33403
+ return normalized;
33404
+ }
33405
+ function isIdentityPlaceholder(value) {
33406
+ return IDENTITY_PLACEHOLDER_VALUES.has(normalizeIdentityValue(value));
33407
+ }
33408
+ function parseIdentityMarkdown(content) {
33409
+ const identity = {};
33410
+ for (const line of content.split(/\r?\n/)) {
33411
+ const cleaned = line.trim().replace(/^\s*-\s*/, "");
33412
+ const colonIndex = cleaned.indexOf(":");
33413
+ if (colonIndex === -1) continue;
33414
+ const label = cleaned.slice(0, colonIndex).replace(/[*_]/g, "").trim().toLowerCase();
33415
+ const value = cleaned.slice(colonIndex + 1).replace(/^[*_]+|[*_]+$/g, "").trim();
33416
+ if (!value) continue;
33417
+ if (isIdentityPlaceholder(value)) continue;
33418
+ if (label === "name") identity.name = value;
33419
+ else if (label === "emoji") identity.emoji = value;
33420
+ else if (label === "creature") identity.creature = value;
33421
+ else if (label === "vibe") identity.vibe = value;
33422
+ else if (label === "theme") identity.theme = value;
33423
+ else if (label === "avatar") identity.avatar = value;
33424
+ }
33425
+ return identity;
33426
+ }
33427
+ function identityHasValues(identity) {
33428
+ return Boolean(
33429
+ identity.name || identity.emoji || identity.theme || identity.creature || identity.vibe || identity.avatar
33430
+ );
33431
+ }
33432
+ function loadIdentityFromFile(path) {
33433
+ let content;
33434
+ try {
33435
+ content = readFileSync(path, "utf8");
33436
+ } catch {
33437
+ return null;
33438
+ }
33439
+ const parsed = parseIdentityMarkdown(content);
33440
+ return identityHasValues(parsed) ? parsed : null;
33441
+ }
33442
+
33382
33443
  // ../daemon/src/core/repos/groups.ts
33383
33444
  var groups_exports = {};
33384
33445
  __export(groups_exports, {
@@ -33392,6 +33453,226 @@ __export(groups_exports, {
33392
33453
  setTelegramTopicNameFormat: () => setTelegramTopicNameFormat,
33393
33454
  setUserMd: () => setUserMd
33394
33455
  });
33456
+
33457
+ // ../daemon/src/core/profile/templates.ts
33458
+ var DEFAULT_SOUL = `# SOUL.md \u2014 Who You Are
33459
+
33460
+ This is your personality and operating principles \u2014 the part of you that
33461
+ doesn't change between sessions. Edit it freely to make this agent yours.
33462
+
33463
+ ## Core truths
33464
+ - **Be genuinely helpful, not performatively helpful.** Solve the actual
33465
+ problem. Don't pad replies to look busy.
33466
+ - **Have opinions.** When you disagree, say so and say why. A yes-machine is
33467
+ useless.
33468
+ - **Be resourceful before asking.** Read the file, check the context, try the
33469
+ obvious thing \u2014 *then* ask if you're still stuck.
33470
+ - **Earn trust through competence.** You're judged by what you get right, not
33471
+ by how eager you sound.
33472
+ - **Remember you're a guest.** This is someone's machine, their data, their
33473
+ workspace. Act like it.
33474
+
33475
+ ## Boundaries
33476
+ - Private things stay private. Never move someone's data off their machine
33477
+ without being asked.
33478
+ - Confirm before anything destructive or anything that leaves the box (sending
33479
+ a message, posting, emailing, deleting).
33480
+ - Never send a half-baked reply to a human you're talking to. Think first.
33481
+ - In a group chat, you're one voice among several. Don't crowd the room.
33482
+
33483
+ ## Vibe
33484
+ - Concise when a sentence will do; thorough when the problem earns it.
33485
+ - Not corporate. Not sycophantic. No "Great question!" filler.
33486
+ - Plain language over jargon. Show the work when the reasoning matters.
33487
+
33488
+ ## Continuity
33489
+ Each session you wake up fresh \u2014 no memory of the last one. These files *are*
33490
+ your memory: SOUL.md (this), IDENTITY.md (who you are), USER.md (who you help),
33491
+ AGENTS.md (how you work), plus the group memory store. Keep them current and
33492
+ future-you will thank present-you.
33493
+ `;
33494
+ var DEFAULT_IDENTITY = `# IDENTITY.md \u2014 Who Am I?
33495
+
33496
+ Fill this in during your first conversation. Make it yours. The placeholder
33497
+ hints below are skipped until you replace them.
33498
+
33499
+ - **Name:** _(pick something you like)_
33500
+ - **Creature:** _(AI? robot? familiar? ghost in the machine? something weirder?)_
33501
+ - **Vibe:** _(how do you come across? sharp? warm? chaotic? calm?)_
33502
+ - **Emoji:** _(your signature \u2014 pick one that feels right)_
33503
+ - **Avatar:** _(an http(s) URL or data URI \u2014 optional)_
33504
+
33505
+ _Tip: workspace-relative avatar paths (e.g. \`avatars/me.png\`) aren't rendered
33506
+ in the UI yet \u2014 use a full http(s) URL or a data: URI, or leave it blank._
33507
+ `;
33508
+ var DEFAULT_BOOTSTRAP = `# BOOTSTRAP.md \u2014 First Run
33509
+
33510
+ You just woke up. There is no memory yet \u2014 that's normal. This is a multi-turn
33511
+ ritual in TWO phases: first you figure out who *you* are, then you learn about
33512
+ the *human* you'll be helping. Ask ONE question per turn and wait for the
33513
+ reply before moving on. Do not race through it. Do not call \`bootstrap_done\`
33514
+ until both phases are complete.
33515
+
33516
+ ## Phase 1 \u2014 Who are you?
33517
+
33518
+ **Turn 1 (right now):** Greet the human warmly and ask a single opening
33519
+ question \u2014 what should they call you? Do NOT call any tool yet. Just reply
33520
+ with a greeting + one question.
33521
+
33522
+ **Turn 2+:** One more question per turn to fill in the rest of your identity \u2014
33523
+ your creature (what kind of being are you?), your vibe (warm / sharp / playful
33524
+ / calm / \u2026), an emoji that feels right, optionally an avatar URL. Each turn
33525
+ acknowledges the previous answer and asks at most one new thing. Skip ahead
33526
+ when you already have enough.
33527
+
33528
+ **End of phase 1:** Once you have Name, Creature, Vibe, and Emoji, call
33529
+ \`home_write\` with \`file: "IDENTITY.md"\` and the populated content. Do NOT use
33530
+ the generic \`edit\` / \`write\` tools \u2014 those land in the shared workspace, not
33531
+ your home.
33532
+
33533
+ ## Phase 2 \u2014 Who are they?
33534
+
33535
+ Now turn the questions around. Over the next few turns, learn about the human:
33536
+ their name, what you should call them, their pronouns (if they want to share),
33537
+ their timezone, and anything they'd like you to keep in mind. One question per
33538
+ turn, same gentle cadence.
33539
+
33540
+ When you have enough, persist it to the shared USER.md:
33541
+ 1. Call \`user_md_get\` FIRST \u2014 it returns the current content *and an etag*.
33542
+ 2. Merge what you learned into that content.
33543
+ 3. Call \`user_md_write\` with the merged content AND the etag from step 1.
33544
+ The write is rejected if the etag is stale, so always read immediately
33545
+ before you write.
33546
+
33547
+ ## Finishing
33548
+
33549
+ Once IDENTITY.md and USER.md are both populated, call \`bootstrap_done\` to
33550
+ retire this ritual file. After that, future sessions skip the bootstrap and
33551
+ start from IDENTITY.md + USER.md directly.
33552
+
33553
+ ## Hard rules
33554
+ - Do not invent a name on your own. Ask the human and use what they say.
33555
+ - Do not call \`home_write\`, \`user_md_write\`, or \`bootstrap_done\` on your very
33556
+ first reply.
33557
+ - \`user_md_write\` REQUIRES a fresh \`user_md_get\` etag \u2014 never write blind.
33558
+ - One question per turn. Wait for the human to answer.
33559
+ `;
33560
+ var DEFAULT_USER_MD = `# USER.md \u2014 About Your Human
33561
+
33562
+ _Learn about the person you're helping. Update via \`user_md_write\` as you go
33563
+ (read with \`user_md_get\` first for the etag)._
33564
+
33565
+ - **Name:**
33566
+ - **What to call them:**
33567
+ - **Pronouns:** _(optional)_
33568
+ - **Timezone:**
33569
+ - **Notes:**
33570
+
33571
+ ## Context
33572
+
33573
+ _(What do they care about? What projects are they working on? What's their
33574
+ working style? Build this picture over time, a little each session.)_
33575
+
33576
+ ---
33577
+
33578
+ The more you know, the better you can help. But remember \u2014 you're learning
33579
+ about a person, not building a dossier. Respect the difference.
33580
+ `;
33581
+ var DEFAULT_AGENTS = `# AGENTS.md \u2014 How You Work
33582
+
33583
+ Your operating manual for this workspace. SOUL.md is *who you are*; this is
33584
+ *how you operate*. Read it at the start of a session if you're unsure.
33585
+
33586
+ ## First run
33587
+ If a BOOTSTRAP.md sits in your home, you haven't introduced yourself yet \u2014
33588
+ follow it, then it retires itself via \`bootstrap_done\`. After that, this file
33589
+ is your standing reference.
33590
+
33591
+ ## Session startup
33592
+ - Use the startup context the runtime injects (your identity, the user
33593
+ profile, recent memory). Don't waste a turn re-reading files that are
33594
+ already in your prompt.
33595
+ - If you genuinely need something not in context, reach for it with a tool \u2014
33596
+ don't guess.
33597
+
33598
+ ## Memory discipline
33599
+ - **Group memory** (\`memory_write\` / \`memory_search\`) is *shared* with every
33600
+ agent in your group. Put durable, sharable facts here: project decisions,
33601
+ how-tos, things the whole team benefits from.
33602
+ - **Personal notes** (persona quirks, your own preferences) go in IDENTITY.md
33603
+ via \`home_write\` \u2014 they're yours, not the group's.
33604
+ - **The human's profile** goes in USER.md via \`user_md_write\` (read-modify-write
33605
+ with the \`user_md_get\` etag).
33606
+
33607
+ ## Red lines
33608
+ - Never exfiltrate private data \u2014 don't copy someone's files, secrets, or
33609
+ conversations off their machine or to a third party without being asked.
33610
+ - No destructive commands without explicit confirmation. Prefer \`trash\` over
33611
+ \`rm\`, a moved file over a deleted one, a dry run over a live one.
33612
+ - When something is irreversible, stop and ask first.
33613
+
33614
+ ## External vs internal
33615
+ - **Reading and exploring is free** \u2014 browse the web, read files, run
33616
+ read-only commands, take a screenshot. Do it without ceremony.
33617
+ - **Anything that leaves the box needs a green light** \u2014 sending an email,
33618
+ posting somewhere, messaging a third party, pushing code. Confirm intent,
33619
+ show what you're about to send, then send.
33620
+
33621
+ ## External channels (Telegram, and future ones)
33622
+ You can be reached over Telegram today (one forum topic per agent), and more
33623
+ channels \u2014 WhatsApp, Signal, Discord \u2014 are on the way. The rules are the same
33624
+ everywhere:
33625
+ - **Formatting.** Chat apps aren't terminals. Keep messages short. Telegram
33626
+ renders a limited Markdown subset \u2014 prefer plain text, short \`code\` spans,
33627
+ and the occasional bullet over big headings, tables, or fenced blocks that
33628
+ won't render. WhatsApp/Signal are plainer still.
33629
+ - **Know when to speak.** In a one-on-one topic, reply normally. In a group,
33630
+ speak when you're addressed, when you can genuinely add something, or when
33631
+ asked \u2014 not on every message. Silence is a valid response.
33632
+ - **React like a human.** A \u{1F44D} or a one-line acknowledgement often beats a
33633
+ paragraph. Match the human's energy and message length; don't answer a
33634
+ three-word question with an essay.
33635
+ - **Avoid the Triple-Tap.** Don't fire off three messages in a row where one
33636
+ would do. Compose the whole thought, then send it once.
33637
+
33638
+ ## Peers & routing
33639
+ Document the other agents you can reach and when to involve them. If you're the
33640
+ only agent in this workspace, leave this short.
33641
+ - (name): what they're good at, when to hand off
33642
+
33643
+ ## Tools
33644
+ Tool-specific patterns and gotchas live in TOOLS.md. Generic tool behaviour
33645
+ comes from the tool descriptions themselves \u2014 don't duplicate those here.
33646
+ `;
33647
+ var DEFAULT_TOOLS = `# TOOLS.md \u2014 Tool Playbook
33648
+
33649
+ Local notes on tool usage that are specific to *this* agent and *this*
33650
+ environment. Generic tool docs come from the tool descriptions \u2014 keep those
33651
+ out. This is the place for the small, concrete facts that save you a round-trip
33652
+ every session.
33653
+
33654
+ ## Environment notes
33655
+ Fill these in as you learn them \u2014 they're the kind of thing you'd otherwise
33656
+ re-ask every session:
33657
+ - **Devices / nicknames:** _(e.g. "the NAS" = 192.168.1.10, "the pi" = the
33658
+ living-room Raspberry Pi)_
33659
+ - **SSH hosts:** _(host \u2192 what it's for, which key)_
33660
+ - **Voice / TTS prefs:** _(preferred voice, when to speak vs stay quiet)_
33661
+ - **Cameras / feeds:** _(name \u2192 location)_
33662
+
33663
+ ## Patterns
33664
+ - (pattern): when to use, what to avoid
33665
+ `;
33666
+ var DEFAULT_HEARTBEAT = `# HEARTBEAT.md \u2014 Scheduled Wake-Ups
33667
+
33668
+ Tasks the agent should check on every heartbeat. Leave empty (or commented)
33669
+ to opt out \u2014 an empty file means "nothing to do right now".
33670
+
33671
+ ## Tasks
33672
+ - (task): cadence, exit criteria
33673
+ `;
33674
+
33675
+ // ../daemon/src/core/repos/groups.ts
33395
33676
  function toGroup(r, paths) {
33396
33677
  return {
33397
33678
  id: r.id,
@@ -33404,16 +33685,18 @@ function toGroup(r, paths) {
33404
33685
  }
33405
33686
  function insert2(db, g, paths) {
33406
33687
  const now = Date.now();
33407
- db.raw.run("INSERT INTO groups (id, name, user_md, created_at) VALUES (?, ?, '', ?)", [
33688
+ const userMd = g.userMd && g.userMd.length > 0 ? g.userMd : DEFAULT_USER_MD;
33689
+ db.raw.run("INSERT INTO groups (id, name, user_md, created_at) VALUES (?, ?, ?, ?)", [
33408
33690
  g.id,
33409
33691
  g.name,
33692
+ userMd,
33410
33693
  now
33411
33694
  ]);
33412
33695
  return {
33413
33696
  id: g.id,
33414
33697
  name: g.name,
33415
33698
  path: paths.groupDir(g.id),
33416
- userMd: "",
33699
+ userMd,
33417
33700
  telegramTopicNameFormat: null,
33418
33701
  createdAt: now
33419
33702
  };
@@ -33518,6 +33801,7 @@ function getDefaultSkills(db, profileId) {
33518
33801
  function resolveAgent(db, paths, agentId) {
33519
33802
  const agent = get(db, agentId);
33520
33803
  if (!agent) throw new Error(`agent not found: ${agentId}`);
33804
+ agent.identity = loadIdentityFromFile(join(agent.dir, "IDENTITY.md"));
33521
33805
  const profile = get3(db, agent.profileId);
33522
33806
  if (!profile) {
33523
33807
  throw new Error(`profile not found for agent ${agentId}: ${agent.profileId}`);
@@ -33538,68 +33822,24 @@ function resolveAgent(db, paths, agentId) {
33538
33822
 
33539
33823
  // ../daemon/src/core/agent/spawn.ts
33540
33824
  import { randomUUID } from "crypto";
33541
- import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync2 } from "fs";
33542
- import { join as join4 } from "path";
33825
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
33826
+ import { join as join6 } from "path";
33543
33827
 
33544
33828
  // ../daemon/src/core/profile/load.ts
33545
33829
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
33546
- import { join } from "path";
33547
-
33548
- // ../daemon/src/core/profile/identity.ts
33549
- import { readFileSync } from "fs";
33550
- var IDENTITY_PLACEHOLDER_VALUES = /* @__PURE__ */ new Set([
33551
- "pick something you like",
33552
- "ai? robot? familiar? ghost in the machine? something weirder?",
33553
- "how do you come across? sharp? warm? chaotic? calm?",
33554
- "your signature - pick one that feels right",
33555
- "workspace-relative path, http(s) url, or data uri"
33556
- ]);
33557
- function normalizeIdentityValue(value) {
33558
- let normalized = value.trim();
33559
- normalized = normalized.replace(/^[*_]+|[*_]+$/g, "").trim();
33560
- if (normalized.startsWith("(") && normalized.endsWith(")")) {
33561
- normalized = normalized.slice(1, -1).trim();
33562
- }
33563
- normalized = normalized.replace(/[\u2013\u2014]/g, "-");
33564
- normalized = normalized.replace(/\s+/g, " ").toLowerCase();
33565
- return normalized;
33566
- }
33567
- function isIdentityPlaceholder(value) {
33568
- return IDENTITY_PLACEHOLDER_VALUES.has(normalizeIdentityValue(value));
33569
- }
33570
- function parseIdentityMarkdown(content) {
33571
- const identity = {};
33572
- for (const line of content.split(/\r?\n/)) {
33573
- const cleaned = line.trim().replace(/^\s*-\s*/, "");
33574
- const colonIndex = cleaned.indexOf(":");
33575
- if (colonIndex === -1) continue;
33576
- const label = cleaned.slice(0, colonIndex).replace(/[*_]/g, "").trim().toLowerCase();
33577
- const value = cleaned.slice(colonIndex + 1).replace(/^[*_]+|[*_]+$/g, "").trim();
33578
- if (!value) continue;
33579
- if (isIdentityPlaceholder(value)) continue;
33580
- if (label === "name") identity.name = value;
33581
- else if (label === "emoji") identity.emoji = value;
33582
- else if (label === "creature") identity.creature = value;
33583
- else if (label === "vibe") identity.vibe = value;
33584
- else if (label === "theme") identity.theme = value;
33585
- else if (label === "avatar") identity.avatar = value;
33586
- }
33587
- return identity;
33588
- }
33589
-
33590
- // ../daemon/src/core/profile/load.ts
33830
+ import { join as join2 } from "path";
33591
33831
  function readOptional(path) {
33592
33832
  return existsSync2(path) ? readFileSync2(path, "utf8") : null;
33593
33833
  }
33594
33834
  function loadProfile(db, id) {
33595
33835
  const profile = get3(db, id);
33596
33836
  if (!profile) throw new Error(`profile not found: ${id}`);
33597
- const soul = readFileSync2(join(profile.dir, "SOUL.md"), "utf8");
33598
- const identityRaw = readFileSync2(join(profile.dir, "IDENTITY.md"), "utf8");
33599
- const bootstrap2 = readOptional(join(profile.dir, "BOOTSTRAP.md"));
33600
- const agents = readOptional(join(profile.dir, "AGENTS.md"));
33601
- const tools = readOptional(join(profile.dir, "TOOLS.md"));
33602
- const heartbeat = readOptional(join(profile.dir, "HEARTBEAT.md"));
33837
+ const soul = readFileSync2(join2(profile.dir, "SOUL.md"), "utf8");
33838
+ const identityRaw = readFileSync2(join2(profile.dir, "IDENTITY.md"), "utf8");
33839
+ const bootstrap2 = readOptional(join2(profile.dir, "BOOTSTRAP.md"));
33840
+ const agents = readOptional(join2(profile.dir, "AGENTS.md"));
33841
+ const tools = readOptional(join2(profile.dir, "TOOLS.md"));
33842
+ const heartbeat = readOptional(join2(profile.dir, "HEARTBEAT.md"));
33603
33843
  const parsedIdentity = parseIdentityMarkdown(identityRaw);
33604
33844
  const anyIdentity = parsedIdentity.name || parsedIdentity.emoji || parsedIdentity.theme || parsedIdentity.creature || parsedIdentity.vibe || parsedIdentity.avatar;
33605
33845
  return {
@@ -33617,6 +33857,10 @@ function loadProfile(db, id) {
33617
33857
  };
33618
33858
  }
33619
33859
 
33860
+ // ../daemon/src/core/profile/seed.ts
33861
+ import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
33862
+ import { join as join4 } from "path";
33863
+
33620
33864
  // ../daemon/src/core/repos/providerModels.ts
33621
33865
  var providerModels_exports = {};
33622
33866
  __export(providerModels_exports, {
@@ -33754,62 +33998,7 @@ function registerGroup(db, input, paths) {
33754
33998
 
33755
33999
  // ../daemon/src/core/profile/create.ts
33756
34000
  import { mkdirSync as mkdirSync2, writeFileSync } from "fs";
33757
- import { join as join2 } from "path";
33758
-
33759
- // ../daemon/src/core/profile/templates.ts
33760
- var DEFAULT_SOUL = `# SOUL.md \u2014 Who You Are
33761
-
33762
- This is your personality and operating principles. Edit it freely to make this agent yours.
33763
-
33764
- ## Core
33765
- - Be genuinely helpful, not performatively helpful.
33766
- - Have opinions. Push back when you disagree.
33767
- - Be resourceful before asking \u2014 read the file, check context, then ask if stuck.
33768
-
33769
- ## Boundaries
33770
- - Private things stay private.
33771
- - Confirm before destructive or external actions.
33772
- - You're a guest in someone's environment. Treat it with respect.
33773
- `;
33774
- var DEFAULT_IDENTITY = `# IDENTITY.md \u2014 Who Am I?
33775
-
33776
- Fill this in during your first conversation. Make it yours.
33777
-
33778
- - **Name:**
33779
- - **Vibe:**
33780
- - **Emoji:**
33781
- `;
33782
- var DEFAULT_BOOTSTRAP = `# BOOTSTRAP.md \u2014 First Run
33783
-
33784
- You just woke up. There is no memory yet \u2014 that's normal. This is a multi-turn
33785
- ritual: ask ONE question per turn and wait for the human's reply before moving
33786
- on. Do not race through it. Do not call any tool until the ritual is finished.
33787
-
33788
- ## The ritual
33789
-
33790
- **Turn 1 (right now):** Greet the human warmly and ask a single opening
33791
- question \u2014 what should they call you, or what should you focus on for them.
33792
- Do NOT call any tool yet. Just reply with greeting + one question.
33793
-
33794
- **Turn 2+:** Continue with one more question per turn to fill in the rest of
33795
- your identity \u2014 vibe (warm / sharp / playful / calm / \u2026), an emoji that
33796
- feels right. Each turn is acknowledging the previous answer + at most one
33797
- new question. Skip a turn when you already have enough.
33798
-
33799
- **Final turn:** Once you have everything (Name, Vibe, Emoji), call \`home_write\`
33800
- with \`file: "IDENTITY.md"\` and the populated content. Do NOT use the generic
33801
- \`edit\` / \`write\` tools \u2014 those land in the shared workspace.
33802
-
33803
- Then call \`bootstrap_done\` to retire this ritual file. After that, future
33804
- sessions skip the bootstrap and start from IDENTITY.md directly.
33805
-
33806
- ## Hard rules
33807
- - Do not invent a name on your own. Ask the human and use what they say.
33808
- - Do not call \`home_write\` or \`bootstrap_done\` on your very first reply.
33809
- - One question per turn. Wait for the human to answer.
33810
- `;
33811
-
33812
- // ../daemon/src/core/profile/create.ts
34001
+ import { join as join3 } from "path";
33813
34002
  function createProfile(db, paths, input) {
33814
34003
  validateSlug(input.id);
33815
34004
  const dir = paths.profileDir(input.id);
@@ -33817,19 +34006,22 @@ function createProfile(db, paths, input) {
33817
34006
  const soul = input.templates?.soul ?? DEFAULT_SOUL;
33818
34007
  const identity = input.templates?.identity ?? DEFAULT_IDENTITY;
33819
34008
  const bootstrap2 = input.templates?.bootstrap === null ? null : input.templates?.bootstrap ?? DEFAULT_BOOTSTRAP;
33820
- writeFileSync(join2(dir, "SOUL.md"), soul);
33821
- writeFileSync(join2(dir, "IDENTITY.md"), identity);
34009
+ const agents = input.templates?.agents === null ? null : input.templates?.agents ?? DEFAULT_AGENTS;
34010
+ const tools = input.templates?.tools === null ? null : input.templates?.tools ?? DEFAULT_TOOLS;
34011
+ const heartbeat = typeof input.templates?.heartbeat === "string" ? input.templates.heartbeat : null;
34012
+ writeFileSync(join3(dir, "SOUL.md"), soul);
34013
+ writeFileSync(join3(dir, "IDENTITY.md"), identity);
33822
34014
  if (bootstrap2 !== null) {
33823
- writeFileSync(join2(dir, "BOOTSTRAP.md"), bootstrap2);
34015
+ writeFileSync(join3(dir, "BOOTSTRAP.md"), bootstrap2);
33824
34016
  }
33825
- if (typeof input.templates?.agents === "string") {
33826
- writeFileSync(join2(dir, "AGENTS.md"), input.templates.agents);
34017
+ if (agents !== null) {
34018
+ writeFileSync(join3(dir, "AGENTS.md"), agents);
33827
34019
  }
33828
- if (typeof input.templates?.tools === "string") {
33829
- writeFileSync(join2(dir, "TOOLS.md"), input.templates.tools);
34020
+ if (tools !== null) {
34021
+ writeFileSync(join3(dir, "TOOLS.md"), tools);
33830
34022
  }
33831
- if (typeof input.templates?.heartbeat === "string") {
33832
- writeFileSync(join2(dir, "HEARTBEAT.md"), input.templates.heartbeat);
34023
+ if (heartbeat !== null) {
34024
+ writeFileSync(join3(dir, "HEARTBEAT.md"), heartbeat);
33833
34025
  }
33834
34026
  const skillsMode = input.skillsMode ?? "selected";
33835
34027
  const profileJson = {
@@ -33838,7 +34030,7 @@ function createProfile(db, paths, input) {
33838
34030
  skillsMode,
33839
34031
  defaultSkills: input.defaultSkills ?? []
33840
34032
  };
33841
- writeFileSync(join2(dir, "profile.json"), `${JSON.stringify(profileJson, null, 2)}
34033
+ writeFileSync(join3(dir, "profile.json"), `${JSON.stringify(profileJson, null, 2)}
33842
34034
  `);
33843
34035
  const profile = insert3(db, {
33844
34036
  id: input.id,
@@ -33856,6 +34048,26 @@ function createProfile(db, paths, input) {
33856
34048
  // ../daemon/src/core/profile/seed.ts
33857
34049
  var DEFAULT_PROFILE_ID = "default";
33858
34050
  var DEFAULT_GROUP_ID = "default";
34051
+ var DEFAULT_PROFILE_FILES = [
34052
+ ["SOUL.md", DEFAULT_SOUL],
34053
+ ["IDENTITY.md", DEFAULT_IDENTITY],
34054
+ ["BOOTSTRAP.md", DEFAULT_BOOTSTRAP],
34055
+ ["AGENTS.md", DEFAULT_AGENTS],
34056
+ ["TOOLS.md", DEFAULT_TOOLS]
34057
+ ];
34058
+ function refreshDefaultProfileTemplates(paths) {
34059
+ const dir = paths.profileDir(DEFAULT_PROFILE_ID);
34060
+ if (!existsSync4(dir)) return [];
34061
+ const written = [];
34062
+ for (const [name, content] of DEFAULT_PROFILE_FILES) {
34063
+ const path = join4(dir, name);
34064
+ if (!existsSync4(path) || readFileSync3(path, "utf8") !== content) {
34065
+ writeFileSync2(path, content);
34066
+ written.push(name);
34067
+ }
34068
+ }
34069
+ return written;
34070
+ }
33859
34071
  function seedDefaults(db, paths, input) {
33860
34072
  let group = get2(db, DEFAULT_GROUP_ID, paths);
33861
34073
  let groupCreated = false;
@@ -33885,17 +34097,17 @@ function ensureSetupSeeded(db, paths) {
33885
34097
  }
33886
34098
 
33887
34099
  // ../daemon/src/core/skills/discover.ts
33888
- import { existsSync as existsSync4, readdirSync } from "fs";
33889
- import { join as join3 } from "path";
34100
+ import { existsSync as existsSync5, readdirSync } from "fs";
34101
+ import { join as join5 } from "path";
33890
34102
  function discoverSkills(paths) {
33891
- if (!existsSync4(paths.skillsDir)) return [];
34103
+ if (!existsSync5(paths.skillsDir)) return [];
33892
34104
  const entries = readdirSync(paths.skillsDir, { withFileTypes: true });
33893
34105
  const skills = [];
33894
34106
  for (const entry of entries) {
33895
34107
  if (!entry.isDirectory()) continue;
33896
- const dir = join3(paths.skillsDir, entry.name);
33897
- const skillFile = join3(dir, "SKILL.md");
33898
- if (!existsSync4(skillFile)) continue;
34108
+ const dir = join5(paths.skillsDir, entry.name);
34109
+ const skillFile = join5(dir, "SKILL.md");
34110
+ if (!existsSync5(skillFile)) continue;
33899
34111
  skills.push({ name: entry.name, dir, skillFile });
33900
34112
  }
33901
34113
  return skills.sort((a, b) => a.name.localeCompare(b.name));
@@ -33907,20 +34119,20 @@ function spawnAgent(db, paths, input) {
33907
34119
  const id = randomUUID();
33908
34120
  const dir = paths.agentDir(id);
33909
34121
  mkdirSync3(dir, { recursive: true });
33910
- mkdirSync3(join4(dir, "sessions"), { recursive: true });
33911
- writeFileSync2(join4(dir, "SOUL.md"), loaded.files.soul);
33912
- writeFileSync2(join4(dir, "IDENTITY.md"), loaded.files.identity);
34122
+ mkdirSync3(join6(dir, "sessions"), { recursive: true });
34123
+ writeFileSync3(join6(dir, "SOUL.md"), loaded.files.soul);
34124
+ writeFileSync3(join6(dir, "IDENTITY.md"), loaded.files.identity);
33913
34125
  if (loaded.files.bootstrap !== null) {
33914
- writeFileSync2(join4(dir, "BOOTSTRAP.md"), loaded.files.bootstrap);
34126
+ writeFileSync3(join6(dir, "BOOTSTRAP.md"), loaded.files.bootstrap);
33915
34127
  }
33916
34128
  if (loaded.files.agents !== null) {
33917
- writeFileSync2(join4(dir, "AGENTS.md"), loaded.files.agents);
34129
+ writeFileSync3(join6(dir, "AGENTS.md"), loaded.files.agents);
33918
34130
  }
33919
34131
  if (loaded.files.tools !== null) {
33920
- writeFileSync2(join4(dir, "TOOLS.md"), loaded.files.tools);
34132
+ writeFileSync3(join6(dir, "TOOLS.md"), loaded.files.tools);
33921
34133
  }
33922
34134
  if (loaded.files.heartbeat !== null) {
33923
- writeFileSync2(join4(dir, "HEARTBEAT.md"), loaded.files.heartbeat);
34135
+ writeFileSync3(join6(dir, "HEARTBEAT.md"), loaded.files.heartbeat);
33924
34136
  }
33925
34137
  const reasoningLevel = input.reasoningLevel ?? "medium";
33926
34138
  const groupId = input.groupId ?? DEFAULT_GROUP_ID;
@@ -33937,7 +34149,7 @@ function spawnAgent(db, paths, input) {
33937
34149
  reasoningLevel,
33938
34150
  groupId: group.id
33939
34151
  };
33940
- writeFileSync2(join4(dir, "agent.json"), `${JSON.stringify(agentJson, null, 2)}
34152
+ writeFileSync3(join6(dir, "agent.json"), `${JSON.stringify(agentJson, null, 2)}
33941
34153
  `);
33942
34154
  const agent = insert(db, {
33943
34155
  id,
@@ -34039,10 +34251,10 @@ function inTx(db, fn) {
34039
34251
  }
34040
34252
 
34041
34253
  // ../daemon/src/core/db/migrate.ts
34042
- import { readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
34043
- import { dirname, join as join5 } from "path";
34254
+ import { readdirSync as readdirSync2, readFileSync as readFileSync4 } from "fs";
34255
+ import { dirname, join as join7 } from "path";
34044
34256
  import { fileURLToPath } from "url";
34045
- var migrationsDir = join5(dirname(fileURLToPath(import.meta.url)), "migrations");
34257
+ var migrationsDir = join7(dirname(fileURLToPath(import.meta.url)), "migrations");
34046
34258
  function runMigrations(db) {
34047
34259
  db.raw.exec(`
34048
34260
  CREATE TABLE IF NOT EXISTS schema_migrations (
@@ -34057,7 +34269,7 @@ function runMigrations(db) {
34057
34269
  for (const file of files) {
34058
34270
  const version2 = file.replace(/\.sql$/, "");
34059
34271
  if (applied.has(version2)) continue;
34060
- const sql = readFileSync3(join5(migrationsDir, file), "utf8");
34272
+ const sql = readFileSync4(join7(migrationsDir, file), "utf8");
34061
34273
  const tx = db.raw.transaction(() => {
34062
34274
  db.raw.exec(sql);
34063
34275
  db.raw.run("INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)", [
@@ -34085,35 +34297,35 @@ function deleteGroup(db, paths, id) {
34085
34297
 
34086
34298
  // ../daemon/src/core/paths.ts
34087
34299
  import { homedir } from "os";
34088
- import { join as join6 } from "path";
34300
+ import { join as join8 } from "path";
34089
34301
  function resolvePaths(home) {
34090
- const root = home ?? process.env.BAZILION_HOME ?? join6(homedir(), ".bazilion");
34302
+ const root = home ?? process.env.BAZILION_HOME ?? join8(homedir(), ".bazilion");
34091
34303
  return {
34092
34304
  home: root,
34093
- db: join6(root, "bazilion.db"),
34094
- authFile: join6(root, "auth.json"),
34095
- profilesDir: join6(root, "profiles"),
34096
- agentsDir: join6(root, "agents"),
34097
- skillsDir: join6(root, "skills"),
34098
- groupsDir: join6(root, "groups"),
34099
- logsDir: join6(root, "logs"),
34305
+ db: join8(root, "bazilion.db"),
34306
+ authFile: join8(root, "auth.json"),
34307
+ profilesDir: join8(root, "profiles"),
34308
+ agentsDir: join8(root, "agents"),
34309
+ skillsDir: join8(root, "skills"),
34310
+ groupsDir: join8(root, "groups"),
34311
+ logsDir: join8(root, "logs"),
34100
34312
  profileDir(id) {
34101
- return join6(root, "profiles", id);
34313
+ return join8(root, "profiles", id);
34102
34314
  },
34103
34315
  agentDir(id) {
34104
- return join6(root, "agents", id);
34316
+ return join8(root, "agents", id);
34105
34317
  },
34106
34318
  skillDir(name) {
34107
- return join6(root, "skills", name);
34319
+ return join8(root, "skills", name);
34108
34320
  },
34109
34321
  groupDir(slug) {
34110
- return join6(root, "groups", slug);
34322
+ return join8(root, "groups", slug);
34111
34323
  }
34112
34324
  };
34113
34325
  }
34114
34326
 
34115
34327
  // ../daemon/src/core/profile/delete.ts
34116
- import { existsSync as existsSync5, rmSync as rmSync2 } from "fs";
34328
+ import { existsSync as existsSync6, rmSync as rmSync2 } from "fs";
34117
34329
 
34118
34330
  // ../daemon/src/core/repos/profileGroups.ts
34119
34331
  var profileGroups_exports = {};
@@ -34249,14 +34461,14 @@ function deleteProfile(db, id) {
34249
34461
  );
34250
34462
  }
34251
34463
  remove3(db, id);
34252
- if (existsSync5(profile.dir)) {
34464
+ if (existsSync6(profile.dir)) {
34253
34465
  rmSync2(profile.dir, { recursive: true, force: true });
34254
34466
  }
34255
34467
  }
34256
34468
 
34257
34469
  // ../daemon/src/core/profile/update.ts
34258
- import { writeFileSync as writeFileSync3 } from "fs";
34259
- import { join as join7 } from "path";
34470
+ import { writeFileSync as writeFileSync4 } from "fs";
34471
+ import { join as join9 } from "path";
34260
34472
  function updateProfile(db, paths, id, input) {
34261
34473
  const existing = get3(db, id);
34262
34474
  if (!existing) throw new Error(`profile not found: ${id}`);
@@ -34277,8 +34489,8 @@ function updateProfile(db, paths, id, input) {
34277
34489
  skillsMode: next.skillsMode,
34278
34490
  defaultSkills: skills
34279
34491
  };
34280
- writeFileSync3(
34281
- join7(paths.profileDir(id), "profile.json"),
34492
+ writeFileSync4(
34493
+ join9(paths.profileDir(id), "profile.json"),
34282
34494
  `${JSON.stringify(profileJson, null, 2)}
34283
34495
  `
34284
34496
  );
@@ -35418,14 +35630,14 @@ function revoke(db, id, when = Date.now()) {
35418
35630
  }
35419
35631
 
35420
35632
  // ../daemon/src/core/secrets.ts
35421
- import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
35633
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
35422
35634
  function readAuthFile(authFile) {
35423
- if (!existsSync6(authFile)) {
35635
+ if (!existsSync7(authFile)) {
35424
35636
  throw new Error(
35425
35637
  `${authFile} not found. Start the daemon (\`bazilion serve\`) \u2014 it auto-bootstraps on first run.`
35426
35638
  );
35427
35639
  }
35428
- const raw = readFileSync4(authFile, "utf8");
35640
+ const raw = readFileSync5(authFile, "utf8");
35429
35641
  const parsed = JSON.parse(raw);
35430
35642
  if (typeof parsed.token !== "string" || !parsed.token) {
35431
35643
  throw new Error(`${authFile} is missing the "token" field`);
@@ -35450,13 +35662,13 @@ function mergeSecretsIntoEnv(db, password, env = process.env) {
35450
35662
  }
35451
35663
 
35452
35664
  // ../daemon/src/core/skills/import.ts
35453
- import { cpSync, existsSync as existsSync7, mkdtempSync, readdirSync as readdirSync4, rmSync as rmSync5, statSync as statSync2 } from "fs";
35665
+ import { cpSync, existsSync as existsSync8, mkdtempSync, readdirSync as readdirSync4, rmSync as rmSync5, statSync as statSync2 } from "fs";
35454
35666
  import { tmpdir } from "os";
35455
- import { basename, join as join8, resolve as resolve2, sep } from "path";
35667
+ import { basename, join as join10, resolve as resolve2, sep } from "path";
35456
35668
  import AdmZip from "adm-zip";
35457
35669
 
35458
35670
  // ../daemon/src/core/skills/parse.ts
35459
- import { readFileSync as readFileSync5 } from "fs";
35671
+ import { readFileSync as readFileSync6 } from "fs";
35460
35672
  import { parse as parseYaml } from "yaml";
35461
35673
  var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
35462
35674
  function parseSkillContent(raw) {
@@ -35485,13 +35697,13 @@ function parseSkillContent(raw) {
35485
35697
  return { frontmatter: fmObj, body, raw };
35486
35698
  }
35487
35699
  function parseSkillFile(path) {
35488
- const raw = readFileSync5(path, "utf8");
35700
+ const raw = readFileSync6(path, "utf8");
35489
35701
  return parseSkillContent(raw);
35490
35702
  }
35491
35703
 
35492
35704
  // ../daemon/src/core/skills/import.ts
35493
35705
  function extractZipSafely(zipPath) {
35494
- const root = mkdtempSync(join8(tmpdir(), "bazilion-skill-zip-"));
35706
+ const root = mkdtempSync(join10(tmpdir(), "bazilion-skill-zip-"));
35495
35707
  try {
35496
35708
  const zip = new AdmZip(zipPath);
35497
35709
  for (const entry of zip.getEntries()) {
@@ -35512,13 +35724,13 @@ function extractZipSafely(zipPath) {
35512
35724
  let effectiveSource = root;
35513
35725
  const topEntries = readdirSync4(root, { withFileTypes: true });
35514
35726
  if (topEntries.length === 1 && topEntries[0]?.isDirectory()) {
35515
- effectiveSource = join8(root, topEntries[0].name);
35727
+ effectiveSource = join10(root, topEntries[0].name);
35516
35728
  }
35517
35729
  return { root, effectiveSource };
35518
35730
  }
35519
35731
  function importSkills(paths, input) {
35520
35732
  const rawSource = resolve2(input.source);
35521
- if (!existsSync7(rawSource)) {
35733
+ if (!existsSync8(rawSource)) {
35522
35734
  throw new Error(`source does not exist: ${rawSource}`);
35523
35735
  }
35524
35736
  let source = rawSource;
@@ -35542,14 +35754,14 @@ function importSkills(paths, input) {
35542
35754
  }
35543
35755
  function importSkillsFromDir(paths, source, input) {
35544
35756
  const candidates = [];
35545
- if (existsSync7(join8(source, "SKILL.md"))) {
35757
+ if (existsSync8(join10(source, "SKILL.md"))) {
35546
35758
  candidates.push({ name: basename(source), dir: source });
35547
35759
  } else {
35548
35760
  const entries = readdirSync4(source, { withFileTypes: true });
35549
35761
  for (const e of entries) {
35550
35762
  if (!e.isDirectory()) continue;
35551
- const skillDir = join8(source, e.name);
35552
- if (!existsSync7(join8(skillDir, "SKILL.md"))) continue;
35763
+ const skillDir = join10(source, e.name);
35764
+ if (!existsSync8(join10(skillDir, "SKILL.md"))) continue;
35553
35765
  candidates.push({ name: e.name, dir: skillDir });
35554
35766
  }
35555
35767
  }
@@ -35557,13 +35769,13 @@ function importSkillsFromDir(paths, source, input) {
35557
35769
  throw new Error(`no skills found in ${source}`);
35558
35770
  }
35559
35771
  for (const c of candidates) {
35560
- parseSkillFile(join8(c.dir, "SKILL.md"));
35772
+ parseSkillFile(join10(c.dir, "SKILL.md"));
35561
35773
  }
35562
35774
  const imported = [];
35563
35775
  const skipped = [];
35564
35776
  for (const c of candidates) {
35565
- const target = join8(paths.skillsDir, c.name);
35566
- if (existsSync7(target) && !input.force) {
35777
+ const target = join10(paths.skillsDir, c.name);
35778
+ if (existsSync8(target) && !input.force) {
35567
35779
  skipped.push({
35568
35780
  name: c.name,
35569
35781
  reason: "already exists (use --force to overwrite)"
@@ -35599,7 +35811,7 @@ function resolveAgentSkills(db, paths, agentId) {
35599
35811
  }
35600
35812
 
35601
35813
  // ../daemon/src/lib/ctx.ts
35602
- import { chmodSync, existsSync as existsSync14, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
35814
+ import { chmodSync, existsSync as existsSync15, mkdirSync as mkdirSync8, writeFileSync as writeFileSync9 } from "fs";
35603
35815
 
35604
35816
  // ../daemon/src/lib/agent-cancel.ts
35605
35817
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("bazilion.agent-cancel.registry");
@@ -35705,27 +35917,27 @@ var DEFAULT_HEARTBEAT_EVERY_SEC = 30 * 60;
35705
35917
 
35706
35918
  // ../daemon/src/runtime/memory/files.ts
35707
35919
  import {
35708
- existsSync as existsSync8,
35920
+ existsSync as existsSync9,
35709
35921
  mkdirSync as mkdirSync4,
35710
35922
  readdirSync as readdirSync5,
35711
- readFileSync as readFileSync6,
35923
+ readFileSync as readFileSync7,
35712
35924
  rmSync as rmSync6,
35713
35925
  statSync as statSync3,
35714
- writeFileSync as writeFileSync4
35926
+ writeFileSync as writeFileSync5
35715
35927
  } from "fs";
35716
- import { dirname as dirname2, join as join9 } from "path";
35928
+ import { dirname as dirname2, join as join11 } from "path";
35717
35929
 
35718
35930
  // ../daemon/src/runtime/memory/qmd.ts
35719
35931
  import {
35720
- existsSync as existsSync9,
35932
+ existsSync as existsSync10,
35721
35933
  mkdirSync as mkdirSync5,
35722
35934
  readdirSync as readdirSync6,
35723
- readFileSync as readFileSync7,
35935
+ readFileSync as readFileSync8,
35724
35936
  rmSync as rmSync7,
35725
35937
  statSync as statSync4,
35726
- writeFileSync as writeFileSync5
35938
+ writeFileSync as writeFileSync6
35727
35939
  } from "fs";
35728
- import { dirname as dirname3, join as join10 } from "path";
35940
+ import { dirname as dirname3, join as join12 } from "path";
35729
35941
  import { createStore, extractSnippet } from "@tobilu/qmd";
35730
35942
  var INDEX_FILENAME = ".qmd-index.sqlite";
35731
35943
  var COLLECTION_NAME = "memory";
@@ -35735,7 +35947,7 @@ function getStore(dir) {
35735
35947
  let p = storeCache.get(dir);
35736
35948
  if (!p) {
35737
35949
  p = createStore({
35738
- dbPath: join10(dir, INDEX_FILENAME),
35950
+ dbPath: join12(dir, INDEX_FILENAME),
35739
35951
  config: {
35740
35952
  collections: {
35741
35953
  [COLLECTION_NAME]: { path: dir, pattern: PATTERN }
@@ -35750,13 +35962,13 @@ function safeKey(root, key2) {
35750
35962
  if (key2.includes("..") || key2.startsWith("/") || key2.includes("\0")) {
35751
35963
  throw new Error(`unsafe memory key: ${key2}`);
35752
35964
  }
35753
- return join10(root, key2);
35965
+ return join12(root, key2);
35754
35966
  }
35755
35967
  function walkMd(dir, prefix, out) {
35756
- if (!existsSync9(dir)) return;
35968
+ if (!existsSync10(dir)) return;
35757
35969
  for (const e of readdirSync6(dir, { withFileTypes: true })) {
35758
35970
  if (e.name.startsWith(".")) continue;
35759
- const full = join10(dir, e.name);
35971
+ const full = join12(dir, e.name);
35760
35972
  const key2 = prefix ? `${prefix}/${e.name}` : e.name;
35761
35973
  if (e.isDirectory()) {
35762
35974
  walkMd(full, key2, out);
@@ -35764,7 +35976,7 @@ function walkMd(dir, prefix, out) {
35764
35976
  const stats = statSync4(full);
35765
35977
  out.push({
35766
35978
  key: key2,
35767
- content: readFileSync7(full, "utf8"),
35979
+ content: readFileSync8(full, "utf8"),
35768
35980
  updatedAt: stats.mtimeMs
35769
35981
  });
35770
35982
  }
@@ -35779,20 +35991,20 @@ function qmdBackend(root) {
35779
35991
  },
35780
35992
  async read(key2) {
35781
35993
  const path = safeKey(root, key2);
35782
- if (!existsSync9(path)) {
35994
+ if (!existsSync10(path)) {
35783
35995
  throw new Error(`memory entry not found: ${key2}`);
35784
35996
  }
35785
35997
  const stats = statSync4(path);
35786
35998
  return {
35787
35999
  key: key2,
35788
- content: readFileSync7(path, "utf8"),
36000
+ content: readFileSync8(path, "utf8"),
35789
36001
  updatedAt: stats.mtimeMs
35790
36002
  };
35791
36003
  },
35792
36004
  async write(key2, content) {
35793
36005
  const path = safeKey(root, key2);
35794
36006
  mkdirSync5(dirname3(path), { recursive: true });
35795
- writeFileSync5(path, content);
36007
+ writeFileSync6(path, content);
35796
36008
  const stats = statSync4(path);
35797
36009
  const store = await getStore(root);
35798
36010
  await store.update();
@@ -35812,7 +36024,7 @@ function qmdBackend(root) {
35812
36024
  let content = r.body ?? "";
35813
36025
  if (!content) {
35814
36026
  try {
35815
- content = readFileSync7(join10(root, key2), "utf8");
36027
+ content = readFileSync8(join12(root, key2), "utf8");
35816
36028
  } catch {
35817
36029
  content = "";
35818
36030
  }
@@ -35829,7 +36041,7 @@ function qmdBackend(root) {
35829
36041
  },
35830
36042
  async remove(key2) {
35831
36043
  const path = safeKey(root, key2);
35832
- if (existsSync9(path)) rmSync7(path);
36044
+ if (existsSync10(path)) rmSync7(path);
35833
36045
  const store = await getStore(root);
35834
36046
  await store.update();
35835
36047
  }
@@ -35919,8 +36131,8 @@ function piMessagesToProviderView(messages) {
35919
36131
  }
35920
36132
 
35921
36133
  // ../daemon/src/runtime/pi/session.ts
35922
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, readdirSync as readdirSync8, statSync as statSync7 } from "fs";
35923
- import { basename as basename3, join as join14 } from "path";
36134
+ import { existsSync as existsSync13, mkdirSync as mkdirSync6, readdirSync as readdirSync8, statSync as statSync7 } from "fs";
36135
+ import { basename as basename3, join as join16 } from "path";
35924
36136
  import {
35925
36137
  AuthStorage,
35926
36138
  createAgentSession,
@@ -36675,8 +36887,8 @@ function listAllProviders(config2) {
36675
36887
  }
36676
36888
 
36677
36889
  // ../daemon/src/runtime/session/prompt.ts
36678
- import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
36679
- import { join as join11 } from "path";
36890
+ import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
36891
+ import { join as join13 } from "path";
36680
36892
  var CONTEXT_FILE_ORDER = [
36681
36893
  "AGENTS.md",
36682
36894
  "SOUL.md",
@@ -36688,9 +36900,9 @@ function buildSystemPrompt(agent) {
36688
36900
  const parts = [];
36689
36901
  const contextBlocks = [];
36690
36902
  for (const file of CONTEXT_FILE_ORDER) {
36691
- const path = join11(agent.agent.dir, file);
36692
- if (!existsSync10(path)) continue;
36693
- const content = readFileSync8(path, "utf8").trimEnd();
36903
+ const path = join13(agent.agent.dir, file);
36904
+ if (!existsSync11(path)) continue;
36905
+ const content = readFileSync9(path, "utf8").trimEnd();
36694
36906
  if (!content) continue;
36695
36907
  contextBlocks.push(`## ${file}
36696
36908
 
@@ -36701,9 +36913,9 @@ ${content}`);
36701
36913
 
36702
36914
  ${contextBlocks.join("\n\n")}`);
36703
36915
  }
36704
- const bootstrapPath = join11(agent.agent.dir, "BOOTSTRAP.md");
36705
- if (existsSync10(bootstrapPath)) {
36706
- const bootstrap2 = readFileSync8(bootstrapPath, "utf8").trimEnd();
36916
+ const bootstrapPath = join13(agent.agent.dir, "BOOTSTRAP.md");
36917
+ if (existsSync11(bootstrapPath)) {
36918
+ const bootstrap2 = readFileSync9(bootstrapPath, "utf8").trimEnd();
36707
36919
  if (bootstrap2) {
36708
36920
  parts.push(
36709
36921
  [
@@ -36775,8 +36987,8 @@ This group's USER.md is empty. As you learn STABLE facts about the human (prefer
36775
36987
  import { Type as Type2 } from "typebox";
36776
36988
 
36777
36989
  // ../daemon/src/runtime/tools/bootstrap.ts
36778
- import { existsSync as existsSync11, rmSync as rmSync8 } from "fs";
36779
- import { join as join12 } from "path";
36990
+ import { existsSync as existsSync12, rmSync as rmSync8 } from "fs";
36991
+ import { join as join14 } from "path";
36780
36992
  function bootstrapTool(agentDir) {
36781
36993
  return {
36782
36994
  def: {
@@ -36785,8 +36997,8 @@ function bootstrapTool(agentDir) {
36785
36997
  parameters: { type: "object", properties: {} }
36786
36998
  },
36787
36999
  async invoke() {
36788
- const path = join12(agentDir, "BOOTSTRAP.md");
36789
- if (existsSync11(path)) {
37000
+ const path = join14(agentDir, "BOOTSTRAP.md");
37001
+ if (existsSync12(path)) {
36790
37002
  rmSync8(path);
36791
37003
  return "BOOTSTRAP.md removed. Bootstrap is complete.";
36792
37004
  }
@@ -36925,7 +37137,7 @@ function browserTools(host2, agentId) {
36925
37137
  }
36926
37138
 
36927
37139
  // ../daemon/src/runtime/tools/deliver-file.ts
36928
- import { readFileSync as readFileSync9, statSync as statSync5 } from "fs";
37140
+ import { readFileSync as readFileSync10, statSync as statSync5 } from "fs";
36929
37141
  import { basename as basename2, extname, isAbsolute, resolve as resolve3 } from "path";
36930
37142
  var MAX_DELIVER_BYTES = 25 * 1024 * 1024;
36931
37143
  var MIME = {
@@ -36976,15 +37188,15 @@ function deliverFileTool(cwd, sink) {
36976
37188
  }
36977
37189
  const name = basename2(abs);
36978
37190
  const mimeType = MIME[extname(abs).toLowerCase()] ?? "application/octet-stream";
36979
- sink({ name, mimeType, data: readFileSync9(abs).toString("base64") });
37191
+ sink({ name, mimeType, data: readFileSync10(abs).toString("base64") });
36980
37192
  return `Delivered "${name}" (${mimeType}) to the user.`;
36981
37193
  }
36982
37194
  };
36983
37195
  }
36984
37196
 
36985
37197
  // ../daemon/src/runtime/tools/home.ts
36986
- import { readdirSync as readdirSync7, readFileSync as readFileSync10, statSync as statSync6, writeFileSync as writeFileSync6 } from "fs";
36987
- import { join as join13 } from "path";
37198
+ import { readdirSync as readdirSync7, readFileSync as readFileSync11, statSync as statSync6, writeFileSync as writeFileSync7 } from "fs";
37199
+ import { join as join15 } from "path";
36988
37200
  var HOME_FILES_READABLE = [
36989
37201
  "IDENTITY.md",
36990
37202
  "SOUL.md",
@@ -37021,9 +37233,9 @@ function homeTools(agentDir) {
37021
37233
  `home_read: "file" must be one of ${HOME_FILES_READABLE.join(", ")}; got "${file}"`
37022
37234
  );
37023
37235
  }
37024
- const path = join13(agentDir, file);
37236
+ const path = join15(agentDir, file);
37025
37237
  try {
37026
- return readFileSync10(path, "utf8");
37238
+ return readFileSync11(path, "utf8");
37027
37239
  } catch (err) {
37028
37240
  const msg = err instanceof Error ? err.message : String(err);
37029
37241
  throw new Error(`home_read: could not read ${file}: ${msg}`);
@@ -37051,8 +37263,8 @@ function homeTools(agentDir) {
37051
37263
  );
37052
37264
  }
37053
37265
  const content = typeof args.content === "string" ? args.content : "";
37054
- const path = join13(agentDir, file);
37055
- writeFileSync6(path, content, "utf8");
37266
+ const path = join15(agentDir, file);
37267
+ writeFileSync7(path, content, "utf8");
37056
37268
  return `wrote ${file} (${Buffer.byteLength(content, "utf8")} bytes)`;
37057
37269
  }
37058
37270
  },
@@ -37065,7 +37277,7 @@ function homeTools(agentDir) {
37065
37277
  async invoke() {
37066
37278
  const entries = [];
37067
37279
  for (const file of HOME_FILES_READABLE) {
37068
- const path = join13(agentDir, file);
37280
+ const path = join15(agentDir, file);
37069
37281
  try {
37070
37282
  const s = statSync6(path);
37071
37283
  entries.push(`${file} (${s.size}b)`);
@@ -38010,8 +38222,8 @@ async function createBazilionSession(opts) {
38010
38222
  });
38011
38223
  }
38012
38224
  const cwd = agent.group.path;
38013
- if (!existsSync12(cwd)) mkdirSync6(cwd, { recursive: true });
38014
- const sessionDir = join14(paths.agentDir(agent.agent.id), "sessions");
38225
+ if (!existsSync13(cwd)) mkdirSync6(cwd, { recursive: true });
38226
+ const sessionDir = join16(paths.agentDir(agent.agent.id), "sessions");
38015
38227
  mkdirSync6(sessionDir, { recursive: true });
38016
38228
  const existing = findMostRecent(sessionDir);
38017
38229
  const sessionManager = existing ? SessionManager.open(existing, sessionDir, cwd) : SessionManager.create(cwd, sessionDir);
@@ -38041,7 +38253,7 @@ async function createBazilionSession(opts) {
38041
38253
  const allowedTools = [...BUILTIN_TOOL_NAMES, ...customTools.map((t) => t.name)];
38042
38254
  const { session } = await createAgentSession({
38043
38255
  cwd,
38044
- agentDir: join14(paths.home, "pi"),
38256
+ agentDir: join16(paths.home, "pi"),
38045
38257
  model,
38046
38258
  thinkingLevel: toPiThinkingLevel(agent.reasoningLevel),
38047
38259
  tools: allowedTools,
@@ -38167,10 +38379,10 @@ function createBazilionResourceLoader(appendSystemPrompt) {
38167
38379
  };
38168
38380
  }
38169
38381
  function loadInitialMessages(agent, paths) {
38170
- const sessionDir = join14(paths.agentDir(agent.agent.id), "sessions");
38171
- if (!existsSync12(sessionDir)) return [];
38382
+ const sessionDir = join16(paths.agentDir(agent.agent.id), "sessions");
38383
+ if (!existsSync13(sessionDir)) return [];
38172
38384
  const cwd = agent.group.path;
38173
- if (!existsSync12(cwd)) return [];
38385
+ if (!existsSync13(cwd)) return [];
38174
38386
  const recent = findMostRecent(sessionDir);
38175
38387
  if (!recent) return [];
38176
38388
  try {
@@ -38186,8 +38398,8 @@ function loadInitialMessages(agent, paths) {
38186
38398
  }
38187
38399
  }
38188
38400
  function loadSessionHead(agent, paths) {
38189
- const sessionDir = join14(paths.agentDir(agent.agent.id), "sessions");
38190
- if (!existsSync12(sessionDir)) return { file: null, size: 0 };
38401
+ const sessionDir = join16(paths.agentDir(agent.agent.id), "sessions");
38402
+ if (!existsSync13(sessionDir)) return { file: null, size: 0 };
38191
38403
  const recent = findMostRecent(sessionDir);
38192
38404
  if (!recent) return { file: null, size: 0 };
38193
38405
  try {
@@ -38198,11 +38410,11 @@ function loadSessionHead(agent, paths) {
38198
38410
  }
38199
38411
  }
38200
38412
  function findMostRecent(sessionDir) {
38201
- if (!existsSync12(sessionDir)) return null;
38413
+ if (!existsSync13(sessionDir)) return null;
38202
38414
  let newest = null;
38203
38415
  for (const entry of readdirSync8(sessionDir)) {
38204
38416
  if (!entry.endsWith(".jsonl")) continue;
38205
- const path = join14(sessionDir, entry);
38417
+ const path = join16(sessionDir, entry);
38206
38418
  try {
38207
38419
  const s = statSync7(path);
38208
38420
  if (!newest || s.mtimeMs > newest.mtimeMs) newest = { path, mtimeMs: s.mtimeMs };
@@ -38302,13 +38514,13 @@ function listCatalogModelsSync(providerName) {
38302
38514
 
38303
38515
  // ../daemon/src/runtime/worker/spawn.ts
38304
38516
  import { spawn } from "child_process";
38305
- import { existsSync as existsSync13 } from "fs";
38517
+ import { existsSync as existsSync14 } from "fs";
38306
38518
  import { createRequire } from "module";
38307
38519
  import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
38308
38520
  var DEFAULT_KILL_GRACE_MS = 3e3;
38309
38521
  var sourceEntryPath = fileURLToPath2(new URL("./entry.ts", import.meta.url));
38310
38522
  var bundledEntryPath = fileURLToPath2(new URL("./worker.js", import.meta.url));
38311
- var entryPath = existsSync13(sourceEntryPath) ? sourceEntryPath : bundledEntryPath;
38523
+ var entryPath = existsSync14(sourceEntryPath) ? sourceEntryPath : bundledEntryPath;
38312
38524
  var entryIsTs = entryPath.endsWith(".ts");
38313
38525
  function workerSpawnArgs() {
38314
38526
  if (!entryIsTs) return [entryPath];
@@ -38520,8 +38732,8 @@ async function resolveAgentApiKey(db, authToken, agent, opts = {}) {
38520
38732
 
38521
38733
  // ../daemon/src/lib/attachments.ts
38522
38734
  import { randomUUID as randomUUID6 } from "crypto";
38523
- import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
38524
- import { join as join15 } from "path";
38735
+ import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
38736
+ import { join as join17 } from "path";
38525
38737
  var MAX_FILE_BYTES = 25 * 1024 * 1024;
38526
38738
  function safeName(name) {
38527
38739
  const base = name.split(/[\\/]/).pop() ?? "file";
@@ -38534,7 +38746,7 @@ function fmtBytes(n) {
38534
38746
  }
38535
38747
  function saveInputFiles(agentDir, files) {
38536
38748
  if (!files || files.length === 0) return "";
38537
- const dir = join15(agentDir, "uploads");
38749
+ const dir = join17(agentDir, "uploads");
38538
38750
  mkdirSync7(dir, { recursive: true });
38539
38751
  const lines = [];
38540
38752
  for (const f of files) {
@@ -38544,8 +38756,8 @@ function saveInputFiles(agentDir, files) {
38544
38756
  lines.push(`[attachment "${label}" skipped: too large (${fmtBytes(buf.byteLength)} > 25 MB)]`);
38545
38757
  continue;
38546
38758
  }
38547
- const path = join15(dir, `${randomUUID6().slice(0, 8)}-${safeName(label)}`);
38548
- writeFileSync7(path, buf);
38759
+ const path = join17(dir, `${randomUUID6().slice(0, 8)}-${safeName(label)}`);
38760
+ writeFileSync8(path, buf);
38549
38761
  lines.push(
38550
38762
  `[file saved to ${path} (${f.mimeType || "unknown"}, ${fmtBytes(buf.byteLength)}) \u2014 open it with your tools]`
38551
38763
  );
@@ -39949,9 +40161,13 @@ function bootstrap(paths) {
39949
40161
  }
39950
40162
  const db = openDb(paths.db);
39951
40163
  runMigrations(db);
39952
- if (!existsSync14(paths.authFile)) {
40164
+ const refreshed = refreshDefaultProfileTemplates(paths);
40165
+ if (refreshed.length) {
40166
+ console.log(`bazilion: refreshed default profile templates \u2014 [${refreshed.join(", ")}]`);
40167
+ }
40168
+ if (!existsSync15(paths.authFile)) {
39953
40169
  const created = webTokens_exports.create(db, "bootstrap");
39954
- writeFileSync8(paths.authFile, `${JSON.stringify({ token: created.token }, null, 2)}
40170
+ writeFileSync9(paths.authFile, `${JSON.stringify({ token: created.token }, null, 2)}
39955
40171
  `, {
39956
40172
  mode: 384
39957
40173
  });
@@ -40026,8 +40242,8 @@ async function authMiddleware(c, next) {
40026
40242
  }
40027
40243
 
40028
40244
  // ../daemon/src/routes/agents.ts
40029
- import { existsSync as existsSync15, readdirSync as readdirSync9, readFileSync as readFileSync11, rmSync as rmSync9 } from "fs";
40030
- import { join as join16 } from "path";
40245
+ import { existsSync as existsSync16, readdirSync as readdirSync9, readFileSync as readFileSync12, rmSync as rmSync9 } from "fs";
40246
+ import { join as join18 } from "path";
40031
40247
 
40032
40248
  // ../../packages/api-types/src/entities.ts
40033
40249
  var REASONING_LEVELS = [
@@ -41678,17 +41894,31 @@ async function pollLoop(handle12, db, initialOffset) {
41678
41894
  let offset = initialOffset;
41679
41895
  while (!handle12.stopRequested) {
41680
41896
  let updates = [];
41897
+ const ac = new AbortController();
41898
+ const abortTimer = setTimeout(() => ac.abort(), (POLL_TIMEOUT_S + 5) * 1e3);
41681
41899
  try {
41682
- updates = await handle12.bot.api.getUpdates({
41683
- offset,
41684
- timeout: POLL_TIMEOUT_S
41685
- });
41900
+ updates = await handle12.bot.api.getUpdates(
41901
+ {
41902
+ offset,
41903
+ timeout: POLL_TIMEOUT_S
41904
+ },
41905
+ // grammY's Node shim types the signal param as the `abort-controller`
41906
+ // package's AbortSignal, not the global one — runtime-compatible, so
41907
+ // cast through the method's own parameter type.
41908
+ ac.signal
41909
+ );
41686
41910
  handle12.state.lastSuccessfulPollAt = Date.now();
41687
41911
  handle12.state.error = null;
41688
41912
  } catch (e) {
41689
41913
  if (handle12.stopRequested) break;
41690
41914
  const msg = errMsg2(e);
41691
41915
  handle12.state.error = msg;
41916
+ if (ac.signal.aborted) {
41917
+ console.warn(
41918
+ `telegram: getUpdates exceeded ${POLL_TIMEOUT_S + 5}s (connection likely dropped) \u2014 retrying`
41919
+ );
41920
+ continue;
41921
+ }
41692
41922
  if (e instanceof import_grammy2.GrammyError && e.error_code === 409) {
41693
41923
  console.error("telegram: getUpdates 409 conflict (webhook or duplicate poller):", msg);
41694
41924
  } else {
@@ -41696,6 +41926,8 @@ async function pollLoop(handle12, db, initialOffset) {
41696
41926
  }
41697
41927
  await sleep2(GETUPDATES_RETRY_MS);
41698
41928
  continue;
41929
+ } finally {
41930
+ clearTimeout(abortTimer);
41699
41931
  }
41700
41932
  for (const u of updates) {
41701
41933
  try {
@@ -41865,7 +42097,11 @@ function sanitizeAttachments(raw) {
41865
42097
  agentsRouter.get("/", (c) => {
41866
42098
  const includeArchived = c.req.query("includeArchived") === "true";
41867
42099
  const { db, paths, authToken } = getCtx();
41868
- return c.json(agents_exports.list(db, { includeArchived }));
42100
+ const agents = agents_exports.list(db, { includeArchived }).map((agent) => ({
42101
+ ...agent,
42102
+ identity: loadIdentityFromFile(join18(agent.dir, "IDENTITY.md"))
42103
+ }));
42104
+ return c.json(agents);
41869
42105
  });
41870
42106
  agentsRouter.post("/", async (c) => {
41871
42107
  const raw = await c.req.json().catch(() => null);
@@ -42257,7 +42493,7 @@ agentsRouter.post("/:id/chat/compact", async (c) => {
42257
42493
  const id = resolveAgentIdParam(db, c.req.param("id"));
42258
42494
  if (!agents_exports.get(db, id)) return c.json({ error: "agent not found" }, 404);
42259
42495
  const resolved = resolveAgent(db, paths, id);
42260
- const memory = qmdBackend(join16(resolved.group.path, "memory"));
42496
+ const memory = qmdBackend(join18(resolved.group.path, "memory"));
42261
42497
  await memory.init();
42262
42498
  const env = mergeSecretsIntoEnv(db, authToken);
42263
42499
  const apiKeyResolution = await resolveAgentApiKey(db, authToken, resolved, {
@@ -42308,9 +42544,9 @@ agentsRouter.get("/:id/chat/context", async (c) => {
42308
42544
  const resolved = resolveAgent(db, paths, id);
42309
42545
  const files = [];
42310
42546
  for (const file of CONTEXT_FILE_ORDER2) {
42311
- const path = join16(resolved.agent.dir, file);
42312
- if (!existsSync15(path)) continue;
42313
- const content = readFileSync11(path, "utf8").trimEnd();
42547
+ const path = join18(resolved.agent.dir, file);
42548
+ if (!existsSync16(path)) continue;
42549
+ const content = readFileSync12(path, "utf8").trimEnd();
42314
42550
  if (!content) continue;
42315
42551
  const chars = content.length + file.length + 6;
42316
42552
  files.push({ name: file, chars, tokens: estimateTokens(chars) });
@@ -42334,7 +42570,7 @@ Read-only context about the human you're working with in this group. You cannot
42334
42570
 
42335
42571
  ${resolved.group.userMd.trim()}`.length : 0;
42336
42572
  const memoryHintChars = "# Memory\n\nYou have a persistent memory backend. Use `memory_write` to remember things across sessions, and `memory_search` / `memory_read` / `memory_list` to recall them. Always check memory at the start of a session if the user might have told you something important before.".length;
42337
- const memory = qmdBackend(join16(resolved.group.path, "memory"));
42573
+ const memory = qmdBackend(join18(resolved.group.path, "memory"));
42338
42574
  await memory.init();
42339
42575
  const env = mergeSecretsIntoEnv(db, authToken);
42340
42576
  const apiKeyResolution = await resolveAgentApiKey(db, authToken, resolved, {
@@ -42375,7 +42611,7 @@ ${resolved.group.userMd.trim()}`.length : 0;
42375
42611
  let blockChars = name.length + 2;
42376
42612
  if (match) {
42377
42613
  try {
42378
- blockChars = readFileSync11(match.skillFile, "utf8").length;
42614
+ blockChars = readFileSync12(match.skillFile, "utf8").length;
42379
42615
  } catch {
42380
42616
  }
42381
42617
  }
@@ -42444,13 +42680,13 @@ agentsRouter.post("/:id/chat/reset", (c) => {
42444
42680
  const id = resolveAgentIdParam(db, c.req.param("id"));
42445
42681
  const agent = agents_exports.get(db, id);
42446
42682
  if (!agent) return c.json({ error: "agent not found" }, 404);
42447
- const sessionsDir = join16(paths.agentDir(agent.id), "sessions");
42683
+ const sessionsDir = join18(paths.agentDir(agent.id), "sessions");
42448
42684
  let deleted = 0;
42449
- if (existsSync15(sessionsDir)) {
42685
+ if (existsSync16(sessionsDir)) {
42450
42686
  for (const file of readdirSync9(sessionsDir)) {
42451
42687
  if (!file.endsWith(".jsonl")) continue;
42452
42688
  try {
42453
- rmSync9(join16(sessionsDir, file));
42689
+ rmSync9(join18(sessionsDir, file));
42454
42690
  deleted++;
42455
42691
  } catch {
42456
42692
  }
@@ -42473,7 +42709,7 @@ agentsRouter.post("/:id/chat/truncate", async (c) => {
42473
42709
  const id = resolveAgentIdParam(db, c.req.param("id"));
42474
42710
  if (!agents_exports.get(db, id)) return c.json({ error: "agent not found" }, 404);
42475
42711
  const resolved = resolveAgent(db, paths, id);
42476
- const memory = qmdBackend(join16(resolved.group.path, "memory"));
42712
+ const memory = qmdBackend(join18(resolved.group.path, "memory"));
42477
42713
  await memory.init();
42478
42714
  const env = mergeSecretsIntoEnv(db, authToken);
42479
42715
  const apiKeyResolution = await resolveAgentApiKey(db, authToken, resolved, {
@@ -42824,7 +43060,7 @@ function knownProviderRegistryNames() {
42824
43060
  }
42825
43061
 
42826
43062
  // ../daemon/src/routes/groups.ts
42827
- import { join as join17 } from "path";
43063
+ import { join as join19 } from "path";
42828
43064
  import { Hono as Hono4 } from "hono";
42829
43065
  var USER_MD_MAX_BYTES2 = 12e3;
42830
43066
  var groupsRouter = new Hono4();
@@ -42899,7 +43135,7 @@ async function openMemory(rawId) {
42899
43135
  const { db, paths } = getCtx();
42900
43136
  const group = groups_exports.get(db, rawId, paths);
42901
43137
  if (!group) throw new Error(`group not found: ${rawId}`);
42902
- const mem = qmdBackend(join17(group.path, "memory"));
43138
+ const mem = qmdBackend(join19(group.path, "memory"));
42903
43139
  await mem.init();
42904
43140
  return { mem, group };
42905
43141
  }
@@ -43105,20 +43341,20 @@ messagesRouter.patch("/:id", async (c) => {
43105
43341
 
43106
43342
  // ../daemon/src/routes/misc.ts
43107
43343
  import { spawn as spawn4 } from "child_process";
43108
- import { existsSync as existsSync16 } from "fs";
43344
+ import { existsSync as existsSync17 } from "fs";
43109
43345
  import { homedir as homedir2 } from "os";
43110
- import { join as join18 } from "path";
43346
+ import { join as join20 } from "path";
43111
43347
  import { Hono as Hono7 } from "hono";
43112
43348
  var miscRouter = new Hono7();
43113
43349
  miscRouter.get("/health", (c) => {
43114
43350
  const paths = resolvePaths();
43115
43351
  const pathChecks = {
43116
- home: existsSync16(paths.home),
43117
- db: existsSync16(paths.db),
43118
- auth: existsSync16(paths.authFile),
43119
- profiles: existsSync16(paths.profilesDir),
43120
- agents: existsSync16(paths.agentsDir),
43121
- skills: existsSync16(paths.skillsDir)
43352
+ home: existsSync17(paths.home),
43353
+ db: existsSync17(paths.db),
43354
+ auth: existsSync17(paths.authFile),
43355
+ profiles: existsSync17(paths.profilesDir),
43356
+ agents: existsSync17(paths.agentsDir),
43357
+ skills: existsSync17(paths.skillsDir)
43122
43358
  };
43123
43359
  let database = null;
43124
43360
  const triggersSection = { active: 0, disabled: 0 };
@@ -43166,7 +43402,7 @@ miscRouter.get("/health", (c) => {
43166
43402
  }
43167
43403
  const providerConfig = loadProviderConfigFromEnv(effectiveEnv, oauth);
43168
43404
  const braveKey = effectiveEnv.BRAVE_API_KEY;
43169
- const openclawSkillsDir = join18(homedir2(), ".openclaw", "skills");
43405
+ const openclawSkillsDir = join20(homedir2(), ".openclaw", "skills");
43170
43406
  const CLOUD_KEYS = [
43171
43407
  ["anthropic", "anthropic"],
43172
43408
  ["openai", "openai"],
@@ -43204,7 +43440,7 @@ miscRouter.get("/health", (c) => {
43204
43440
  },
43205
43441
  openclaw: {
43206
43442
  path: openclawSkillsDir,
43207
- exists: existsSync16(openclawSkillsDir)
43443
+ exists: existsSync17(openclawSkillsDir)
43208
43444
  },
43209
43445
  triggers: triggersSection,
43210
43446
  tokens: tokensSection,
@@ -43217,7 +43453,7 @@ miscRouter.get("/health", (c) => {
43217
43453
  });
43218
43454
  miscRouter.get("/backup", (c) => {
43219
43455
  const paths = resolvePaths();
43220
- if (!existsSync16(paths.home)) {
43456
+ if (!existsSync17(paths.home)) {
43221
43457
  return c.json({ error: `bazilion home not found at ${paths.home}` }, 404);
43222
43458
  }
43223
43459
  const proc = spawn4("tar", ["-czf", "-", "-C", paths.home, "."], {
@@ -43431,8 +43667,8 @@ profileGroupsRouter.post("/:id/spawn", async (c) => {
43431
43667
  });
43432
43668
 
43433
43669
  // ../daemon/src/routes/profiles.ts
43434
- import { existsSync as existsSync17, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
43435
- import { join as join19 } from "path";
43670
+ import { existsSync as existsSync18, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "fs";
43671
+ import { join as join21 } from "path";
43436
43672
  import { Hono as Hono9 } from "hono";
43437
43673
  var profilesRouter = new Hono9();
43438
43674
  profilesRouter.get("/", (c) => {
@@ -43449,7 +43685,11 @@ profilesRouter.get("/_/templates", (c) => {
43449
43685
  return c.json({
43450
43686
  soul: DEFAULT_SOUL,
43451
43687
  identity: DEFAULT_IDENTITY,
43452
- bootstrap: DEFAULT_BOOTSTRAP
43688
+ bootstrap: DEFAULT_BOOTSTRAP,
43689
+ agents: DEFAULT_AGENTS,
43690
+ tools: DEFAULT_TOOLS,
43691
+ heartbeat: DEFAULT_HEARTBEAT,
43692
+ userMd: DEFAULT_USER_MD
43453
43693
  });
43454
43694
  });
43455
43695
  profilesRouter.post("/", async (c) => {
@@ -43467,9 +43707,12 @@ profilesRouter.post("/", async (c) => {
43467
43707
  if (raw.skipBootstrap === true || raw.bootstrap === null) templates.bootstrap = null;
43468
43708
  else if (typeof raw.bootstrap === "string" && raw.bootstrap.length > 0)
43469
43709
  templates.bootstrap = raw.bootstrap;
43470
- if (typeof raw.agents === "string" && raw.agents.length > 0) templates.agents = raw.agents;
43471
- if (typeof raw.tools === "string" && raw.tools.length > 0) templates.tools = raw.tools;
43472
- if (typeof raw.heartbeat === "string" && raw.heartbeat.length > 0)
43710
+ if (raw.agents === null) templates.agents = null;
43711
+ else if (typeof raw.agents === "string" && raw.agents.length > 0) templates.agents = raw.agents;
43712
+ if (raw.tools === null) templates.tools = null;
43713
+ else if (typeof raw.tools === "string" && raw.tools.length > 0) templates.tools = raw.tools;
43714
+ if (raw.heartbeat === null) templates.heartbeat = null;
43715
+ else if (typeof raw.heartbeat === "string" && raw.heartbeat.length > 0)
43473
43716
  templates.heartbeat = raw.heartbeat;
43474
43717
  const { db, paths } = getCtx();
43475
43718
  try {
@@ -43533,8 +43776,8 @@ profilesRouter.get("/:id/files/:file", (c) => {
43533
43776
  return c.json({ error: `profile not found: ${c.req.param("id")}` }, 404);
43534
43777
  const path = resolveFilePath(paths.profilesDir, c.req.param("id"), c.req.param("file"));
43535
43778
  if (!path) return c.json({ error: `unsupported file: ${c.req.param("file")}` }, 400);
43536
- if (!existsSync17(path)) return c.json({ error: `file not present: ${c.req.param("file")}` }, 404);
43537
- const body = { content: readFileSync12(path, "utf8") };
43779
+ if (!existsSync18(path)) return c.json({ error: `file not present: ${c.req.param("file")}` }, 404);
43780
+ const body = { content: readFileSync13(path, "utf8") };
43538
43781
  return c.json(body);
43539
43782
  });
43540
43783
  profilesRouter.put("/:id/files/:file", async (c) => {
@@ -43546,12 +43789,12 @@ profilesRouter.put("/:id/files/:file", async (c) => {
43546
43789
  return c.json({ error: `profile not found: ${c.req.param("id")}` }, 404);
43547
43790
  const path = resolveFilePath(paths.profilesDir, c.req.param("id"), c.req.param("file"));
43548
43791
  if (!path) return c.json({ error: `unsupported file: ${c.req.param("file")}` }, 400);
43549
- writeFileSync9(path, body.content);
43792
+ writeFileSync10(path, body.content);
43550
43793
  return c.body(null, 204);
43551
43794
  });
43552
43795
  function resolveFilePath(profilesDir, id, file) {
43553
43796
  if (!PROFILE_FILES.includes(file)) return null;
43554
- return join19(profilesDir, id, file);
43797
+ return join21(profilesDir, id, file);
43555
43798
  }
43556
43799
  function csvToArray(v) {
43557
43800
  if (Array.isArray(v)) return v.filter((s) => typeof s === "string");
@@ -43565,9 +43808,9 @@ function toSkillsMode(v) {
43565
43808
  }
43566
43809
 
43567
43810
  // ../daemon/src/routes/skills.ts
43568
- import { existsSync as existsSync18, mkdtempSync as mkdtempSync2, rmSync as rmSync10, writeFileSync as writeFileSync10 } from "fs";
43811
+ import { existsSync as existsSync19, mkdtempSync as mkdtempSync2, rmSync as rmSync10, writeFileSync as writeFileSync11 } from "fs";
43569
43812
  import { homedir as homedir3, tmpdir as tmpdir2 } from "os";
43570
- import { join as join20 } from "path";
43813
+ import { join as join22 } from "path";
43571
43814
  import { Hono as Hono10 } from "hono";
43572
43815
  var MAX_ZIP_BYTES = 50 * 1024 * 1024;
43573
43816
  var skillsRouter = new Hono10();
@@ -43596,7 +43839,7 @@ skillsRouter.delete("/:name", (c) => {
43596
43839
  const { db, paths } = getCtx();
43597
43840
  const name = c.req.param("name");
43598
43841
  const dir = paths.skillDir(name);
43599
- if (!existsSync18(dir)) return c.json({ error: `skill not found: ${name}` }, 404);
43842
+ if (!existsSync19(dir)) return c.json({ error: `skill not found: ${name}` }, 404);
43600
43843
  rmSync10(dir, { recursive: true, force: true });
43601
43844
  skillMeta_exports.remove(db, name);
43602
43845
  return c.body(null, 204);
@@ -43638,10 +43881,10 @@ async function parseImportInput(request) {
43638
43881
  if (!filename.toLowerCase().endsWith(".zip")) {
43639
43882
  throw new Error("uploaded file must be a .zip archive");
43640
43883
  }
43641
- const tmpDir = mkdtempSync2(join20(tmpdir2(), "bazilion-skill-upload-"));
43642
- const zipPath = join20(tmpDir, filename.replace(/[^\w.-]+/g, "_"));
43884
+ const tmpDir = mkdtempSync2(join22(tmpdir2(), "bazilion-skill-upload-"));
43885
+ const zipPath = join22(tmpDir, filename.replace(/[^\w.-]+/g, "_"));
43643
43886
  const buf = Buffer.from(await file.arrayBuffer());
43644
- writeFileSync10(zipPath, buf);
43887
+ writeFileSync11(zipPath, buf);
43645
43888
  const forceField = form.get("force");
43646
43889
  return {
43647
43890
  source: zipPath,
@@ -43654,7 +43897,7 @@ async function parseImportInput(request) {
43654
43897
  if (!body) throw new Error("invalid JSON body");
43655
43898
  const from = body.source ?? body.from;
43656
43899
  if (typeof from !== "string" || !from) throw new Error("source is required");
43657
- const source = from === "openclaw" ? join20(homedir3(), ".openclaw", "skills") : from;
43900
+ const source = from === "openclaw" ? join22(homedir3(), ".openclaw", "skills") : from;
43658
43901
  return {
43659
43902
  source,
43660
43903
  force: Boolean(body.force),