@pellux/goodvibes-agent 0.1.114 → 0.1.116

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.
@@ -816523,7 +816523,7 @@ var createStyledCell = (char, overrides = {}) => ({
816523
816523
  // src/version.ts
816524
816524
  import { readFileSync } from "fs";
816525
816525
  import { join } from "path";
816526
- var _version = "0.1.114";
816526
+ var _version = "0.1.116";
816527
816527
  var _sdkVersion = "0.33.35";
816528
816528
  try {
816529
816529
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, "..", "package.json"), "utf-8"));
@@ -841974,7 +841974,7 @@ async function initializeBootstrapCore(stdout, options, getControlPlaneRecentEve
841974
841974
  }
841975
841975
 
841976
841976
  // src/runtime/bootstrap-shell.ts
841977
- import { join as join91 } from "path";
841977
+ import { join as join92 } from "path";
841978
841978
 
841979
841979
  // src/input/command-registry.ts
841980
841980
  class CommandRegistry {
@@ -851684,9 +851684,195 @@ import { dirname as dirname58 } from "path";
851684
851684
 
851685
851685
  // src/agent/runtime-profile.ts
851686
851686
  import { existsSync as existsSync71, mkdirSync as mkdirSync59, readFileSync as readFileSync78, readdirSync as readdirSync20, rmSync as rmSync9, statSync as statSync19, writeFileSync as writeFileSync51 } from "fs";
851687
- import { dirname as dirname57, join as join86 } from "path";
851688
- var PROFILE_CREATED_FILE = "profile.json";
851689
- var PROFILE_ID_PATTERN = /^[a-z0-9](?:[a-z0-9._-]{0,62}[a-z0-9])?$/;
851687
+ import { dirname as dirname57, join as join88 } from "path";
851688
+
851689
+ // src/agent/persona-discovery.ts
851690
+ import { promises as fsPromises5 } from "fs";
851691
+ import { join as join86 } from "path";
851692
+ var DIRECTORY_MARKERS = ["PERSONA.md", "persona.md", "AGENT.md", "agent.md"];
851693
+ function parseFrontmatter2(content) {
851694
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
851695
+ if (!match)
851696
+ return {};
851697
+ const result2 = {};
851698
+ for (const line of match[1].split(`
851699
+ `)) {
851700
+ const [key, ...rest] = line.split(":");
851701
+ if (key && rest.length > 0) {
851702
+ result2[key.trim()] = rest.join(":").trim();
851703
+ }
851704
+ }
851705
+ return result2;
851706
+ }
851707
+ function getPersonaDirectories(cwd, homeDir) {
851708
+ return [
851709
+ { root: join86(cwd, ".goodvibes", "personas"), origin: "project-local" },
851710
+ { root: join86(cwd, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "personas"), origin: "project-local" },
851711
+ { root: join86(cwd, ".goodvibes", "agents"), origin: "project-local" },
851712
+ { root: join86(homeDir, ".goodvibes", "personas"), origin: "global" },
851713
+ { root: join86(homeDir, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "personas"), origin: "global" },
851714
+ { root: join86(homeDir, ".goodvibes", "agents"), origin: "global" }
851715
+ ];
851716
+ }
851717
+ async function readPersonaFile(path7, origin) {
851718
+ let content = "";
851719
+ try {
851720
+ content = await fsPromises5.readFile(path7, "utf-8");
851721
+ } catch {
851722
+ return null;
851723
+ }
851724
+ const frontmatter = parseFrontmatter2(content);
851725
+ const markdownBody = content.replace(/^---\n[\s\S]*?\n---\n?/, "").trim();
851726
+ const body2 = (frontmatter.system_prompt ?? markdownBody).trim();
851727
+ if (!body2)
851728
+ return null;
851729
+ const name51 = frontmatter.name ?? path7.split(/[\\/]/).pop()?.replace(/\.md$/i, "") ?? "persona";
851730
+ const description = frontmatter.description ?? frontmatter.summary ?? frontmatter.title ?? "";
851731
+ return {
851732
+ name: name51,
851733
+ description,
851734
+ path: path7,
851735
+ origin,
851736
+ body: body2,
851737
+ frontmatter
851738
+ };
851739
+ }
851740
+ async function scanPersonaDirectory(root, origin) {
851741
+ let entries = [];
851742
+ try {
851743
+ entries = await fsPromises5.readdir(root);
851744
+ } catch {
851745
+ return [];
851746
+ }
851747
+ const records = [];
851748
+ for (const entry of entries.sort((a4, b3) => a4.localeCompare(b3))) {
851749
+ if (entry.endsWith(".md")) {
851750
+ const record2 = await readPersonaFile(join86(root, entry), origin);
851751
+ if (record2)
851752
+ records.push(record2);
851753
+ continue;
851754
+ }
851755
+ for (const marker of DIRECTORY_MARKERS) {
851756
+ const record2 = await readPersonaFile(join86(root, entry, marker), origin);
851757
+ if (record2) {
851758
+ records.push(record2);
851759
+ break;
851760
+ }
851761
+ }
851762
+ }
851763
+ return records;
851764
+ }
851765
+ async function discoverPersonas(shellPaths) {
851766
+ const seen = new Set;
851767
+ const records = [];
851768
+ for (const { root, origin } of getPersonaDirectories(shellPaths.workingDirectory, shellPaths.homeDirectory)) {
851769
+ for (const record2 of await scanPersonaDirectory(root, origin)) {
851770
+ const key = record2.name.toLowerCase();
851771
+ if (seen.has(key))
851772
+ continue;
851773
+ seen.add(key);
851774
+ records.push(record2);
851775
+ }
851776
+ }
851777
+ return records.sort((a4, b3) => {
851778
+ const originRank = a4.origin === b3.origin ? 0 : a4.origin === "project-local" ? -1 : 1;
851779
+ return originRank || a4.name.localeCompare(b3.name);
851780
+ });
851781
+ }
851782
+
851783
+ // src/agent/routine-discovery.ts
851784
+ import { promises as fsPromises6 } from "fs";
851785
+ import { join as join87 } from "path";
851786
+ var DIRECTORY_MARKERS2 = ["ROUTINE.md", "routine.md"];
851787
+ function parseFrontmatter3(content) {
851788
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
851789
+ if (!match)
851790
+ return {};
851791
+ const result2 = {};
851792
+ for (const line of match[1].split(`
851793
+ `)) {
851794
+ const [key, ...rest] = line.split(":");
851795
+ if (key && rest.length > 0) {
851796
+ result2[key.trim()] = rest.join(":").trim();
851797
+ }
851798
+ }
851799
+ return result2;
851800
+ }
851801
+ function getRoutineDirectories(cwd, homeDir) {
851802
+ return [
851803
+ { root: join87(cwd, ".goodvibes", "routines"), origin: "project-local" },
851804
+ { root: join87(cwd, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "routines"), origin: "project-local" },
851805
+ { root: join87(homeDir, ".goodvibes", "routines"), origin: "global" },
851806
+ { root: join87(homeDir, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "routines"), origin: "global" }
851807
+ ];
851808
+ }
851809
+ async function readRoutineFile(path7, origin) {
851810
+ let content = "";
851811
+ try {
851812
+ content = await fsPromises6.readFile(path7, "utf-8");
851813
+ } catch {
851814
+ return null;
851815
+ }
851816
+ const frontmatter = parseFrontmatter3(content);
851817
+ const markdownBody = content.replace(/^---\n[\s\S]*?\n---\n?/, "").trim();
851818
+ const steps = (frontmatter.steps ?? markdownBody).trim();
851819
+ if (!steps)
851820
+ return null;
851821
+ const name51 = frontmatter.name ?? path7.split(/[\\/]/).pop()?.replace(/\.md$/i, "") ?? "routine";
851822
+ const description = frontmatter.description ?? frontmatter.summary ?? frontmatter.title ?? "";
851823
+ return {
851824
+ name: name51,
851825
+ description,
851826
+ path: path7,
851827
+ origin,
851828
+ steps,
851829
+ frontmatter
851830
+ };
851831
+ }
851832
+ async function scanRoutineDirectory(root, origin) {
851833
+ let entries = [];
851834
+ try {
851835
+ entries = await fsPromises6.readdir(root);
851836
+ } catch {
851837
+ return [];
851838
+ }
851839
+ const records = [];
851840
+ for (const entry of entries.sort((a4, b3) => a4.localeCompare(b3))) {
851841
+ if (entry.endsWith(".md")) {
851842
+ const record2 = await readRoutineFile(join87(root, entry), origin);
851843
+ if (record2)
851844
+ records.push(record2);
851845
+ continue;
851846
+ }
851847
+ for (const marker of DIRECTORY_MARKERS2) {
851848
+ const record2 = await readRoutineFile(join87(root, entry, marker), origin);
851849
+ if (record2) {
851850
+ records.push(record2);
851851
+ break;
851852
+ }
851853
+ }
851854
+ }
851855
+ return records;
851856
+ }
851857
+ async function discoverRoutines(shellPaths) {
851858
+ const seen = new Set;
851859
+ const records = [];
851860
+ for (const { root, origin } of getRoutineDirectories(shellPaths.workingDirectory, shellPaths.homeDirectory)) {
851861
+ for (const record2 of await scanRoutineDirectory(root, origin)) {
851862
+ const key = record2.name.toLowerCase();
851863
+ if (seen.has(key))
851864
+ continue;
851865
+ seen.add(key);
851866
+ records.push(record2);
851867
+ }
851868
+ }
851869
+ return records.sort((a4, b3) => {
851870
+ const originRank = a4.origin === b3.origin ? 0 : a4.origin === "project-local" ? -1 : 1;
851871
+ return originRank || a4.name.localeCompare(b3.name);
851872
+ });
851873
+ }
851874
+
851875
+ // src/agent/runtime-profile-starters.ts
851690
851876
  var STARTER_TEMPLATES = [
851691
851877
  {
851692
851878
  id: "household",
@@ -852007,6 +852193,10 @@ var STARTER_TEMPLATES = [
852007
852193
  ]
852008
852194
  }
852009
852195
  ];
852196
+
852197
+ // src/agent/runtime-profile.ts
852198
+ var PROFILE_CREATED_FILE = "profile.json";
852199
+ var PROFILE_ID_PATTERN = /^[a-z0-9](?:[a-z0-9._-]{0,62}[a-z0-9])?$/;
852010
852200
  function normalizeAgentRuntimeProfileId(value) {
852011
852201
  return value.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "").replace(/[-_]{2,}/g, "-");
852012
852202
  }
@@ -852022,20 +852212,20 @@ function assertValidAgentRuntimeProfileId(value) {
852022
852212
  return normalized;
852023
852213
  }
852024
852214
  function getAgentRuntimeProfilesRoot(baseHomeDirectory) {
852025
- return join86(baseHomeDirectory, ".goodvibes", "agent", "profile-homes");
852215
+ return join88(baseHomeDirectory, ".goodvibes", "agent", "profile-homes");
852026
852216
  }
852027
852217
  function getAgentRuntimeProfileTemplatesRoot(baseHomeDirectory) {
852028
- return join86(baseHomeDirectory, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "profile-starters");
852218
+ return join88(baseHomeDirectory, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "profile-starters");
852029
852219
  }
852030
852220
  function resolveAgentRuntimeProfileHome(baseHomeDirectory, profileName) {
852031
852221
  const id = assertValidAgentRuntimeProfileId(profileName);
852032
852222
  return {
852033
852223
  id,
852034
- homeDirectory: join86(getAgentRuntimeProfilesRoot(baseHomeDirectory), id)
852224
+ homeDirectory: join88(getAgentRuntimeProfilesRoot(baseHomeDirectory), id)
852035
852225
  };
852036
852226
  }
852037
852227
  function readProfileCreatedAt(homeDirectory) {
852038
- const path7 = join86(homeDirectory, PROFILE_CREATED_FILE);
852228
+ const path7 = join88(homeDirectory, PROFILE_CREATED_FILE);
852039
852229
  if (!existsSync71(path7))
852040
852230
  return null;
852041
852231
  try {
@@ -852048,7 +852238,7 @@ function readProfileCreatedAt(homeDirectory) {
852048
852238
  return null;
852049
852239
  }
852050
852240
  function readProfileStarterTemplate(homeDirectory) {
852051
- const path7 = join86(homeDirectory, PROFILE_CREATED_FILE);
852241
+ const path7 = join88(homeDirectory, PROFILE_CREATED_FILE);
852052
852242
  if (!existsSync71(path7))
852053
852243
  return {};
852054
852244
  try {
@@ -852082,7 +852272,7 @@ function buildProfileInfo(baseHomeDirectory, id) {
852082
852272
  };
852083
852273
  }
852084
852274
  function profileStorePath(homeDirectory, folder, file2) {
852085
- return join86(homeDirectory, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, folder, file2);
852275
+ return join88(homeDirectory, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, folder, file2);
852086
852276
  }
852087
852277
  function isAgentRuntimeProfileTemplateId(value) {
852088
852278
  if (typeof value !== "string")
@@ -852111,6 +852301,65 @@ function parseStringArray(value) {
852111
852301
  return [];
852112
852302
  return value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean);
852113
852303
  }
852304
+ function splitFrontmatterList(value) {
852305
+ if (!value)
852306
+ return [];
852307
+ return value.split(",").map((entry) => entry.trim()).filter(Boolean);
852308
+ }
852309
+ function normalizedLookupValues(value, path7) {
852310
+ const slug = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
852311
+ const basename5 = path7?.split(/[\\/]/).pop()?.replace(/\.md$/i, "") ?? "";
852312
+ return [value, slug, path7 ?? "", basename5].map((entry) => entry.trim().toLowerCase()).filter(Boolean);
852313
+ }
852314
+ function selectDiscoveredRecord(records, selector2, label) {
852315
+ if (records.length === 0)
852316
+ throw new Error(`No discovered Agent ${label} files found.`);
852317
+ if (!selector2?.trim())
852318
+ return records[0];
852319
+ const lookup = selector2.trim().toLowerCase();
852320
+ const match = records.find((record2) => normalizedLookupValues(record2.name, record2.path).includes(lookup));
852321
+ if (!match)
852322
+ throw new Error(`Unknown discovered Agent ${label}: ${selector2}.`);
852323
+ return match;
852324
+ }
852325
+ function selectDiscoveredRecords(records, selectors4, label) {
852326
+ if (records.length === 0)
852327
+ throw new Error(`No discovered Agent ${label} files found.`);
852328
+ if (!selectors4 || selectors4.length === 0 || selectors4.includes("all"))
852329
+ return records;
852330
+ return selectors4.map((selector2) => selectDiscoveredRecord(records, selector2, label));
852331
+ }
852332
+ function discoveredSkillToTemplate(skill) {
852333
+ if (!skill.body.trim())
852334
+ throw new Error(`Discovered Agent skill ${skill.name} has no procedure body.`);
852335
+ return {
852336
+ name: skill.name,
852337
+ description: skill.description || `Imported skill from ${skill.origin} skill file.`,
852338
+ procedure: skill.body,
852339
+ triggers: splitFrontmatterList(skill.frontmatter.triggers),
852340
+ tags: splitFrontmatterList(skill.frontmatter.tags)
852341
+ };
852342
+ }
852343
+ function discoveredRoutineToTemplate(routine) {
852344
+ if (!routine.steps.trim())
852345
+ throw new Error(`Discovered Agent routine ${routine.name} has no steps.`);
852346
+ return {
852347
+ name: routine.name,
852348
+ description: routine.description || `Imported routine from ${routine.origin} markdown file.`,
852349
+ steps: routine.steps,
852350
+ triggers: splitFrontmatterList(routine.frontmatter.triggers),
852351
+ tags: splitFrontmatterList(routine.frontmatter.tags)
852352
+ };
852353
+ }
852354
+ function discoveredPersonaToTemplate(persona) {
852355
+ return {
852356
+ name: persona.name,
852357
+ description: persona.description || `Imported persona from ${persona.origin} markdown file.`,
852358
+ body: persona.body,
852359
+ tags: splitFrontmatterList(persona.frontmatter.tags),
852360
+ triggers: splitFrontmatterList(persona.frontmatter.triggers)
852361
+ };
852362
+ }
852114
852363
  function readTemplateTextBlock(value, field) {
852115
852364
  if (typeof value !== "string" || !value.trim())
852116
852365
  throw new Error(`Starter template ${field} is required.`);
@@ -852184,7 +852433,7 @@ function listLocalTemplates(baseHomeDirectory) {
852184
852433
  const root = getAgentRuntimeProfileTemplatesRoot(baseHomeDirectory);
852185
852434
  if (!existsSync71(root))
852186
852435
  return [];
852187
- return readdirSync20(root).filter((entry) => entry.endsWith(".json")).map((entry) => readLocalTemplate(join86(root, entry))).filter((entry) => entry !== null).sort((left, right) => left.id.localeCompare(right.id));
852436
+ return readdirSync20(root).filter((entry) => entry.endsWith(".json")).map((entry) => readLocalTemplate(join88(root, entry))).filter((entry) => entry !== null).sort((left, right) => left.id.localeCompare(right.id));
852188
852437
  }
852189
852438
  function resolveAgentRuntimeProfileTemplate(templateId, baseHomeDirectory) {
852190
852439
  const id = assertValidAgentRuntimeProfileId(templateId);
@@ -852235,11 +852484,63 @@ function importAgentRuntimeProfileTemplate(baseHomeDirectory, sourcePath) {
852235
852484
  const parsed = parseStarterTemplate(JSON.parse(readFileSync78(source, "utf-8")), "local");
852236
852485
  const root = getAgentRuntimeProfileTemplatesRoot(baseHomeDirectory);
852237
852486
  mkdirSync59(root, { recursive: true });
852238
- const target = join86(root, `${parsed.id}.json`);
852487
+ const target = join88(root, `${parsed.id}.json`);
852239
852488
  writeFileSync51(target, `${JSON.stringify(templateFilePayload({ ...parsed, source: "local", path: target }), null, 2)}
852240
852489
  `, "utf-8");
852241
852490
  return summarizeTemplate({ ...parsed, source: "local", path: target });
852242
852491
  }
852492
+ async function createAgentRuntimeProfileTemplateFromDiscovered(shellPaths, options) {
852493
+ const id = assertValidAgentRuntimeProfileId(options.id);
852494
+ const [personas, skills, routines] = await Promise.all([
852495
+ discoverPersonas(shellPaths),
852496
+ discoverSkills(shellPaths),
852497
+ discoverRoutines(shellPaths)
852498
+ ]);
852499
+ const selectedPersona = selectDiscoveredRecord(personas, options.persona, "persona");
852500
+ const selectedSkills = selectDiscoveredRecords(skills, options.skills, "skill");
852501
+ const selectedRoutines = selectDiscoveredRecords(routines, options.routines, "routine");
852502
+ const target = join88(getAgentRuntimeProfileTemplatesRoot(shellPaths.homeDirectory), `${id}.json`);
852503
+ if (existsSync71(target) && options.replace !== true) {
852504
+ throw new Error(`Agent starter template already exists: ${id}. Rerun with --replace to overwrite it.`);
852505
+ }
852506
+ const persona = discoveredPersonaToTemplate(selectedPersona);
852507
+ const template = {
852508
+ id,
852509
+ source: "local",
852510
+ path: target,
852511
+ name: options.name?.trim() || `${persona.name} Starter`,
852512
+ description: options.description?.trim() || "Agent starter template assembled from discovered local persona, skill, and routine files.",
852513
+ personaName: persona.name,
852514
+ skillNames: selectedSkills.map((skill) => skill.name),
852515
+ routineNames: selectedRoutines.map((routine) => routine.name),
852516
+ persona,
852517
+ skills: selectedSkills.map(discoveredSkillToTemplate),
852518
+ routines: selectedRoutines.map(discoveredRoutineToTemplate)
852519
+ };
852520
+ mkdirSync59(dirname57(target), { recursive: true });
852521
+ writeFileSync51(target, `${JSON.stringify(templateFilePayload(template), null, 2)}
852522
+ `, "utf-8");
852523
+ return summarizeTemplate(template);
852524
+ }
852525
+ async function createAgentRuntimeProfileFromDiscovered(shellPaths, options) {
852526
+ const profileId = assertValidAgentRuntimeProfileId(options.profileName);
852527
+ const resolution2 = resolveAgentRuntimeProfileHome(shellPaths.homeDirectory, profileId);
852528
+ if (existsSync71(resolution2.homeDirectory)) {
852529
+ throw new Error(`Agent profile already exists: ${resolution2.id}`);
852530
+ }
852531
+ const templateId = assertValidAgentRuntimeProfileId(options.templateId ?? profileId);
852532
+ const template = await createAgentRuntimeProfileTemplateFromDiscovered(shellPaths, {
852533
+ id: templateId,
852534
+ name: options.name,
852535
+ description: options.description,
852536
+ persona: options.persona,
852537
+ skills: options.skills,
852538
+ routines: options.routines,
852539
+ replace: options.replace
852540
+ });
852541
+ const profile5 = createAgentRuntimeProfile(shellPaths.homeDirectory, profileId, { templateId: template.id });
852542
+ return { profile: profile5, template };
852543
+ }
852243
852544
  function createMissingSkill(registry5, template) {
852244
852545
  const existing = registry5.get(template.name);
852245
852546
  if (existing)
@@ -852304,7 +852605,7 @@ function listAgentRuntimeProfiles(baseHomeDirectory) {
852304
852605
  return [];
852305
852606
  return readdirSync20(root).filter((entry) => PROFILE_ID_PATTERN.test(entry) && !entry.includes("..")).filter((entry) => {
852306
852607
  try {
852307
- return statSync19(join86(root, entry)).isDirectory();
852608
+ return statSync19(join88(root, entry)).isDirectory();
852308
852609
  } catch {
852309
852610
  return false;
852310
852611
  }
@@ -852318,7 +852619,7 @@ function createAgentRuntimeProfile(baseHomeDirectory, profileName, options = {})
852318
852619
  mkdirSync59(resolution2.homeDirectory, { recursive: true });
852319
852620
  const createdAt = new Date().toISOString();
852320
852621
  const appliedTemplate = options.templateId ? applyAgentRuntimeProfileTemplate(resolution2.homeDirectory, options.templateId, baseHomeDirectory) : undefined;
852321
- writeFileSync51(join86(resolution2.homeDirectory, PROFILE_CREATED_FILE), `${JSON.stringify({
852622
+ writeFileSync51(join88(resolution2.homeDirectory, PROFILE_CREATED_FILE), `${JSON.stringify({
852322
852623
  id: resolution2.id,
852323
852624
  createdAt,
852324
852625
  starterTemplate: appliedTemplate
@@ -852348,6 +852649,12 @@ function parseFlag(args2, name51) {
852348
852649
  const value = args2[index + 1];
852349
852650
  return value && !value.startsWith("--") ? value : undefined;
852350
852651
  }
852652
+ function parseCsvFlag(args2, name51) {
852653
+ const raw = parseFlag(args2, name51);
852654
+ if (!raw)
852655
+ return;
852656
+ return raw.split(",").map((entry) => entry.trim()).filter(Boolean);
852657
+ }
852351
852658
  function profileLine(profile5) {
852352
852659
  const created = profile5.createdAt ? ` created=${profile5.createdAt}` : "";
852353
852660
  const starter = profile5.starterTemplateId ? ` starter=${profile5.starterTemplateId}` : "";
@@ -852387,7 +852694,8 @@ function renderTemplates(homeDirectory) {
852387
852694
  " /agent-profile template export research ./agent-starter.json --yes",
852388
852695
  " edit the JSON file",
852389
852696
  " /agent-profile template import ./agent-starter.json --yes",
852390
- " /agent-profile create <name> --template <imported-id> --yes"
852697
+ " /agent-profile create <name> --template <imported-id> --yes",
852698
+ " /agent-profile create-from-discovered <name> --yes"
852391
852699
  ].join(`
852392
852700
  `);
852393
852701
  }
@@ -852434,8 +852742,8 @@ function registerAgentRuntimeProfileRuntimeCommands(registry5) {
852434
852742
  name: "agent-profile",
852435
852743
  aliases: ["runtime-profile", "agent-profiles"],
852436
852744
  description: "Manage isolated Agent profiles and starter templates",
852437
- usage: "[list|templates|guide|template show|template export|template import|create|delete]",
852438
- handler(args2, ctx) {
852745
+ usage: "[list|templates|guide|template show|template export|template import|template from-discovered|create|create-from-discovered|delete]",
852746
+ async handler(args2, ctx) {
852439
852747
  const shellPaths = requireShellPaths(ctx);
852440
852748
  const homeDirectory = shellPaths.homeDirectory;
852441
852749
  const parsed = stripYesFlag(args2);
@@ -852501,7 +852809,36 @@ function registerAgentRuntimeProfileRuntimeCommands(registry5) {
852501
852809
  use: /agent-profile create <name> --template ${template.id} --yes`);
852502
852810
  return;
852503
852811
  }
852504
- ctx.print("Usage: /agent-profile template [show <id>|export <id> <path> --yes|import <path> --yes]");
852812
+ if (mode === "from-discovered" || mode === "import-discovered") {
852813
+ const templateId = commandArgs[2];
852814
+ if (!templateId) {
852815
+ ctx.print("Usage: /agent-profile template from-discovered <id> [--name <name>] [--description <summary>] [--persona <name>] [--skills all|name,name] [--routines all|name,name] [--replace] --yes");
852816
+ return;
852817
+ }
852818
+ if (!parsed.yes) {
852819
+ requireYesFlag(ctx, `create Agent starter template ${templateId} from discovered behavior`, "/agent-profile template from-discovered <id> --yes");
852820
+ return;
852821
+ }
852822
+ const template = await createAgentRuntimeProfileTemplateFromDiscovered(shellPaths, {
852823
+ id: templateId,
852824
+ name: parseFlag(commandArgs, "--name"),
852825
+ description: parseFlag(commandArgs, "--description"),
852826
+ persona: parseFlag(commandArgs, "--persona"),
852827
+ skills: parseCsvFlag(commandArgs, "--skills"),
852828
+ routines: parseCsvFlag(commandArgs, "--routines"),
852829
+ replace: commandArgs.includes("--replace")
852830
+ });
852831
+ ctx.print([
852832
+ `Agent starter template created from discovered behavior: ${template.id}`,
852833
+ ` persona: ${template.personaName}`,
852834
+ ` skills: ${template.skillNames.join(", ")}`,
852835
+ ` routines: ${template.routineNames.join(", ")}`,
852836
+ ` use: /agent-profile create <name> --template ${template.id} --yes`
852837
+ ].join(`
852838
+ `));
852839
+ return;
852840
+ }
852841
+ ctx.print("Usage: /agent-profile template [show <id>|export <id> <path> --yes|import <path> --yes|from-discovered <id> --yes]");
852505
852842
  return;
852506
852843
  }
852507
852844
  if (sub === "create") {
@@ -852522,6 +852859,38 @@ function registerAgentRuntimeProfileRuntimeCommands(registry5) {
852522
852859
  profile5.starterTemplateId ? ` starter: ${profile5.starterTemplateId}` : "",
852523
852860
  ` launch: goodvibes-agent --agent-profile ${profile5.id}`
852524
852861
  ].filter(Boolean).join(`
852862
+ `));
852863
+ return;
852864
+ }
852865
+ if (sub === "create-from-discovered" || sub === "create-discovered") {
852866
+ const profileName = commandArgs[1];
852867
+ if (!profileName) {
852868
+ ctx.print("Usage: /agent-profile create-from-discovered <name> [--template-id <id>] [--profile-name <display>] [--description <summary>] [--persona <name>] [--skills all|name,name] [--routines all|name,name] [--replace] --yes");
852869
+ return;
852870
+ }
852871
+ if (!parsed.yes) {
852872
+ requireYesFlag(ctx, `create Agent profile ${profileName} from discovered behavior`, "/agent-profile create-from-discovered <name> --yes");
852873
+ return;
852874
+ }
852875
+ const created = await createAgentRuntimeProfileFromDiscovered(shellPaths, {
852876
+ profileName,
852877
+ templateId: parseFlag(commandArgs, "--template-id") ?? parseFlag(commandArgs, "--starter-id"),
852878
+ name: parseFlag(commandArgs, "--profile-name") ?? parseFlag(commandArgs, "--name"),
852879
+ description: parseFlag(commandArgs, "--description"),
852880
+ persona: parseFlag(commandArgs, "--persona"),
852881
+ skills: parseCsvFlag(commandArgs, "--skills"),
852882
+ routines: parseCsvFlag(commandArgs, "--routines"),
852883
+ replace: commandArgs.includes("--replace")
852884
+ });
852885
+ ctx.print([
852886
+ `Agent profile created from discovered behavior: ${created.profile.id}`,
852887
+ ` home: ${created.profile.homeDirectory}`,
852888
+ ` starter: ${created.template.id}`,
852889
+ ` persona: ${created.template.personaName}`,
852890
+ ` skills: ${created.template.skillNames.join(", ")}`,
852891
+ ` routines: ${created.template.routineNames.join(", ")}`,
852892
+ ` launch: goodvibes-agent --agent-profile ${created.profile.id}`
852893
+ ].join(`
852525
852894
  `));
852526
852895
  return;
852527
852896
  }
@@ -852538,7 +852907,7 @@ function registerAgentRuntimeProfileRuntimeCommands(registry5) {
852538
852907
  ctx.print(deleteAgentRuntimeProfile(homeDirectory, name51) ? `Agent profile deleted: ${name51}` : `Agent profile not found: ${name51}`);
852539
852908
  return;
852540
852909
  }
852541
- ctx.print("Usage: /agent-profile [list|templates|guide|template show <id>|template export <id> <path> --yes|template import <path> --yes|create <name> [--template <id>] --yes|delete <name> --yes]");
852910
+ ctx.print("Usage: /agent-profile [list|templates|guide|template show <id>|template export <id> <path> --yes|template import <path> --yes|create <name> [--template <id>] --yes|create-from-discovered <name> --yes|delete <name> --yes]");
852542
852911
  } catch (error51) {
852543
852912
  ctx.print(`Error: ${error51 instanceof Error ? error51.message : String(error51)}`);
852544
852913
  }
@@ -852664,100 +853033,6 @@ function registerDelegationRuntimeCommands(registry5) {
852664
853033
  });
852665
853034
  }
852666
853035
 
852667
- // src/agent/persona-discovery.ts
852668
- import { promises as fsPromises5 } from "fs";
852669
- import { join as join87 } from "path";
852670
- var DIRECTORY_MARKERS = ["PERSONA.md", "persona.md", "AGENT.md", "agent.md"];
852671
- function parseFrontmatter2(content) {
852672
- const match = content.match(/^---\n([\s\S]*?)\n---/);
852673
- if (!match)
852674
- return {};
852675
- const result2 = {};
852676
- for (const line of match[1].split(`
852677
- `)) {
852678
- const [key, ...rest] = line.split(":");
852679
- if (key && rest.length > 0) {
852680
- result2[key.trim()] = rest.join(":").trim();
852681
- }
852682
- }
852683
- return result2;
852684
- }
852685
- function getPersonaDirectories(cwd, homeDir) {
852686
- return [
852687
- { root: join87(cwd, ".goodvibes", "personas"), origin: "project-local" },
852688
- { root: join87(cwd, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "personas"), origin: "project-local" },
852689
- { root: join87(cwd, ".goodvibes", "agents"), origin: "project-local" },
852690
- { root: join87(homeDir, ".goodvibes", "personas"), origin: "global" },
852691
- { root: join87(homeDir, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "personas"), origin: "global" },
852692
- { root: join87(homeDir, ".goodvibes", "agents"), origin: "global" }
852693
- ];
852694
- }
852695
- async function readPersonaFile(path7, origin) {
852696
- let content = "";
852697
- try {
852698
- content = await fsPromises5.readFile(path7, "utf-8");
852699
- } catch {
852700
- return null;
852701
- }
852702
- const frontmatter = parseFrontmatter2(content);
852703
- const markdownBody = content.replace(/^---\n[\s\S]*?\n---\n?/, "").trim();
852704
- const body2 = (frontmatter.system_prompt ?? markdownBody).trim();
852705
- if (!body2)
852706
- return null;
852707
- const name51 = frontmatter.name ?? path7.split(/[\\/]/).pop()?.replace(/\.md$/i, "") ?? "persona";
852708
- const description = frontmatter.description ?? frontmatter.summary ?? frontmatter.title ?? "";
852709
- return {
852710
- name: name51,
852711
- description,
852712
- path: path7,
852713
- origin,
852714
- body: body2,
852715
- frontmatter
852716
- };
852717
- }
852718
- async function scanPersonaDirectory(root, origin) {
852719
- let entries = [];
852720
- try {
852721
- entries = await fsPromises5.readdir(root);
852722
- } catch {
852723
- return [];
852724
- }
852725
- const records = [];
852726
- for (const entry of entries.sort((a4, b3) => a4.localeCompare(b3))) {
852727
- if (entry.endsWith(".md")) {
852728
- const record2 = await readPersonaFile(join87(root, entry), origin);
852729
- if (record2)
852730
- records.push(record2);
852731
- continue;
852732
- }
852733
- for (const marker of DIRECTORY_MARKERS) {
852734
- const record2 = await readPersonaFile(join87(root, entry, marker), origin);
852735
- if (record2) {
852736
- records.push(record2);
852737
- break;
852738
- }
852739
- }
852740
- }
852741
- return records;
852742
- }
852743
- async function discoverPersonas(shellPaths) {
852744
- const seen = new Set;
852745
- const records = [];
852746
- for (const { root, origin } of getPersonaDirectories(shellPaths.workingDirectory, shellPaths.homeDirectory)) {
852747
- for (const record2 of await scanPersonaDirectory(root, origin)) {
852748
- const key = record2.name.toLowerCase();
852749
- if (seen.has(key))
852750
- continue;
852751
- seen.add(key);
852752
- records.push(record2);
852753
- }
852754
- }
852755
- return records.sort((a4, b3) => {
852756
- const originRank = a4.origin === b3.origin ? 0 : a4.origin === "project-local" ? -1 : 1;
852757
- return originRank || a4.name.localeCompare(b3.name);
852758
- });
852759
- }
852760
-
852761
853036
  // src/input/commands/personas-runtime.ts
852762
853037
  function parsePersonaArgs(args2) {
852763
853038
  const flags2 = new Map;
@@ -853497,98 +853772,6 @@ function registerAgentSkillsRuntimeCommands(registry5) {
853497
853772
  });
853498
853773
  }
853499
853774
 
853500
- // src/agent/routine-discovery.ts
853501
- import { promises as fsPromises6 } from "fs";
853502
- import { join as join88 } from "path";
853503
- var DIRECTORY_MARKERS2 = ["ROUTINE.md", "routine.md"];
853504
- function parseFrontmatter3(content) {
853505
- const match = content.match(/^---\n([\s\S]*?)\n---/);
853506
- if (!match)
853507
- return {};
853508
- const result2 = {};
853509
- for (const line of match[1].split(`
853510
- `)) {
853511
- const [key, ...rest] = line.split(":");
853512
- if (key && rest.length > 0) {
853513
- result2[key.trim()] = rest.join(":").trim();
853514
- }
853515
- }
853516
- return result2;
853517
- }
853518
- function getRoutineDirectories(cwd, homeDir) {
853519
- return [
853520
- { root: join88(cwd, ".goodvibes", "routines"), origin: "project-local" },
853521
- { root: join88(cwd, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "routines"), origin: "project-local" },
853522
- { root: join88(homeDir, ".goodvibes", "routines"), origin: "global" },
853523
- { root: join88(homeDir, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "routines"), origin: "global" }
853524
- ];
853525
- }
853526
- async function readRoutineFile(path7, origin) {
853527
- let content = "";
853528
- try {
853529
- content = await fsPromises6.readFile(path7, "utf-8");
853530
- } catch {
853531
- return null;
853532
- }
853533
- const frontmatter = parseFrontmatter3(content);
853534
- const markdownBody = content.replace(/^---\n[\s\S]*?\n---\n?/, "").trim();
853535
- const steps = (frontmatter.steps ?? markdownBody).trim();
853536
- if (!steps)
853537
- return null;
853538
- const name51 = frontmatter.name ?? path7.split(/[\\/]/).pop()?.replace(/\.md$/i, "") ?? "routine";
853539
- const description = frontmatter.description ?? frontmatter.summary ?? frontmatter.title ?? "";
853540
- return {
853541
- name: name51,
853542
- description,
853543
- path: path7,
853544
- origin,
853545
- steps,
853546
- frontmatter
853547
- };
853548
- }
853549
- async function scanRoutineDirectory(root, origin) {
853550
- let entries = [];
853551
- try {
853552
- entries = await fsPromises6.readdir(root);
853553
- } catch {
853554
- return [];
853555
- }
853556
- const records = [];
853557
- for (const entry of entries.sort((a4, b3) => a4.localeCompare(b3))) {
853558
- if (entry.endsWith(".md")) {
853559
- const record2 = await readRoutineFile(join88(root, entry), origin);
853560
- if (record2)
853561
- records.push(record2);
853562
- continue;
853563
- }
853564
- for (const marker of DIRECTORY_MARKERS2) {
853565
- const record2 = await readRoutineFile(join88(root, entry, marker), origin);
853566
- if (record2) {
853567
- records.push(record2);
853568
- break;
853569
- }
853570
- }
853571
- }
853572
- return records;
853573
- }
853574
- async function discoverRoutines(shellPaths) {
853575
- const seen = new Set;
853576
- const records = [];
853577
- for (const { root, origin } of getRoutineDirectories(shellPaths.workingDirectory, shellPaths.homeDirectory)) {
853578
- for (const record2 of await scanRoutineDirectory(root, origin)) {
853579
- const key = record2.name.toLowerCase();
853580
- if (seen.has(key))
853581
- continue;
853582
- seen.add(key);
853583
- records.push(record2);
853584
- }
853585
- }
853586
- return records.sort((a4, b3) => {
853587
- const originRank = a4.origin === b3.origin ? 0 : a4.origin === "project-local" ? -1 : 1;
853588
- return originRank || a4.name.localeCompare(b3.name);
853589
- });
853590
- }
853591
-
853592
853775
  // src/input/commands/routines-runtime.ts
853593
853776
  function parseRoutineArgs(args2) {
853594
853777
  const flags2 = new Map;
@@ -854489,6 +854672,143 @@ Use /channels list to see available channel ids.`);
854489
854672
  // src/input/agent-workspace-snapshot.ts
854490
854673
  import { basename as basename5, sep as sep3 } from "path";
854491
854674
 
854675
+ // src/agent/behavior-discovery-summary.ts
854676
+ import { readdirSync as readdirSync21, readFileSync as readFileSync80 } from "fs";
854677
+ import { join as join90 } from "path";
854678
+ var EMPTY_SUMMARY = {
854679
+ count: 0,
854680
+ projectLocalCount: 0,
854681
+ globalCount: 0,
854682
+ names: []
854683
+ };
854684
+ var EMPTY_AGENT_BEHAVIOR_DISCOVERY_SNAPSHOT = {
854685
+ personas: EMPTY_SUMMARY,
854686
+ skills: EMPTY_SUMMARY,
854687
+ routines: EMPTY_SUMMARY
854688
+ };
854689
+ function parseFrontmatter4(content) {
854690
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
854691
+ if (!match)
854692
+ return {};
854693
+ const result2 = {};
854694
+ for (const line of match[1].split(`
854695
+ `)) {
854696
+ const [key, ...rest] = line.split(":");
854697
+ if (key && rest.length > 0) {
854698
+ result2[key.trim()] = rest.join(":").trim();
854699
+ }
854700
+ }
854701
+ return result2;
854702
+ }
854703
+ function markdownBody(content) {
854704
+ return content.replace(/^---\n[\s\S]*?\n---\n?/, "").trim();
854705
+ }
854706
+ function readDiscoveryCandidate(path7, origin, definition) {
854707
+ let content = "";
854708
+ try {
854709
+ content = readFileSync80(path7, "utf-8");
854710
+ } catch {
854711
+ return null;
854712
+ }
854713
+ const frontmatter = parseFrontmatter4(content);
854714
+ const body2 = definition.frontmatterBodyKey ? (frontmatter[definition.frontmatterBodyKey] ?? markdownBody(content)).trim() : markdownBody(content);
854715
+ if (body2.length === 0)
854716
+ return null;
854717
+ const name51 = frontmatter.name ?? path7.split(/[\\/]/).pop()?.replace(/\.md$/i, "") ?? "";
854718
+ const normalized = name51.trim();
854719
+ return normalized ? { name: normalized, origin } : null;
854720
+ }
854721
+ function candidatePaths(root, entry, markers) {
854722
+ if (entry.endsWith(".md"))
854723
+ return [join90(root, entry)];
854724
+ return markers.map((marker) => join90(root, entry, marker));
854725
+ }
854726
+ function summarizeDefinition(definition, limit3) {
854727
+ const seen = new Set;
854728
+ const names2 = [];
854729
+ let projectLocalCount = 0;
854730
+ let globalCount = 0;
854731
+ for (const { root, origin } of definition.roots) {
854732
+ let entries = [];
854733
+ try {
854734
+ entries = readdirSync21(root);
854735
+ } catch {
854736
+ continue;
854737
+ }
854738
+ for (const entry of entries.sort((left, right) => left.localeCompare(right))) {
854739
+ for (const path7 of candidatePaths(root, entry, definition.markers)) {
854740
+ const candidate = readDiscoveryCandidate(path7, origin, definition);
854741
+ if (!candidate)
854742
+ continue;
854743
+ const key = candidate.name.toLowerCase();
854744
+ if (seen.has(key))
854745
+ break;
854746
+ seen.add(key);
854747
+ if (candidate.origin === "project-local")
854748
+ projectLocalCount += 1;
854749
+ else
854750
+ globalCount += 1;
854751
+ if (names2.length < limit3)
854752
+ names2.push(candidate.name);
854753
+ break;
854754
+ }
854755
+ }
854756
+ }
854757
+ if (seen.size === 0)
854758
+ return EMPTY_SUMMARY;
854759
+ return {
854760
+ count: seen.size,
854761
+ projectLocalCount,
854762
+ globalCount,
854763
+ names: names2
854764
+ };
854765
+ }
854766
+ function definitions(shellPaths) {
854767
+ const cwd = shellPaths.workingDirectory;
854768
+ const homeDir = shellPaths.homeDirectory;
854769
+ const personas = {
854770
+ roots: [
854771
+ { root: join90(cwd, ".goodvibes", "personas"), origin: "project-local" },
854772
+ { root: join90(cwd, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "personas"), origin: "project-local" },
854773
+ { root: join90(cwd, ".goodvibes", "agents"), origin: "project-local" },
854774
+ { root: join90(homeDir, ".goodvibes", "personas"), origin: "global" },
854775
+ { root: join90(homeDir, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "personas"), origin: "global" },
854776
+ { root: join90(homeDir, ".goodvibes", "agents"), origin: "global" }
854777
+ ],
854778
+ markers: ["PERSONA.md", "persona.md", "AGENT.md", "agent.md"],
854779
+ frontmatterBodyKey: "system_prompt"
854780
+ };
854781
+ const skills = {
854782
+ roots: [
854783
+ { root: join90(cwd, ".goodvibes", "skills"), origin: "project-local" },
854784
+ { root: join90(cwd, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "skills"), origin: "project-local" },
854785
+ { root: join90(homeDir, ".goodvibes", "skills"), origin: "global" },
854786
+ { root: join90(homeDir, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "skills"), origin: "global" }
854787
+ ],
854788
+ markers: ["SKILL.md"]
854789
+ };
854790
+ const routines = {
854791
+ roots: [
854792
+ { root: join90(cwd, ".goodvibes", "routines"), origin: "project-local" },
854793
+ { root: join90(cwd, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "routines"), origin: "project-local" },
854794
+ { root: join90(homeDir, ".goodvibes", "routines"), origin: "global" },
854795
+ { root: join90(homeDir, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "routines"), origin: "global" }
854796
+ ],
854797
+ markers: ["ROUTINE.md", "routine.md"],
854798
+ frontmatterBodyKey: "steps"
854799
+ };
854800
+ return {
854801
+ personas: summarizeDefinition(personas, 4),
854802
+ skills: summarizeDefinition(skills, 4),
854803
+ routines: summarizeDefinition(routines, 4)
854804
+ };
854805
+ }
854806
+ function summarizeAgentBehaviorDiscovery(shellPaths) {
854807
+ if (!shellPaths)
854808
+ return EMPTY_AGENT_BEHAVIOR_DISCOVERY_SNAPSHOT;
854809
+ return definitions(shellPaths);
854810
+ }
854811
+
854492
854812
  // src/agent/memory-prompt.ts
854493
854813
  var DEFAULT_LIMIT = 10;
854494
854814
  var MIN_PROMPT_MEMORY_CONFIDENCE = 50;
@@ -854521,9 +854841,16 @@ function buildReviewedMemoryPrompt(memoryRegistry, limit3 = DEFAULT_LIMIT) {
854521
854841
  function setupStatusForCount(count, ready, empty) {
854522
854842
  return count > 0 ? ready : empty;
854523
854843
  }
854844
+ function sampleNames(summary) {
854845
+ if (summary.names.length === 0)
854846
+ return "";
854847
+ const suffix = summary.count > summary.names.length ? `, +${summary.count - summary.names.length} more` : "";
854848
+ return ` Found: ${summary.names.join(", ")}${suffix}.`;
854849
+ }
854524
854850
  function buildAgentWorkspaceSetupChecklist(input) {
854525
854851
  const providerReady = input.provider !== "unknown" && input.model !== "unknown";
854526
854852
  const hasActivePersona = input.activePersonaName !== "(none)" && input.activePersonaName !== "(unavailable)";
854853
+ const discoveredBehaviorCount = input.discoveredPersonas.count + input.discoveredSkills.count + input.discoveredRoutines.count;
854527
854854
  return [
854528
854855
  {
854529
854856
  id: "runtime",
@@ -854549,30 +854876,30 @@ function buildAgentWorkspaceSetupChecklist(input) {
854549
854876
  {
854550
854877
  id: "profile",
854551
854878
  label: "Agent profile",
854552
- status: setupStatusForCount(input.runtimeProfileCount, "ready", "optional"),
854553
- detail: input.runtimeProfileCount > 0 ? `${input.runtimeProfileCount} isolated Agent profile(s) are available.` : `${input.runtimeStarterTemplateCount} starter template(s) are available if this machine needs separate operator identities.`,
854554
- command: "/agent-profile templates"
854879
+ status: input.runtimeProfileCount > 0 ? "ready" : discoveredBehaviorCount > 0 ? "recommended" : "optional",
854880
+ detail: input.runtimeProfileCount > 0 ? `${input.runtimeProfileCount} isolated Agent profile(s) are available.` : discoveredBehaviorCount > 0 ? `${discoveredBehaviorCount} discovered behavior file(s) can seed an isolated Agent profile from the Profiles workspace.` : `${input.runtimeStarterTemplateCount} starter template(s) are available if this machine needs separate operator identities.`,
854881
+ command: discoveredBehaviorCount > 0 && input.runtimeProfileCount === 0 ? "/agent-profile guide" : "/agent-profile templates"
854555
854882
  },
854556
854883
  {
854557
854884
  id: "persona",
854558
854885
  label: "Persona",
854559
854886
  status: hasActivePersona ? "ready" : "recommended",
854560
- detail: hasActivePersona ? `Active persona: ${input.activePersonaName}.` : "Create or choose a persona to make the assistant voice and policy explicit.",
854561
- command: "/personas"
854887
+ detail: hasActivePersona ? `Active persona: ${input.activePersonaName}.${input.discoveredPersonas.count > 0 ? ` ${input.discoveredPersonas.count} discovered persona file(s) are still available to import.` : ""}` : input.discoveredPersonas.count > 0 ? `${input.discoveredPersonas.count} discovered persona file(s) can be imported into the Agent-local registry.${sampleNames(input.discoveredPersonas)}` : "Create or choose a persona to make the assistant voice and policy explicit.",
854888
+ command: input.discoveredPersonas.count > 0 ? "/personas discover" : "/personas"
854562
854889
  },
854563
854890
  {
854564
854891
  id: "skills",
854565
854892
  label: "Skills",
854566
- status: input.enabledSkillCount > 0 || input.enabledSkillBundleCount > 0 ? "ready" : input.skillCount > 0 || input.skillBundleCount > 0 ? "recommended" : "optional",
854567
- detail: input.skillCount > 0 || input.skillBundleCount > 0 ? `${input.enabledSkillCount}/${input.skillCount} local skill(s) enabled; ${input.enabledSkillBundleCount}/${input.skillBundleCount} bundle(s) enabled.` : "Create reusable local skills and bundles for repeated workflows.",
854568
- command: "/agent-skills"
854893
+ status: input.enabledSkillCount > 0 || input.enabledSkillBundleCount > 0 ? "ready" : input.skillCount > 0 || input.skillBundleCount > 0 || input.discoveredSkills.count > 0 ? "recommended" : "optional",
854894
+ detail: input.skillCount > 0 || input.skillBundleCount > 0 ? `${input.enabledSkillCount}/${input.skillCount} local skill(s) enabled; ${input.enabledSkillBundleCount}/${input.skillBundleCount} bundle(s) enabled.${input.discoveredSkills.count > 0 ? ` ${input.discoveredSkills.count} discovered skill file(s) are still available to import.` : ""}` : input.discoveredSkills.count > 0 ? `${input.discoveredSkills.count} discovered skill file(s) can be imported as local reusable procedures.${sampleNames(input.discoveredSkills)}` : "Create reusable local skills and bundles for repeated workflows.",
854895
+ command: input.discoveredSkills.count > 0 ? "/agent-skills discover" : "/agent-skills"
854569
854896
  },
854570
854897
  {
854571
854898
  id: "routines",
854572
854899
  label: "Routines",
854573
- status: setupStatusForCount(input.enabledRoutineCount, "ready", input.routineCount > 0 ? "recommended" : "optional"),
854574
- detail: input.routineCount > 0 ? `${input.enabledRoutineCount}/${input.routineCount} local routine(s) enabled.` : "Create local routines first; promote schedules only with explicit confirmation.",
854575
- command: "/routines"
854900
+ status: setupStatusForCount(input.enabledRoutineCount, "ready", input.routineCount > 0 || input.discoveredRoutines.count > 0 ? "recommended" : "optional"),
854901
+ detail: input.routineCount > 0 ? `${input.enabledRoutineCount}/${input.routineCount} local routine(s) enabled.${input.discoveredRoutines.count > 0 ? ` ${input.discoveredRoutines.count} discovered routine file(s) are still available to import.` : ""}` : input.discoveredRoutines.count > 0 ? `${input.discoveredRoutines.count} discovered routine file(s) can be imported as main-conversation workflows.${sampleNames(input.discoveredRoutines)}` : "Create local routines first; promote schedules only with explicit confirmation.",
854902
+ command: input.discoveredRoutines.count > 0 ? "/routines discover" : "/routines"
854576
854903
  },
854577
854904
  {
854578
854905
  id: "memory",
@@ -854949,6 +855276,7 @@ function buildAgentWorkspaceRuntimeSnapshot(context) {
854949
855276
  return { count: 0, enabled: 0, items: [] };
854950
855277
  }
854951
855278
  })();
855279
+ const discoveredBehavior = summarizeAgentBehaviorDiscovery(context.workspace?.shellPaths);
854952
855280
  const runtimeProfiles = (() => {
854953
855281
  try {
854954
855282
  return listAgentRuntimeProfiles(context.workspace?.shellPaths?.homeDirectory ?? "");
@@ -855035,6 +855363,9 @@ function buildAgentWorkspaceRuntimeSnapshot(context) {
855035
855363
  skillBundleCount: skillSnapshot.bundleCount,
855036
855364
  enabledSkillBundleCount: skillSnapshot.enabledBundleCount,
855037
855365
  activePersonaName: personaSnapshot.activeName,
855366
+ discoveredPersonas: discoveredBehavior.personas,
855367
+ discoveredSkills: discoveredBehavior.skills,
855368
+ discoveredRoutines: discoveredBehavior.routines,
855038
855369
  readyChannelCount: channels.filter((channel) => channel.ready).length,
855039
855370
  voiceProviderCount: voiceProviders.length,
855040
855371
  mediaProviderCount: mediaProviders.length,
@@ -855068,6 +855399,7 @@ function buildAgentWorkspaceRuntimeSnapshot(context) {
855068
855399
  localPersonaCount: personaSnapshot.count,
855069
855400
  activePersonaName: personaSnapshot.activeName,
855070
855401
  localPersonas: personaSnapshot.items,
855402
+ discoveredBehavior,
855071
855403
  knowledgeRoute: "/api/goodvibes-agent/knowledge",
855072
855404
  knowledgeIsolation: "agent-only",
855073
855405
  executionPolicy: "serial-proactive",
@@ -855259,8 +855591,8 @@ function registerBuiltinCommands(registry5) {
855259
855591
  }
855260
855592
 
855261
855593
  // src/input/input-history.ts
855262
- import { existsSync as existsSync73, mkdirSync as mkdirSync61, readFileSync as readFileSync80, writeFileSync as writeFileSync52 } from "fs";
855263
- import { dirname as dirname59, join as join90 } from "path";
855594
+ import { existsSync as existsSync73, mkdirSync as mkdirSync61, readFileSync as readFileSync81, writeFileSync as writeFileSync52 } from "fs";
855595
+ import { dirname as dirname59, join as join91 } from "path";
855264
855596
  class HistorySearch {
855265
855597
  getEntries;
855266
855598
  active = false;
@@ -855339,7 +855671,7 @@ function resolveHistoryPath2(options) {
855339
855671
  if (!userRoot) {
855340
855672
  throw new Error("InputHistory requires historyPath or an explicit userRoot/homeDirectory.");
855341
855673
  }
855342
- return join90(userRoot, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "input-history.json");
855674
+ return join91(userRoot, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "input-history.json");
855343
855675
  }
855344
855676
 
855345
855677
  class InputHistory {
@@ -855420,7 +855752,7 @@ class InputHistory {
855420
855752
  load() {
855421
855753
  try {
855422
855754
  if (existsSync73(this.historyPath)) {
855423
- const raw = readFileSync80(this.historyPath, "utf-8");
855755
+ const raw = readFileSync81(this.historyPath, "utf-8");
855424
855756
  const parsed = JSON.parse(raw);
855425
855757
  if (Array.isArray(parsed)) {
855426
855758
  this.entries = parsed.map((entry) => this.normalizeStoredEntry(entry)).filter((entry) => entry !== null).slice(0, this.maxEntries);
@@ -861193,7 +861525,7 @@ function registerAgentPanels(manager5, deps) {
861193
861525
 
861194
861526
  // src/panels/builtin/session.ts
861195
861527
  import { networkInterfaces as networkInterfaces3 } from "os";
861196
- import { readFileSync as readFileSync81 } from "fs";
861528
+ import { readFileSync as readFileSync82 } from "fs";
861197
861529
 
861198
861530
  // src/panels/confirm-state.ts
861199
861531
  function handleConfirmInput(confirm, key) {
@@ -862769,7 +863101,7 @@ function getLocalNetworkIp2() {
862769
863101
  }
862770
863102
  function readBootstrapPassword(credentialPath) {
862771
863103
  try {
862772
- const content = readFileSync81(credentialPath, "utf-8");
863104
+ const content = readFileSync82(credentialPath, "utf-8");
862773
863105
  for (const line2 of content.split(`
862774
863106
  `)) {
862775
863107
  if (line2.startsWith("password=")) {
@@ -864141,7 +864473,7 @@ function createBootstrapShell(options) {
864141
864473
  hookActivityTracker: services.hookActivityTracker,
864142
864474
  hookWorkbench: services.hookWorkbench,
864143
864475
  mcpRegistry: services.mcpRegistry,
864144
- daemonHomeDir: join91(services.homeDirectory, ".goodvibes", "daemon")
864476
+ daemonHomeDir: join92(services.homeDirectory, ".goodvibes", "daemon")
864145
864477
  });
864146
864478
  services.panelManager.prewarmRegistered();
864147
864479
  const systemMessageRouter = createSystemMessageRouter(conversation, systemMessagesPanel, (kind2) => {
@@ -866087,7 +866419,7 @@ var verifyBundle2 = exports_security2.verifyBundle;
866087
866419
  var MAX_INPUT_LENGTH2 = exports_security2.MAX_INPUT_LENGTH;
866088
866420
  var MAX_TOKEN_COUNT2 = exports_security2.MAX_TOKEN_COUNT;
866089
866421
  // src/runtime/onboarding/state.ts
866090
- import { existsSync as existsSync74, mkdirSync as mkdirSync62, readFileSync as readFileSync82, writeFileSync as writeFileSync53 } from "fs";
866422
+ import { existsSync as existsSync74, mkdirSync as mkdirSync62, readFileSync as readFileSync83, writeFileSync as writeFileSync53 } from "fs";
866091
866423
  import { dirname as dirname60 } from "path";
866092
866424
  var ONBOARDING_RUNTIME_STATE_FILE = "onboarding-state.json";
866093
866425
  function resolveStatePath(shellPaths, scope) {
@@ -866133,7 +866465,7 @@ function readOnboardingRuntimeState(shellPaths, scope = "project") {
866133
866465
  };
866134
866466
  }
866135
866467
  try {
866136
- const parsed = JSON.parse(readFileSync82(path7, "utf-8"));
866468
+ const parsed = JSON.parse(readFileSync83(path7, "utf-8"));
866137
866469
  if (!isRuntimeStatePayload(parsed)) {
866138
866470
  return {
866139
866471
  scope,
@@ -866493,6 +866825,7 @@ async function collectOnboardingSnapshot(deps) {
866493
866825
  records: sortSurfaceRecords(surfaceResult.value)
866494
866826
  },
866495
866827
  providerAccounts: providerAccountsResult.value,
866828
+ localBehaviorDiscovery: summarizeAgentBehaviorDiscovery(deps.shellPaths),
866496
866829
  collectionIssues
866497
866830
  };
866498
866831
  }
@@ -866550,13 +866883,13 @@ var INBOUND_EVENT_SURFACE_KINDS = new Set([
866550
866883
  ]);
866551
866884
  // src/runtime/onboarding/apply.ts
866552
866885
  init_config8();
866553
- import { existsSync as existsSync76, mkdirSync as mkdirSync63, readFileSync as readFileSync83, rmSync as rmSync10, unlinkSync as unlinkSync12, writeFileSync as writeFileSync54 } from "fs";
866886
+ import { existsSync as existsSync76, mkdirSync as mkdirSync63, readFileSync as readFileSync84, rmSync as rmSync10, unlinkSync as unlinkSync12, writeFileSync as writeFileSync54 } from "fs";
866554
866887
  import { dirname as dirname61 } from "path";
866555
866888
 
866556
866889
  // src/runtime/onboarding/verify.ts
866557
866890
  init_config8();
866558
866891
  import { existsSync as existsSync75 } from "fs";
866559
- import { join as join92 } from "path";
866892
+ import { join as join93 } from "path";
866560
866893
  function getNow(deps) {
866561
866894
  return deps.clock?.() ?? Date.now();
866562
866895
  }
@@ -866637,7 +866970,7 @@ function verifyAuthOperation(_deps, operation) {
866637
866970
  }
866638
866971
  function verifyCreateAgentProfileOperation(deps, operation) {
866639
866972
  const resolution2 = resolveAgentRuntimeProfileHome(deps.shellPaths.homeDirectory, operation.name);
866640
- const ok3 = existsSync75(join92(resolution2.homeDirectory, "profile.json"));
866973
+ const ok3 = existsSync75(join93(resolution2.homeDirectory, "profile.json"));
866641
866974
  return {
866642
866975
  id: `agent-profile:${resolution2.id}`,
866643
866976
  status: ok3 ? "pass" : "fail",
@@ -866675,7 +867008,7 @@ function isPlainObject3(value) {
866675
867008
  function readJsonObject(path7) {
866676
867009
  if (!existsSync76(path7))
866677
867010
  return {};
866678
- const parsed = JSON.parse(readFileSync83(path7, "utf-8"));
867011
+ const parsed = JSON.parse(readFileSync84(path7, "utf-8"));
866679
867012
  if (!isPlainObject3(parsed))
866680
867013
  throw new Error(`Expected an object JSON payload at ${path7}.`);
866681
867014
  return parsed;
@@ -866710,7 +867043,7 @@ function restoreFile(path7, previous, reload) {
866710
867043
  reload?.();
866711
867044
  }
866712
867045
  function snapshotFileRollback(path7, reload) {
866713
- const previous = existsSync76(path7) ? readFileSync83(path7, "utf-8") : null;
867046
+ const previous = existsSync76(path7) ? readFileSync84(path7, "utf-8") : null;
866714
867047
  return () => restoreFile(path7, previous, reload);
866715
867048
  }
866716
867049
  async function runRollbacks(rollbacks) {
@@ -866873,7 +867206,7 @@ async function buildSecretRollbackAction(deps, operation) {
866873
867206
  throw new Error(`Secret storage locations for ${scope} scope are unavailable.`);
866874
867207
  const snapshots = locations.map((location) => ({
866875
867208
  path: location.path,
866876
- previous: existsSync76(location.path) ? readFileSync83(location.path, "utf-8") : null
867209
+ previous: existsSync76(location.path) ? readFileSync84(location.path, "utf-8") : null
866877
867210
  }));
866878
867211
  return () => {
866879
867212
  for (const snapshot of snapshots)
@@ -867093,7 +867426,7 @@ async function applyOnboardingRequest(deps, request2) {
867093
867426
  };
867094
867427
  }
867095
867428
  // src/runtime/onboarding/markers.ts
867096
- import { existsSync as existsSync77, mkdirSync as mkdirSync64, readFileSync as readFileSync84, writeFileSync as writeFileSync55 } from "fs";
867429
+ import { existsSync as existsSync77, mkdirSync as mkdirSync64, readFileSync as readFileSync85, writeFileSync as writeFileSync55 } from "fs";
867097
867430
  import { dirname as dirname62 } from "path";
867098
867431
  var ONBOARDING_CHECK_MARKER_FILE = "onboarding-checked.json";
867099
867432
  function resolveMarkerPath(shellPaths, scope) {
@@ -867140,7 +867473,7 @@ function readOnboardingCheckMarker(shellPaths, scope = "user") {
867140
867473
  if (!existsSync77(path7))
867141
867474
  return buildMissingMarkerState(scope, path7);
867142
867475
  try {
867143
- const parsed = JSON.parse(readFileSync84(path7, "utf-8"));
867476
+ const parsed = JSON.parse(readFileSync85(path7, "utf-8"));
867144
867477
  if (!isCheckMarkerPayload(parsed)) {
867145
867478
  return buildParseErrorState(scope, path7, "Invalid onboarding check marker payload.");
867146
867479
  }
@@ -867182,7 +867515,7 @@ function writeOnboardingCheckMarker(shellPaths, options = {}) {
867182
867515
  return readOnboardingCheckMarker(shellPaths, scope);
867183
867516
  }
867184
867517
  // src/input/handler-content-actions.ts
867185
- import { readFileSync as readFileSync85, existsSync as existsSync78 } from "fs";
867518
+ import { readFileSync as readFileSync86, existsSync as existsSync78 } from "fs";
867186
867519
  var MARKER_REGEX = /\[(TEXT|IMAGE): [^\]]+\]/g;
867187
867520
  var IMAGE_PREFIXES = [
867188
867521
  { prefix: "iVBORw0KGgo", mediaType: "image/png" },
@@ -867244,7 +867577,7 @@ function registerPaste(state4, content, projectRoot) {
867244
867577
  try {
867245
867578
  const resolvedPath3 = resolveAndValidatePath(trimmed2, projectRoot);
867246
867579
  if (existsSync78(resolvedPath3)) {
867247
- const data = readFileSync85(resolvedPath3);
867580
+ const data = readFileSync86(resolvedPath3);
867248
867581
  const base644 = data.toString("base64");
867249
867582
  const ext = trimmed2.slice(trimmed2.lastIndexOf("."));
867250
867583
  const mediaType = mediaTypeFromExt(ext);
@@ -867294,7 +867627,7 @@ function expandPrompt(pasteRegistry, imageRegistry, text, projectRoot) {
867294
867627
  const filePath = injectMatch[1];
867295
867628
  try {
867296
867629
  const resolvedPath3 = resolveAndValidatePath(filePath, projectRoot);
867297
- const content = readFileSync85(resolvedPath3, "utf-8");
867630
+ const content = readFileSync86(resolvedPath3, "utf-8");
867298
867631
  expanded = expanded.slice(0, injectMatch.index) + content + expanded.slice(injectMatch.index + injectMatch[0].length);
867299
867632
  injectRegex.lastIndex = injectMatch.index + content.length;
867300
867633
  } catch (err2) {
@@ -868694,7 +869027,7 @@ class AutocompleteEngine {
868694
869027
 
868695
869028
  // src/input/file-picker.ts
868696
869029
  import { readdir as readdir6 } from "fs/promises";
868697
- import { join as join93, relative as relative15 } from "path";
869030
+ import { join as join94, relative as relative15 } from "path";
868698
869031
 
868699
869032
  class FilePickerModal {
868700
869033
  shellPaths;
@@ -868827,7 +869160,7 @@ class FilePickerModal {
868827
869160
  continue;
868828
869161
  if (entry.name === "node_modules" || entry.name === "dist")
868829
869162
  continue;
868830
- const fullPath = join93(dir, entry.name);
869163
+ const fullPath = join94(dir, entry.name);
868831
869164
  const relPath = relative15(this.shellPaths.workingDirectory, fullPath);
868832
869165
  if (entry.isDirectory()) {
868833
869166
  files.push(relPath + "/");
@@ -872249,246 +872582,13 @@ function quoteSlashCommandArg(value) {
872249
872582
  return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
872250
872583
  }
872251
872584
 
872252
- // src/input/agent-workspace-basic-command-editors.ts
872585
+ // src/input/agent-workspace-basic-command-editor-submission.ts
872253
872586
  function isAffirmative2(value) {
872254
872587
  return /^(y|yes|true)$/i.test(value.trim());
872255
872588
  }
872256
872589
  function splitCommaList(value) {
872257
872590
  return value.split(",").map((entry) => entry.trim()).filter(Boolean);
872258
872591
  }
872259
- function isAgentWorkspaceBasicCommandEditorKind(kind2) {
872260
- return kind2 === "knowledge-bookmarks" || kind2 === "knowledge-file" || kind2 === "knowledge-browser-history" || kind2 === "knowledge-connector-ingest" || kind2 === "tts-prompt" || kind2 === "image-input" || kind2 === "skill-bundle" || kind2 === "persona-discovery-import" || kind2 === "routine-discovery-import" || kind2 === "skill-discovery-import" || kind2 === "profile-template-export" || kind2 === "profile-template-import" || kind2 === "mcp-server" || kind2 === "notify-webhook" || kind2 === "notify-webhook-remove" || kind2 === "notify-webhook-test";
872261
- }
872262
- function createAgentWorkspaceBasicCommandEditor(kind2) {
872263
- if (kind2 === "knowledge-bookmarks") {
872264
- return {
872265
- kind: kind2,
872266
- mode: "create",
872267
- title: "Import Bookmarks into Agent Knowledge",
872268
- selectedFieldIndex: 0,
872269
- message: "Import a browser bookmark export into the isolated Agent Knowledge segment. Type yes on the final field to confirm.",
872270
- fields: [
872271
- { id: "path", label: "Bookmark export path", value: "", required: true, multiline: false, hint: "Path to an HTML or JSON browser bookmark export." },
872272
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /knowledge import-bookmarks with --yes." }
872273
- ]
872274
- };
872275
- }
872276
- if (kind2 === "knowledge-file") {
872277
- return {
872278
- kind: kind2,
872279
- mode: "create",
872280
- title: "Ingest File into Agent Knowledge",
872281
- selectedFieldIndex: 0,
872282
- message: "Import a local source-backed file into the isolated Agent Knowledge segment. Type yes on the final field to confirm.",
872283
- fields: [
872284
- { id: "path", label: "File path", value: "", required: true, multiline: false, hint: "Path to a local document or text file to ingest." },
872285
- { id: "title", label: "Title", value: "", required: false, multiline: false, hint: "Optional source title." },
872286
- { id: "tags", label: "Tags", value: "", required: false, multiline: false, hint: "Comma-separated optional tags." },
872287
- { id: "folder", label: "Folder", value: "", required: false, multiline: false, hint: "Optional Agent Knowledge folder path." },
872288
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /knowledge ingest-file with --yes." }
872289
- ]
872290
- };
872291
- }
872292
- if (kind2 === "knowledge-browser-history") {
872293
- return {
872294
- kind: kind2,
872295
- mode: "create",
872296
- title: "Import Browser History into Agent Knowledge",
872297
- selectedFieldIndex: 0,
872298
- message: "Import local browser history/bookmarks into the isolated Agent Knowledge segment. Type yes on the final field to confirm.",
872299
- fields: [
872300
- { id: "browsers", label: "Browsers", value: "", required: false, multiline: false, hint: "Optional comma list: chrome, brave, edge, firefox, safari, etc." },
872301
- { id: "sources", label: "Sources", value: "history,bookmark", required: false, multiline: false, hint: "history, bookmark, or both." },
872302
- { id: "limit", label: "Limit", value: "250", required: false, multiline: false, hint: "Maximum browser entries to import." },
872303
- { id: "sinceDays", label: "Since days", value: "", required: false, multiline: false, hint: "Optional age window, such as 30." },
872304
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /knowledge import-browser-history with --yes." }
872305
- ]
872306
- };
872307
- }
872308
- if (kind2 === "knowledge-connector-ingest") {
872309
- return {
872310
- kind: kind2,
872311
- mode: "create",
872312
- title: "Ingest Connector Input",
872313
- selectedFieldIndex: 0,
872314
- message: "Send explicit connector input into the isolated Agent Knowledge segment. Type yes on the final field to confirm.",
872315
- fields: [
872316
- { id: "connectorId", label: "Connector id", value: "", required: true, multiline: false, hint: "Connector id from /knowledge connectors." },
872317
- { id: "input", label: "Input", value: "", required: false, multiline: true, hint: "Optional JSON or text input. Ctrl-J inserts a new line." },
872318
- { id: "path", label: "Path", value: "", required: false, multiline: false, hint: "Optional local path for connectors that read files." },
872319
- { id: "content", label: "Content", value: "", required: false, multiline: true, hint: "Optional raw content for connectors that accept text." },
872320
- { id: "allowPrivateHosts", label: "Allow private hosts", value: "no", required: false, multiline: false, hint: "yes/no. Defaults to no." },
872321
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /knowledge ingest-connector with --yes." }
872322
- ]
872323
- };
872324
- }
872325
- if (kind2 === "mcp-server") {
872326
- return {
872327
- kind: kind2,
872328
- mode: "create",
872329
- title: "Add MCP Server",
872330
- selectedFieldIndex: 0,
872331
- message: "Add or update one MCP server from the Agent workspace. Type yes on the final field to confirm.",
872332
- fields: [
872333
- { id: "name", label: "Server name", value: "", required: true, multiline: false, hint: "Letters, numbers, dot, underscore, and dash only." },
872334
- { id: "command", label: "Command", value: "", required: true, multiline: false, hint: "Executable command, such as bunx, npx, uvx, or a full local binary path." },
872335
- { id: "args", label: "Arguments", value: "", required: false, multiline: false, hint: "Optional command arguments. Quotes are supported." },
872336
- { id: "scope", label: "Scope", value: "", required: false, multiline: false, hint: "Optional. Defaults to project. Use project or global." },
872337
- { id: "role", label: "Role", value: "", required: false, multiline: false, hint: "Optional. general, docs, filesystem, git, database, browser, automation, ops, or remote." },
872338
- { id: "trust", label: "Trust mode", value: "", required: false, multiline: false, hint: "Optional. Defaults to constrained. Use constrained, ask-on-risk, or blocked. Use settings for allow-all." },
872339
- { id: "env", label: "Env refs", value: "", required: false, multiline: false, hint: "Comma-separated KEY=VALUE entries. Prefer secret refs, not raw secrets." },
872340
- { id: "paths", label: "Allowed paths", value: "", required: false, multiline: false, hint: "Comma-separated path allowlist entries." },
872341
- { id: "hosts", label: "Allowed hosts", value: "", required: false, multiline: false, hint: "Comma-separated host allowlist entries." },
872342
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /mcp add with --yes." }
872343
- ]
872344
- };
872345
- }
872346
- if (kind2 === "notify-webhook") {
872347
- return {
872348
- kind: kind2,
872349
- mode: "create",
872350
- title: "Add Notification Webhook",
872351
- selectedFieldIndex: 0,
872352
- message: "Add one webhook notification target for explicit reminder/routine delivery. Type yes on the final field to confirm.",
872353
- fields: [
872354
- { id: "url", label: "Webhook URL", value: "", required: true, multiline: false, hint: "HTTP(S) target, for example https://ntfy.sh/my-topic." },
872355
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /notify add with --yes." }
872356
- ]
872357
- };
872358
- }
872359
- if (kind2 === "notify-webhook-remove") {
872360
- return {
872361
- kind: kind2,
872362
- mode: "delete",
872363
- title: "Remove Notification Webhook",
872364
- selectedFieldIndex: 0,
872365
- message: "Remove one configured webhook notification target. Type yes on the final field to confirm.",
872366
- fields: [
872367
- { id: "url", label: "Webhook URL", value: "", required: true, multiline: false, hint: "Exact HTTP(S) webhook URL to remove from configured notification targets." },
872368
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /notify remove with --yes." }
872369
- ]
872370
- };
872371
- }
872372
- if (kind2 === "notify-webhook-test") {
872373
- return {
872374
- kind: kind2,
872375
- mode: "create",
872376
- title: "Test Notification Webhooks",
872377
- selectedFieldIndex: 0,
872378
- message: "Send one test notification to configured webhook targets. Type yes on the final field to confirm.",
872379
- fields: [
872380
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /notify test with --yes." }
872381
- ]
872382
- };
872383
- }
872384
- if (kind2 === "tts-prompt") {
872385
- return {
872386
- kind: kind2,
872387
- mode: "create",
872388
- title: "Speak Assistant Reply",
872389
- selectedFieldIndex: 0,
872390
- message: "Submit a normal assistant prompt and play the reply through configured live TTS.",
872391
- fields: [
872392
- { id: "prompt", label: "Prompt", value: "", required: true, multiline: true, hint: "Assistant prompt to speak. Ctrl-J inserts a new line." }
872393
- ]
872394
- };
872395
- }
872396
- if (kind2 === "image-input") {
872397
- return {
872398
- kind: kind2,
872399
- mode: "create",
872400
- title: "Attach Image Input",
872401
- selectedFieldIndex: 0,
872402
- message: "Attach an image to the next assistant turn. The existing image command validates file type and model support.",
872403
- fields: [
872404
- { id: "path", label: "Image path", value: "", required: true, multiline: false, hint: "PNG, JPEG, WebP, or GIF path under the current workspace." },
872405
- { id: "prompt", label: "Prompt", value: "", required: false, multiline: true, hint: "Optional prompt. Ctrl-J inserts a new line." }
872406
- ]
872407
- };
872408
- }
872409
- if (kind2 === "profile-template-export") {
872410
- return {
872411
- kind: kind2,
872412
- mode: "create",
872413
- title: "Export Agent Starter Template",
872414
- selectedFieldIndex: 0,
872415
- message: "Export a starter template JSON file for review and customization. Type yes on the final field to confirm.",
872416
- fields: [
872417
- { id: "templateId", label: "Starter id", value: "", required: true, multiline: false, hint: "Existing starter id from /agent-profile templates." },
872418
- { id: "path", label: "Output path", value: "", required: true, multiline: false, hint: "Workspace-relative JSON path to write." },
872419
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /agent-profile template export with --yes." }
872420
- ]
872421
- };
872422
- }
872423
- if (kind2 === "profile-template-import") {
872424
- return {
872425
- kind: kind2,
872426
- mode: "create",
872427
- title: "Import Agent Starter Template",
872428
- selectedFieldIndex: 0,
872429
- message: "Import a reviewed starter template JSON file into this Agent home. Type yes on the final field to confirm.",
872430
- fields: [
872431
- { id: "path", label: "Template path", value: "", required: true, multiline: false, hint: "Workspace-relative JSON path to import." },
872432
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /agent-profile template import with --yes." }
872433
- ]
872434
- };
872435
- }
872436
- if (kind2 === "skill-discovery-import") {
872437
- return {
872438
- kind: kind2,
872439
- mode: "create",
872440
- title: "Import Discovered Skill",
872441
- selectedFieldIndex: 0,
872442
- message: "Import one discovered SKILL.md or .md skill file into the Agent-local skill registry. Type yes on the final field to confirm.",
872443
- fields: [
872444
- { id: "name", label: "Discovered skill", value: "", required: true, multiline: false, hint: "Name shown by /agent-skills discover." },
872445
- { id: "enabled", label: "Enable now", value: "yes", required: false, multiline: false, hint: "yes/no." },
872446
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /agent-skills import-discovered with --yes." }
872447
- ]
872448
- };
872449
- }
872450
- if (kind2 === "persona-discovery-import") {
872451
- return {
872452
- kind: kind2,
872453
- mode: "create",
872454
- title: "Import Discovered Persona",
872455
- selectedFieldIndex: 0,
872456
- message: "Import one discovered persona markdown file into the Agent-local persona registry. Type yes on the final field to confirm.",
872457
- fields: [
872458
- { id: "name", label: "Discovered persona", value: "", required: true, multiline: false, hint: "Name shown by /personas discover." },
872459
- { id: "use", label: "Use now", value: "yes", required: false, multiline: false, hint: "yes/no." },
872460
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /personas import-discovered with --yes." }
872461
- ]
872462
- };
872463
- }
872464
- if (kind2 === "routine-discovery-import") {
872465
- return {
872466
- kind: kind2,
872467
- mode: "create",
872468
- title: "Import Discovered Routine",
872469
- selectedFieldIndex: 0,
872470
- message: "Import one discovered routine markdown file into the Agent-local routine registry. Type yes on the final field to confirm.",
872471
- fields: [
872472
- { id: "name", label: "Discovered routine", value: "", required: true, multiline: false, hint: "Name shown by /routines discover." },
872473
- { id: "enabled", label: "Enable now", value: "yes", required: false, multiline: false, hint: "yes/no." },
872474
- { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /routines import-discovered with --yes." }
872475
- ]
872476
- };
872477
- }
872478
- return {
872479
- kind: kind2,
872480
- mode: "create",
872481
- title: "Create Skill Bundle",
872482
- selectedFieldIndex: 0,
872483
- message: "Group existing local skills into a reviewable bundle that can be enabled together.",
872484
- fields: [
872485
- { id: "name", label: "Bundle name", value: "", required: true, multiline: false, hint: "Short bundle name." },
872486
- { id: "description", label: "Description", value: "", required: true, multiline: false, hint: "One-line bundle summary." },
872487
- { id: "skills", label: "Skill ids", value: "", required: true, multiline: false, hint: "Comma-separated existing local skill ids." },
872488
- { id: "enabled", label: "Enable now", value: "yes", required: false, multiline: false, hint: "yes/no." }
872489
- ]
872490
- };
872491
- }
872492
872592
  function buildAgentWorkspaceBasicCommandEditorSubmission(editor, readField, commandDispatchAvailable) {
872493
872593
  if (!commandDispatchAvailable) {
872494
872594
  return {
@@ -872815,6 +872915,100 @@ function buildAgentWorkspaceBasicCommandEditorSubmission(editor, readField, comm
872815
872915
  }
872816
872916
  };
872817
872917
  }
872918
+ if (editor.kind === "profile-template-from-discovered") {
872919
+ if (!isAffirmative2(readField("confirm"))) {
872920
+ return {
872921
+ kind: "editor",
872922
+ editor: { ...editor, message: "Starter-from-discovered creation not confirmed. Type yes, then press Enter." },
872923
+ status: "Agent starter-from-discovered creation not confirmed."
872924
+ };
872925
+ }
872926
+ const parts2 = [
872927
+ "/agent-profile",
872928
+ "template",
872929
+ "from-discovered",
872930
+ quoteSlashCommandArg(readField("id"))
872931
+ ];
872932
+ const name51 = readField("name");
872933
+ const description = readField("description");
872934
+ const persona = readField("persona");
872935
+ const skills = readField("skills");
872936
+ const routines = readField("routines");
872937
+ if (name51.length > 0)
872938
+ parts2.push("--name", quoteSlashCommandArg(name51));
872939
+ if (description.length > 0)
872940
+ parts2.push("--description", quoteSlashCommandArg(description));
872941
+ if (persona.length > 0)
872942
+ parts2.push("--persona", quoteSlashCommandArg(persona));
872943
+ if (skills.length > 0)
872944
+ parts2.push("--skills", quoteSlashCommandArg(skills));
872945
+ if (routines.length > 0)
872946
+ parts2.push("--routines", quoteSlashCommandArg(routines));
872947
+ if (isAffirmative2(readField("replace")))
872948
+ parts2.push("--replace");
872949
+ parts2.push("--yes");
872950
+ const command9 = parts2.join(" ");
872951
+ return {
872952
+ kind: "dispatch",
872953
+ command: command9,
872954
+ status: "Opening Agent starter-from-discovered creation.",
872955
+ actionResult: {
872956
+ kind: "dispatched",
872957
+ title: "Opening Agent starter-from-discovered creation",
872958
+ detail: "The workspace handed a confirmed starter creation command to the shell-owned command router.",
872959
+ command: command9,
872960
+ safety: "safe"
872961
+ }
872962
+ };
872963
+ }
872964
+ if (editor.kind === "profile-from-discovered") {
872965
+ if (!isAffirmative2(readField("confirm"))) {
872966
+ return {
872967
+ kind: "editor",
872968
+ editor: { ...editor, message: "Profile-from-discovered creation not confirmed. Type yes, then press Enter." },
872969
+ status: "Agent profile-from-discovered creation not confirmed."
872970
+ };
872971
+ }
872972
+ const parts2 = [
872973
+ "/agent-profile",
872974
+ "create-from-discovered",
872975
+ quoteSlashCommandArg(readField("profile"))
872976
+ ];
872977
+ const templateId = readField("templateId");
872978
+ const name51 = readField("name");
872979
+ const description = readField("description");
872980
+ const persona = readField("persona");
872981
+ const skills = readField("skills");
872982
+ const routines = readField("routines");
872983
+ if (templateId.length > 0)
872984
+ parts2.push("--template-id", quoteSlashCommandArg(templateId));
872985
+ if (name51.length > 0)
872986
+ parts2.push("--name", quoteSlashCommandArg(name51));
872987
+ if (description.length > 0)
872988
+ parts2.push("--description", quoteSlashCommandArg(description));
872989
+ if (persona.length > 0)
872990
+ parts2.push("--persona", quoteSlashCommandArg(persona));
872991
+ if (skills.length > 0)
872992
+ parts2.push("--skills", quoteSlashCommandArg(skills));
872993
+ if (routines.length > 0)
872994
+ parts2.push("--routines", quoteSlashCommandArg(routines));
872995
+ if (isAffirmative2(readField("replace")))
872996
+ parts2.push("--replace");
872997
+ parts2.push("--yes");
872998
+ const command9 = parts2.join(" ");
872999
+ return {
873000
+ kind: "dispatch",
873001
+ command: command9,
873002
+ status: "Opening Agent profile-from-discovered creation.",
873003
+ actionResult: {
873004
+ kind: "dispatched",
873005
+ title: "Opening Agent profile-from-discovered creation",
873006
+ detail: "The workspace handed a confirmed discovered-behavior profile creation command to the shell-owned command router.",
873007
+ command: command9,
873008
+ safety: "safe"
873009
+ }
873010
+ };
873011
+ }
872818
873012
  if (editor.kind === "skill-discovery-import") {
872819
873013
  if (!isAffirmative2(readField("confirm"))) {
872820
873014
  return {
@@ -872931,6 +873125,280 @@ function buildAgentWorkspaceBasicCommandEditorSubmission(editor, readField, comm
872931
873125
  };
872932
873126
  }
872933
873127
 
873128
+ // src/input/agent-workspace-basic-command-editors.ts
873129
+ function isAgentWorkspaceBasicCommandEditorKind(kind2) {
873130
+ return kind2 === "knowledge-bookmarks" || kind2 === "knowledge-file" || kind2 === "knowledge-browser-history" || kind2 === "knowledge-connector-ingest" || kind2 === "tts-prompt" || kind2 === "image-input" || kind2 === "skill-bundle" || kind2 === "persona-discovery-import" || kind2 === "routine-discovery-import" || kind2 === "skill-discovery-import" || kind2 === "profile-template-export" || kind2 === "profile-template-import" || kind2 === "profile-template-from-discovered" || kind2 === "profile-from-discovered" || kind2 === "mcp-server" || kind2 === "notify-webhook" || kind2 === "notify-webhook-remove" || kind2 === "notify-webhook-test";
873131
+ }
873132
+ function createAgentWorkspaceBasicCommandEditor(kind2) {
873133
+ if (kind2 === "knowledge-bookmarks") {
873134
+ return {
873135
+ kind: kind2,
873136
+ mode: "create",
873137
+ title: "Import Bookmarks into Agent Knowledge",
873138
+ selectedFieldIndex: 0,
873139
+ message: "Import a browser bookmark export into the isolated Agent Knowledge segment. Type yes on the final field to confirm.",
873140
+ fields: [
873141
+ { id: "path", label: "Bookmark export path", value: "", required: true, multiline: false, hint: "Path to an HTML or JSON browser bookmark export." },
873142
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /knowledge import-bookmarks with --yes." }
873143
+ ]
873144
+ };
873145
+ }
873146
+ if (kind2 === "knowledge-file") {
873147
+ return {
873148
+ kind: kind2,
873149
+ mode: "create",
873150
+ title: "Ingest File into Agent Knowledge",
873151
+ selectedFieldIndex: 0,
873152
+ message: "Import a local source-backed file into the isolated Agent Knowledge segment. Type yes on the final field to confirm.",
873153
+ fields: [
873154
+ { id: "path", label: "File path", value: "", required: true, multiline: false, hint: "Path to a local document or text file to ingest." },
873155
+ { id: "title", label: "Title", value: "", required: false, multiline: false, hint: "Optional source title." },
873156
+ { id: "tags", label: "Tags", value: "", required: false, multiline: false, hint: "Comma-separated optional tags." },
873157
+ { id: "folder", label: "Folder", value: "", required: false, multiline: false, hint: "Optional Agent Knowledge folder path." },
873158
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /knowledge ingest-file with --yes." }
873159
+ ]
873160
+ };
873161
+ }
873162
+ if (kind2 === "knowledge-browser-history") {
873163
+ return {
873164
+ kind: kind2,
873165
+ mode: "create",
873166
+ title: "Import Browser History into Agent Knowledge",
873167
+ selectedFieldIndex: 0,
873168
+ message: "Import local browser history/bookmarks into the isolated Agent Knowledge segment. Type yes on the final field to confirm.",
873169
+ fields: [
873170
+ { id: "browsers", label: "Browsers", value: "", required: false, multiline: false, hint: "Optional comma list: chrome, brave, edge, firefox, safari, etc." },
873171
+ { id: "sources", label: "Sources", value: "history,bookmark", required: false, multiline: false, hint: "history, bookmark, or both." },
873172
+ { id: "limit", label: "Limit", value: "250", required: false, multiline: false, hint: "Maximum browser entries to import." },
873173
+ { id: "sinceDays", label: "Since days", value: "", required: false, multiline: false, hint: "Optional age window, such as 30." },
873174
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /knowledge import-browser-history with --yes." }
873175
+ ]
873176
+ };
873177
+ }
873178
+ if (kind2 === "knowledge-connector-ingest") {
873179
+ return {
873180
+ kind: kind2,
873181
+ mode: "create",
873182
+ title: "Ingest Connector Input",
873183
+ selectedFieldIndex: 0,
873184
+ message: "Send explicit connector input into the isolated Agent Knowledge segment. Type yes on the final field to confirm.",
873185
+ fields: [
873186
+ { id: "connectorId", label: "Connector id", value: "", required: true, multiline: false, hint: "Connector id from /knowledge connectors." },
873187
+ { id: "input", label: "Input", value: "", required: false, multiline: true, hint: "Optional JSON or text input. Ctrl-J inserts a new line." },
873188
+ { id: "path", label: "Path", value: "", required: false, multiline: false, hint: "Optional local path for connectors that read files." },
873189
+ { id: "content", label: "Content", value: "", required: false, multiline: true, hint: "Optional raw content for connectors that accept text." },
873190
+ { id: "allowPrivateHosts", label: "Allow private hosts", value: "no", required: false, multiline: false, hint: "yes/no. Defaults to no." },
873191
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /knowledge ingest-connector with --yes." }
873192
+ ]
873193
+ };
873194
+ }
873195
+ if (kind2 === "mcp-server") {
873196
+ return {
873197
+ kind: kind2,
873198
+ mode: "create",
873199
+ title: "Add MCP Server",
873200
+ selectedFieldIndex: 0,
873201
+ message: "Add or update one MCP server from the Agent workspace. Type yes on the final field to confirm.",
873202
+ fields: [
873203
+ { id: "name", label: "Server name", value: "", required: true, multiline: false, hint: "Letters, numbers, dot, underscore, and dash only." },
873204
+ { id: "command", label: "Command", value: "", required: true, multiline: false, hint: "Executable command, such as bunx, npx, uvx, or a full local binary path." },
873205
+ { id: "args", label: "Arguments", value: "", required: false, multiline: false, hint: "Optional command arguments. Quotes are supported." },
873206
+ { id: "scope", label: "Scope", value: "", required: false, multiline: false, hint: "Optional. Defaults to project. Use project or global." },
873207
+ { id: "role", label: "Role", value: "", required: false, multiline: false, hint: "Optional. general, docs, filesystem, git, database, browser, automation, ops, or remote." },
873208
+ { id: "trust", label: "Trust mode", value: "", required: false, multiline: false, hint: "Optional. Defaults to constrained. Use constrained, ask-on-risk, or blocked. Use settings for allow-all." },
873209
+ { id: "env", label: "Env refs", value: "", required: false, multiline: false, hint: "Comma-separated KEY=VALUE entries. Prefer secret refs, not raw secrets." },
873210
+ { id: "paths", label: "Allowed paths", value: "", required: false, multiline: false, hint: "Comma-separated path allowlist entries." },
873211
+ { id: "hosts", label: "Allowed hosts", value: "", required: false, multiline: false, hint: "Comma-separated host allowlist entries." },
873212
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /mcp add with --yes." }
873213
+ ]
873214
+ };
873215
+ }
873216
+ if (kind2 === "notify-webhook") {
873217
+ return {
873218
+ kind: kind2,
873219
+ mode: "create",
873220
+ title: "Add Notification Webhook",
873221
+ selectedFieldIndex: 0,
873222
+ message: "Add one webhook notification target for explicit reminder/routine delivery. Type yes on the final field to confirm.",
873223
+ fields: [
873224
+ { id: "url", label: "Webhook URL", value: "", required: true, multiline: false, hint: "HTTP(S) target, for example https://ntfy.sh/my-topic." },
873225
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /notify add with --yes." }
873226
+ ]
873227
+ };
873228
+ }
873229
+ if (kind2 === "notify-webhook-remove") {
873230
+ return {
873231
+ kind: kind2,
873232
+ mode: "delete",
873233
+ title: "Remove Notification Webhook",
873234
+ selectedFieldIndex: 0,
873235
+ message: "Remove one configured webhook notification target. Type yes on the final field to confirm.",
873236
+ fields: [
873237
+ { id: "url", label: "Webhook URL", value: "", required: true, multiline: false, hint: "Exact HTTP(S) webhook URL to remove from configured notification targets." },
873238
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /notify remove with --yes." }
873239
+ ]
873240
+ };
873241
+ }
873242
+ if (kind2 === "notify-webhook-test") {
873243
+ return {
873244
+ kind: kind2,
873245
+ mode: "create",
873246
+ title: "Test Notification Webhooks",
873247
+ selectedFieldIndex: 0,
873248
+ message: "Send one test notification to configured webhook targets. Type yes on the final field to confirm.",
873249
+ fields: [
873250
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /notify test with --yes." }
873251
+ ]
873252
+ };
873253
+ }
873254
+ if (kind2 === "tts-prompt") {
873255
+ return {
873256
+ kind: kind2,
873257
+ mode: "create",
873258
+ title: "Speak Assistant Reply",
873259
+ selectedFieldIndex: 0,
873260
+ message: "Submit a normal assistant prompt and play the reply through configured live TTS.",
873261
+ fields: [
873262
+ { id: "prompt", label: "Prompt", value: "", required: true, multiline: true, hint: "Assistant prompt to speak. Ctrl-J inserts a new line." }
873263
+ ]
873264
+ };
873265
+ }
873266
+ if (kind2 === "image-input") {
873267
+ return {
873268
+ kind: kind2,
873269
+ mode: "create",
873270
+ title: "Attach Image Input",
873271
+ selectedFieldIndex: 0,
873272
+ message: "Attach an image to the next assistant turn. The existing image command validates file type and model support.",
873273
+ fields: [
873274
+ { id: "path", label: "Image path", value: "", required: true, multiline: false, hint: "PNG, JPEG, WebP, or GIF path under the current workspace." },
873275
+ { id: "prompt", label: "Prompt", value: "", required: false, multiline: true, hint: "Optional prompt. Ctrl-J inserts a new line." }
873276
+ ]
873277
+ };
873278
+ }
873279
+ if (kind2 === "profile-template-export") {
873280
+ return {
873281
+ kind: kind2,
873282
+ mode: "create",
873283
+ title: "Export Agent Starter Template",
873284
+ selectedFieldIndex: 0,
873285
+ message: "Export a starter template JSON file for review and customization. Type yes on the final field to confirm.",
873286
+ fields: [
873287
+ { id: "templateId", label: "Starter id", value: "", required: true, multiline: false, hint: "Existing starter id from /agent-profile templates." },
873288
+ { id: "path", label: "Output path", value: "", required: true, multiline: false, hint: "Workspace-relative JSON path to write." },
873289
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /agent-profile template export with --yes." }
873290
+ ]
873291
+ };
873292
+ }
873293
+ if (kind2 === "profile-template-import") {
873294
+ return {
873295
+ kind: kind2,
873296
+ mode: "create",
873297
+ title: "Import Agent Starter Template",
873298
+ selectedFieldIndex: 0,
873299
+ message: "Import a reviewed starter template JSON file into this Agent home. Type yes on the final field to confirm.",
873300
+ fields: [
873301
+ { id: "path", label: "Template path", value: "", required: true, multiline: false, hint: "Workspace-relative JSON path to import." },
873302
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /agent-profile template import with --yes." }
873303
+ ]
873304
+ };
873305
+ }
873306
+ if (kind2 === "profile-template-from-discovered") {
873307
+ return {
873308
+ kind: kind2,
873309
+ mode: "create",
873310
+ title: "Create Starter from Discovered Behavior",
873311
+ selectedFieldIndex: 0,
873312
+ message: "Create an Agent-local starter template from reviewed discovered persona, skill, and routine markdown. Type yes on the final field to confirm.",
873313
+ fields: [
873314
+ { id: "id", label: "Starter id", value: "", required: true, multiline: false, hint: "New local starter id, for example research-desk." },
873315
+ { id: "name", label: "Starter name", value: "", required: false, multiline: false, hint: "Optional display name. Defaults to the selected persona name." },
873316
+ { id: "description", label: "Description", value: "", required: false, multiline: false, hint: "Optional one-line summary." },
873317
+ { id: "persona", label: "Persona", value: "", required: false, multiline: false, hint: "Optional discovered persona name/path. Blank uses the first discovered persona." },
873318
+ { id: "skills", label: "Skills", value: "", required: false, multiline: false, hint: "all or comma-separated discovered skill names. Blank includes all." },
873319
+ { id: "routines", label: "Routines", value: "", required: false, multiline: false, hint: "all or comma-separated discovered routine names. Blank includes all." },
873320
+ { id: "replace", label: "Replace existing", value: "no", required: false, multiline: false, hint: "yes/no. Existing starter ids are protected unless this is yes." },
873321
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /agent-profile template from-discovered with --yes." }
873322
+ ]
873323
+ };
873324
+ }
873325
+ if (kind2 === "profile-from-discovered") {
873326
+ return {
873327
+ kind: kind2,
873328
+ mode: "create",
873329
+ title: "Create Profile from Discovered Behavior",
873330
+ selectedFieldIndex: 0,
873331
+ message: "Create a local starter template and isolated Agent profile from reviewed discovered behavior markdown. Type yes on the final field to confirm.",
873332
+ fields: [
873333
+ { id: "profile", label: "Profile name", value: "", required: true, multiline: false, hint: "New isolated Agent profile name, for example research-desk." },
873334
+ { id: "templateId", label: "Starter id", value: "", required: false, multiline: false, hint: "Optional local starter id. Blank uses the profile name." },
873335
+ { id: "name", label: "Starter name", value: "", required: false, multiline: false, hint: "Optional display name for the generated starter." },
873336
+ { id: "description", label: "Description", value: "", required: false, multiline: false, hint: "Optional one-line summary." },
873337
+ { id: "persona", label: "Persona", value: "", required: false, multiline: false, hint: "Optional discovered persona name/path. Blank uses the first discovered persona." },
873338
+ { id: "skills", label: "Skills", value: "", required: false, multiline: false, hint: "all or comma-separated discovered skill names. Blank includes all." },
873339
+ { id: "routines", label: "Routines", value: "", required: false, multiline: false, hint: "all or comma-separated discovered routine names. Blank includes all." },
873340
+ { id: "replace", label: "Replace starter", value: "no", required: false, multiline: false, hint: "yes/no. Existing starter ids are protected unless this is yes." },
873341
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /agent-profile create-from-discovered with --yes." }
873342
+ ]
873343
+ };
873344
+ }
873345
+ if (kind2 === "skill-discovery-import") {
873346
+ return {
873347
+ kind: kind2,
873348
+ mode: "create",
873349
+ title: "Import Discovered Skill",
873350
+ selectedFieldIndex: 0,
873351
+ message: "Import one discovered SKILL.md or .md skill file into the Agent-local skill registry. Type yes on the final field to confirm.",
873352
+ fields: [
873353
+ { id: "name", label: "Discovered skill", value: "", required: true, multiline: false, hint: "Name shown by /agent-skills discover." },
873354
+ { id: "enabled", label: "Enable now", value: "yes", required: false, multiline: false, hint: "yes/no." },
873355
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /agent-skills import-discovered with --yes." }
873356
+ ]
873357
+ };
873358
+ }
873359
+ if (kind2 === "persona-discovery-import") {
873360
+ return {
873361
+ kind: kind2,
873362
+ mode: "create",
873363
+ title: "Import Discovered Persona",
873364
+ selectedFieldIndex: 0,
873365
+ message: "Import one discovered persona markdown file into the Agent-local persona registry. Type yes on the final field to confirm.",
873366
+ fields: [
873367
+ { id: "name", label: "Discovered persona", value: "", required: true, multiline: false, hint: "Name shown by /personas discover." },
873368
+ { id: "use", label: "Use now", value: "yes", required: false, multiline: false, hint: "yes/no." },
873369
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /personas import-discovered with --yes." }
873370
+ ]
873371
+ };
873372
+ }
873373
+ if (kind2 === "routine-discovery-import") {
873374
+ return {
873375
+ kind: kind2,
873376
+ mode: "create",
873377
+ title: "Import Discovered Routine",
873378
+ selectedFieldIndex: 0,
873379
+ message: "Import one discovered routine markdown file into the Agent-local routine registry. Type yes on the final field to confirm.",
873380
+ fields: [
873381
+ { id: "name", label: "Discovered routine", value: "", required: true, multiline: false, hint: "Name shown by /routines discover." },
873382
+ { id: "enabled", label: "Enable now", value: "yes", required: false, multiline: false, hint: "yes/no." },
873383
+ { id: "confirm", label: "Confirm", value: "", required: true, multiline: false, hint: "Type yes to run /routines import-discovered with --yes." }
873384
+ ]
873385
+ };
873386
+ }
873387
+ return {
873388
+ kind: kind2,
873389
+ mode: "create",
873390
+ title: "Create Skill Bundle",
873391
+ selectedFieldIndex: 0,
873392
+ message: "Group existing local skills into a reviewable bundle that can be enabled together.",
873393
+ fields: [
873394
+ { id: "name", label: "Bundle name", value: "", required: true, multiline: false, hint: "Short bundle name." },
873395
+ { id: "description", label: "Description", value: "", required: true, multiline: false, hint: "One-line bundle summary." },
873396
+ { id: "skills", label: "Skill ids", value: "", required: true, multiline: false, hint: "Comma-separated existing local skill ids." },
873397
+ { id: "enabled", label: "Enable now", value: "yes", required: false, multiline: false, hint: "yes/no." }
873398
+ ]
873399
+ };
873400
+ }
873401
+
872934
873402
  // src/input/agent-workspace-knowledge-query-editor.ts
872935
873403
  function createAgentKnowledgeQueryEditor(mode) {
872936
873404
  return {
@@ -873354,6 +873822,7 @@ var AGENT_WORKSPACE_CATEGORIES = [
873354
873822
  { id: "setup-provider-model", label: "Provider and model", detail: "Choose the provider/model route for normal assistant chat.", command: "/model", kind: "command", safety: "safe" },
873355
873823
  { id: "setup-agent-knowledge", label: "Agent Knowledge", detail: "Inspect the isolated Agent Knowledge store before ingesting source-backed material.", command: "/knowledge status", kind: "command", safety: "read-only" },
873356
873824
  { id: "setup-runtime-profiles", label: "Agent profiles", detail: "Browse starter templates for isolated Agent homes and operator identities.", command: "/agent-profile templates", kind: "command", safety: "read-only" },
873825
+ { id: "setup-profile-from-discovered", label: "Profile from discovered behavior", detail: "Create an isolated Agent profile directly from reviewed local persona, skill, and routine files.", editorKind: "profile-from-discovered", kind: "editor", safety: "safe" },
873357
873826
  { id: "setup-personas", label: "Personas", detail: "Create or select the active local Agent persona.", targetCategoryId: "personas", kind: "workspace", safety: "safe" },
873358
873827
  { id: "setup-skills", label: "Skills", detail: "Create, review, and enable reusable local Agent skills.", targetCategoryId: "skills", kind: "workspace", safety: "safe" },
873359
873828
  { id: "setup-routines", label: "Routines", detail: "Create, review, and enable local Agent routines before any explicit schedule promotion.", targetCategoryId: "routines", kind: "workspace", safety: "safe" },
@@ -873445,6 +873914,8 @@ var AGENT_WORKSPACE_CATEGORIES = [
873445
873914
  { id: "runtime-profile-list", label: "List Agent profiles", detail: "List isolated Agent profile homes under this Agent home.", command: "/agent-profile list", kind: "command", safety: "read-only" },
873446
873915
  { id: "runtime-profile-template-export", label: "Export starter template", detail: "Open an in-workspace form that exports a starter template JSON file for review and customization.", editorKind: "profile-template-export", kind: "editor", safety: "safe" },
873447
873916
  { id: "runtime-profile-template-import", label: "Import starter template", detail: "Open an in-workspace form that imports a reviewed starter template JSON file into this Agent home.", editorKind: "profile-template-import", kind: "editor", safety: "safe" },
873917
+ { id: "runtime-profile-template-from-discovered", label: "Starter from discovered behavior", detail: "Open an in-workspace form that creates one local starter template from reviewed discovered persona, skill, and routine files.", editorKind: "profile-template-from-discovered", kind: "editor", safety: "safe" },
873918
+ { id: "runtime-profile-from-discovered", label: "Profile from discovered behavior", detail: "Open an in-workspace form that creates a local starter and isolated Agent profile from reviewed discovered behavior files.", editorKind: "profile-from-discovered", kind: "editor", safety: "safe" },
873448
873919
  { id: "runtime-profile-create", label: "Create Agent profile", detail: "Open an in-workspace form that creates an isolated Agent home from a built-in or local starter.", editorKind: "profile", kind: "editor", safety: "safe" },
873449
873920
  { id: "runtime-profile-template-edit", label: "Customize starter", detail: "Open the starter export form, edit the JSON file, then import it as a local starter.", editorKind: "profile-template-export", kind: "editor", safety: "safe" },
873450
873921
  { id: "runtime-profile-switch", label: "Switch Agent profile", detail: "Launch goodvibes-agent --agent-profile NAME to use that isolated Agent home. This workspace cannot switch the current process home after startup.", kind: "guidance", safety: "safe" }
@@ -874952,6 +875423,33 @@ function getOnboardingWizardVisibleFieldCount(viewportHeight) {
874952
875423
  }
874953
875424
 
874954
875425
  // src/input/onboarding/onboarding-wizard-operator-steps.ts
875426
+ function discoveryCount(discovery) {
875427
+ if (!discovery)
875428
+ return 0;
875429
+ return discovery.personas.count + discovery.skills.count + discovery.routines.count;
875430
+ }
875431
+ function discoverySummary(discovery) {
875432
+ if (!discovery || discoveryCount(discovery) === 0)
875433
+ return "No importable local behavior files found yet";
875434
+ return [
875435
+ `${discovery.personas.count} persona file(s)`,
875436
+ `${discovery.skills.count} skill file(s)`,
875437
+ `${discovery.routines.count} routine file(s)`
875438
+ ].join("; ");
875439
+ }
875440
+ function discoverySample(discovery) {
875441
+ if (!discovery)
875442
+ return "";
875443
+ const names2 = [
875444
+ ...discovery.personas.names,
875445
+ ...discovery.skills.names,
875446
+ ...discovery.routines.names
875447
+ ].slice(0, 4);
875448
+ if (names2.length === 0)
875449
+ return "Use /personas discover, /agent-skills discover, and /routines discover after setup to rescan.";
875450
+ const remaining = discoveryCount(discovery) > names2.length ? `, +${discoveryCount(discovery) - names2.length} more` : "";
875451
+ return `Import candidates: ${names2.join(", ")}${remaining}.`;
875452
+ }
874955
875453
  function buildCommunicationStep() {
874956
875454
  return {
874957
875455
  id: "agent-communication",
@@ -875077,15 +875575,17 @@ function buildAgentKnowledgeStep() {
875077
875575
  ]
875078
875576
  };
875079
875577
  }
875080
- function buildLocalStateStep() {
875578
+ function buildLocalStateStep(discovery) {
875579
+ const discoveredCount = discoveryCount(discovery);
875081
875580
  return {
875082
875581
  id: "agent-local-state",
875083
875582
  title: "Local memory and behavior",
875084
- shortLabel: "Memory",
875085
- description: "Review the Agent-local behavior model. Memory, personas, skills, routines, and Agent profiles stay local until a stable shared registry exists.",
875583
+ shortLabel: "Behavior",
875584
+ description: discoveredCount > 0 ? "Review importable Agent-local behavior files, then create an isolated profile from them or import individual records." : "Review the Agent-local behavior model. Memory, personas, skills, routines, and Agent profiles stay local until a stable shared registry exists.",
875086
875585
  summaryTitle: "Local Agent state",
875087
875586
  summaryLines: [
875088
875587
  "Memory/personas/skills/routines: local Agent registries",
875588
+ `Discovered behavior files: ${discoverySummary(discovery)}`,
875089
875589
  "Secrets: rejected or stored by secret reference",
875090
875590
  "Profiles: isolated Agent homes"
875091
875591
  ],
@@ -875101,22 +875601,22 @@ function buildLocalStateStep() {
875101
875601
  kind: "status",
875102
875602
  id: "agent-local-state.personas",
875103
875603
  label: "Personas",
875104
- hint: "Use /personas to create and activate serial operating modes for the main conversation.",
875105
- defaultValue: "Local registry"
875604
+ hint: discovery?.personas.count && discovery.personas.count > 0 ? `${discovery.personas.count} persona file(s) are available. Use the Profiles workspace to create a profile from discovered behavior, or preview individual files with /personas discover.` : "Use /personas to create and activate serial operating modes for the main conversation.",
875605
+ defaultValue: discovery?.personas.count && discovery.personas.count > 0 ? `${discovery.personas.count} discovered` : "Local registry"
875106
875606
  },
875107
875607
  {
875108
875608
  kind: "status",
875109
875609
  id: "agent-local-state.skills",
875110
875610
  label: "Skills",
875111
- hint: "Use /agent-skills and /skills local to manage reusable Agent procedures.",
875112
- defaultValue: "Local registry"
875611
+ hint: discovery?.skills.count && discovery.skills.count > 0 ? `${discovery.skills.count} skill file(s) are available. Use the Profiles workspace to create a profile from discovered behavior, or preview individual files with /agent-skills discover.` : "Use /agent-skills and /skills local to manage reusable Agent procedures.",
875612
+ defaultValue: discovery?.skills.count && discovery.skills.count > 0 ? `${discovery.skills.count} discovered` : "Local registry"
875113
875613
  },
875114
875614
  {
875115
875615
  kind: "status",
875116
875616
  id: "agent-local-state.routines",
875117
875617
  label: "Routines",
875118
- hint: "Use /routines for reusable local procedures. Starting a routine prints steps in the main conversation and does not spawn hidden work.",
875119
- defaultValue: "Local registry"
875618
+ hint: discovery?.routines.count && discovery.routines.count > 0 ? `${discovery.routines.count} routine file(s) are available. Use the Profiles workspace to create a profile from discovered behavior, or preview individual files with /routines discover. ${discoverySample(discovery)}` : "Use /routines for reusable local procedures. Starting a routine prints steps in the main conversation and does not spawn hidden work.",
875619
+ defaultValue: discovery?.routines.count && discovery.routines.count > 0 ? `${discovery.routines.count} discovered` : "Local registry"
875120
875620
  }
875121
875621
  ]
875122
875622
  };
@@ -875265,7 +875765,7 @@ function buildOnboardingWizardSteps(controller) {
875265
875765
  buildCommunicationStep(),
875266
875766
  buildToolsStep(),
875267
875767
  buildAgentKnowledgeStep(),
875268
- buildLocalStateStep(),
875768
+ buildLocalStateStep(controller.runtimeSnapshot?.localBehaviorDiscovery),
875269
875769
  buildAutomationStep(),
875270
875770
  buildVoiceMediaStep(),
875271
875771
  buildDelegationPolicyStep(),
@@ -877778,7 +878278,7 @@ function handleProfilePickerToken(state4, token) {
877778
878278
  }
877779
878279
 
877780
878280
  // src/input/handler-picker-routes.ts
877781
- import { readFileSync as readFileSync86 } from "fs";
878281
+ import { readFileSync as readFileSync87 } from "fs";
877782
878282
 
877783
878283
  // src/renderer/model-picker-overlay.ts
877784
878284
  var MODEL_PICKER_CHROME_LINES = 7;
@@ -878070,7 +878570,7 @@ function handleFilePickerToken(state4, token) {
878070
878570
  throw new Error("working directory is unavailable");
878071
878571
  }
878072
878572
  const resolvedPath3 = resolveAndValidatePath(selected, projectRoot);
878073
- const data = readFileSync86(resolvedPath3);
878573
+ const data = readFileSync87(resolvedPath3);
878074
878574
  const base644 = data.toString("base64");
878075
878575
  const mediaType = state4.mediaTypeFromExt(ext);
878076
878576
  const filename = selected.split("/").pop() ?? selected;
@@ -881570,6 +882070,29 @@ function setupChecklistLines(snapshot2) {
881570
882070
  }
881571
882071
  return lines;
881572
882072
  }
882073
+ function discoverySummaryLine(label, summary, command8) {
882074
+ if (summary.count === 0)
882075
+ return [];
882076
+ const names2 = summary.names.length > 0 ? ` ${summary.names.join(", ")}${summary.count > summary.names.length ? `, +${summary.count - summary.names.length} more` : ""}.` : "";
882077
+ return [
882078
+ { text: `${label}: ${summary.count} discovered; project ${summary.projectLocalCount}; global ${summary.globalCount}.`, fg: FULLSCREEN_PALETTE.info, bold: true },
882079
+ { text: ` ${command8} to preview, then use the import form after review.${names2}`, fg: FULLSCREEN_PALETTE.muted }
882080
+ ];
882081
+ }
882082
+ function behaviorDiscoveryLines(snapshot2) {
882083
+ const lines = [
882084
+ ...discoverySummaryLine("Discovered personas", snapshot2.discoveredBehavior.personas, "/personas discover"),
882085
+ ...discoverySummaryLine("Discovered skills", snapshot2.discoveredBehavior.skills, "/agent-skills discover"),
882086
+ ...discoverySummaryLine("Discovered routines", snapshot2.discoveredBehavior.routines, "/routines discover")
882087
+ ];
882088
+ if (lines.length === 0)
882089
+ return [];
882090
+ return [
882091
+ { text: "" },
882092
+ { text: "Discovered Behavior Files", fg: FULLSCREEN_PALETTE.title, bold: true },
882093
+ ...lines
882094
+ ];
882095
+ }
881573
882096
  function localLibraryLines(title, items, emptyText, selectedId) {
881574
882097
  const lines = [
881575
882098
  { text: title, fg: FULLSCREEN_PALETTE.title, bold: true }
@@ -881650,7 +882173,7 @@ function snapshotLines(workspace, category, snapshot2) {
881650
882173
  if (category.id === "home") {
881651
882174
  base2.push({ text: `Chat route: ${snapshot2.provider} / ${snapshot2.modelDisplayName}`, fg: FULLSCREEN_PALETTE.info }, { text: `Session: ${snapshot2.sessionId}`, fg: FULLSCREEN_PALETTE.muted }, { text: `Policy: ${snapshot2.executionPolicy}; WRFC ${snapshot2.wrfcPolicy}`, fg: FULLSCREEN_PALETTE.good });
881652
882175
  } else if (category.id === "setup") {
881653
- base2.push({ text: `Connection: ${snapshot2.runtimeBaseUrl}`, fg: FULLSCREEN_PALETTE.info }, { text: "Agent role: interactive operator TUI; setup changes here are Agent-local.", fg: FULLSCREEN_PALETTE.good }, ...setupChecklistLines(snapshot2), { text: "" }, { text: `Workspace: ${snapshot2.workingDirectory}`, fg: FULLSCREEN_PALETTE.muted }, { text: `Home: ${snapshot2.homeDirectory}`, fg: FULLSCREEN_PALETTE.muted });
882176
+ base2.push({ text: `Connection: ${snapshot2.runtimeBaseUrl}`, fg: FULLSCREEN_PALETTE.info }, { text: "Agent role: interactive operator TUI; setup changes here are Agent-local.", fg: FULLSCREEN_PALETTE.good }, ...setupChecklistLines(snapshot2), ...behaviorDiscoveryLines(snapshot2), { text: "" }, { text: `Workspace: ${snapshot2.workingDirectory}`, fg: FULLSCREEN_PALETTE.muted }, { text: `Home: ${snapshot2.homeDirectory}`, fg: FULLSCREEN_PALETTE.muted });
881654
882177
  } else if (category.id === "channels") {
881655
882178
  const enabledCount = snapshot2.channels.filter((channel) => channel.enabled).length;
881656
882179
  const readyCount = snapshot2.channels.filter((channel) => channel.ready).length;
@@ -883512,7 +884035,7 @@ function wireShellUiOpeners(options) {
883512
884035
 
883513
884036
  // src/cli/entrypoint.ts
883514
884037
  import { existsSync as existsSync85 } from "fs";
883515
- import { join as join101 } from "path";
884038
+ import { join as join102 } from "path";
883516
884039
  // src/cli/parser.ts
883517
884040
  var COMMAND_ALIASES = {
883518
884041
  run: "run",
@@ -883876,14 +884399,14 @@ function parseGoodVibesCli(argv, binary2 = "goodvibes-agent") {
883876
884399
  };
883877
884400
  }
883878
884401
  // src/cli/help.ts
883879
- import { existsSync as existsSync79, readFileSync as readFileSync87 } from "fs";
883880
- import { dirname as dirname63, join as join94 } from "path";
884402
+ import { existsSync as existsSync79, readFileSync as readFileSync88 } from "fs";
884403
+ import { dirname as dirname63, join as join95 } from "path";
883881
884404
  import { fileURLToPath as fileURLToPath4 } from "url";
883882
884405
  function readJsonVersion(path7) {
883883
884406
  try {
883884
884407
  if (!existsSync79(path7))
883885
884408
  return null;
883886
- const parsed = JSON.parse(readFileSync87(path7, "utf-8"));
884409
+ const parsed = JSON.parse(readFileSync88(path7, "utf-8"));
883887
884410
  return typeof parsed.version === "string" ? parsed.version : null;
883888
884411
  } catch {
883889
884412
  return null;
@@ -883891,7 +884414,7 @@ function readJsonVersion(path7) {
883891
884414
  }
883892
884415
  function getPackageVersion() {
883893
884416
  const here = dirname63(fileURLToPath4(import.meta.url));
883894
- return readJsonVersion(join94(here, "..", "..", "package.json")) ?? VERSION;
884417
+ return readJsonVersion(join95(here, "..", "..", "package.json")) ?? VERSION;
883895
884418
  }
883896
884419
  function renderGoodVibesVersion(binary2 = "goodvibes-agent") {
883897
884420
  return `${binary2} ${getPackageVersion()}`;
@@ -884023,9 +884546,9 @@ var COMMAND_HELP = {
884023
884546
  examples: ["providers", "providers inspect openai-subscriber", "providers use openai openai:gpt-5.4"]
884024
884547
  },
884025
884548
  profiles: {
884026
- usage: ["profiles list", "profiles templates", "profiles templates export <id> <path> --yes", "profiles templates import <path> --yes", "profiles show <name>", "profiles create <name> [--template <id>] --yes", "profiles delete <name> --yes", "--agent-profile <name>"],
884549
+ usage: ["profiles list", "profiles templates", "profiles templates from-discovered <id> --yes", "profiles create-from-discovered <name> --yes", "profiles templates export <id> <path> --yes", "profiles templates import <path> --yes", "profiles show <name>", "profiles create <name> [--template <id>] --yes", "profiles delete <name> --yes", "--agent-profile <name>"],
884027
884550
  summary: "Create and inspect isolated Agent profile homes, with starter templates for household, research, travel, operations, personal productivity, and local imported starters. A profile changes Agent-local config, sessions, memory, personas, skills, routines, and setup paths without changing connected GoodVibes services.",
884028
- examples: ["profiles templates", "profiles templates export research ./research-starter.json --yes", "profiles templates import ./research-starter.json --yes", "profiles create household --template household --yes", "--agent-profile household status"]
884551
+ examples: ["profiles templates", "profiles create-from-discovered research-desk --yes", "profiles templates from-discovered research-desk --yes", "profiles templates export research ./research-starter.json --yes", "profiles templates import ./research-starter.json --yes", "profiles create household --template household --yes", "--agent-profile household status"]
884029
884552
  },
884030
884553
  personas: {
884031
884554
  usage: [
@@ -884631,8 +885154,8 @@ function renderOnboardingCliStatus(options) {
884631
885154
  `);
884632
885155
  }
884633
885156
  // src/cli/external-runtime.ts
884634
- import { existsSync as existsSync80, readFileSync as readFileSync88 } from "fs";
884635
- import { join as join95 } from "path";
885157
+ import { existsSync as existsSync80, readFileSync as readFileSync89 } from "fs";
885158
+ import { join as join96 } from "path";
884636
885159
  function isRecord29(value) {
884637
885160
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
884638
885161
  }
@@ -884646,11 +885169,11 @@ function resolveBaseUrl2(configManager) {
884646
885169
  return `http://${host}:${Number.isFinite(port) ? port : 3421}`;
884647
885170
  }
884648
885171
  function readOperatorToken(homeDirectory) {
884649
- const path7 = join95(homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
885172
+ const path7 = join96(homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
884650
885173
  if (!existsSync80(path7))
884651
885174
  return { token: null, path: path7 };
884652
885175
  try {
884653
- const parsed = JSON.parse(readFileSync88(path7, "utf-8"));
885176
+ const parsed = JSON.parse(readFileSync89(path7, "utf-8"));
884654
885177
  const token = isRecord29(parsed) && typeof parsed.token === "string" ? parsed.token : null;
884655
885178
  return { token, path: path7 };
884656
885179
  } catch {
@@ -885023,8 +885546,8 @@ function applyRuntimeCommandEndpointFlagOverrides(configManager, command8, flags
885023
885546
  return [];
885024
885547
  }
885025
885548
  // src/cli/bundle-command.ts
885026
- import { existsSync as existsSync82, mkdirSync as mkdirSync65, readFileSync as readFileSync89, writeFileSync as writeFileSync56 } from "fs";
885027
- import { dirname as dirname64, join as join97 } from "path";
885549
+ import { existsSync as existsSync82, mkdirSync as mkdirSync65, readFileSync as readFileSync90, writeFileSync as writeFileSync56 } from "fs";
885550
+ import { dirname as dirname64, join as join98 } from "path";
885028
885551
 
885029
885552
  // src/cli/provider-classification.ts
885030
885553
  var SUBSCRIPTION_PROVIDERS = new Set([
@@ -885115,7 +885638,7 @@ function classifyProviderSetup(input) {
885115
885638
  // src/cli/service-posture.ts
885116
885639
  import { closeSync as closeSync4, existsSync as existsSync81, openSync as openSync4, readSync as readSync2, statSync as statSync21 } from "fs";
885117
885640
  import net3 from "net";
885118
- import { isAbsolute as isAbsolute13, join as join96 } from "path";
885641
+ import { isAbsolute as isAbsolute13, join as join97 } from "path";
885119
885642
 
885120
885643
  // src/cli/redaction.ts
885121
885644
  var REDACTED_VALUE = "<redacted>";
@@ -885285,7 +885808,7 @@ function resolveConfiguredLogPath(runtime3) {
885285
885808
  const trimmed2 = value.trim();
885286
885809
  if (!trimmed2)
885287
885810
  return;
885288
- return isAbsolute13(trimmed2) ? trimmed2 : join96(runtime3.homeDirectory, trimmed2);
885811
+ return isAbsolute13(trimmed2) ? trimmed2 : join97(runtime3.homeDirectory, trimmed2);
885289
885812
  }
885290
885813
  function createExternalDaemonLifecycle(logPath) {
885291
885814
  return {
@@ -885371,7 +885894,7 @@ function getNestedValue(source, key) {
885371
885894
  }
885372
885895
  function readJsonFile2(path7) {
885373
885896
  try {
885374
- return { ok: true, value: JSON.parse(readFileSync89(path7, "utf-8")) };
885897
+ return { ok: true, value: JSON.parse(readFileSync90(path7, "utf-8")) };
885375
885898
  } catch (error51) {
885376
885899
  return { ok: false, error: error51 instanceof Error ? error51.message : String(error51) };
885377
885900
  }
@@ -885394,7 +885917,7 @@ function readAuthPosture(runtime3) {
885394
885917
  });
885395
885918
  const userStorePath = shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-users.json");
885396
885919
  const bootstrapCredentialPath = shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-bootstrap.txt");
885397
- const operatorTokenPath = join97(runtime3.homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
885920
+ const operatorTokenPath = join98(runtime3.homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
885398
885921
  return {
885399
885922
  userStorePath,
885400
885923
  userStorePresent: existsSync82(userStorePath),
@@ -885554,7 +886077,7 @@ async function handleBundleCommand(runtime3) {
885554
886077
  }
885555
886078
  // src/cli/management.ts
885556
886079
  import { existsSync as existsSync84 } from "fs";
885557
- import { join as join100 } from "path";
886080
+ import { join as join101 } from "path";
885558
886081
  import { spawn as spawn5 } from "child_process";
885559
886082
  import { networkInterfaces as networkInterfaces4 } from "os";
885560
886083
 
@@ -885581,7 +886104,7 @@ function formatProviderAuthRoute(route) {
885581
886104
 
885582
886105
  // src/cli/management-commands.ts
885583
886106
  import { mkdirSync as mkdirSync66, writeFileSync as writeFileSync57 } from "fs";
885584
- import { dirname as dirname65, join as join98 } from "path";
886107
+ import { dirname as dirname65, join as join99 } from "path";
885585
886108
  init_config8();
885586
886109
  init_config8();
885587
886110
  init_config8();
@@ -885898,7 +886421,7 @@ async function handleTasks(runtime3) {
885898
886421
  });
885899
886422
  }
885900
886423
  async function renderPairing(runtime3) {
885901
- const daemonHomeDir = join98(runtime3.homeDirectory, ".goodvibes", "daemon");
886424
+ const daemonHomeDir = join99(runtime3.homeDirectory, ".goodvibes", "daemon");
885902
886425
  const tokenRecord = getOrCreateCompanionToken(GOODVIBES_AGENT_PAIRING_SURFACE, { daemonHomeDir });
885903
886426
  const binding = resolveRuntimeEndpointBinding(runtime3.configManager, "controlPlane");
885904
886427
  const daemonUrl = `http://${urlHostForBindHost2(binding.host)}:${binding.port}`;
@@ -886436,8 +886959,8 @@ var DELEGATION_METHOD = {
886436
886959
  };
886437
886960
 
886438
886961
  // src/cli/agent-knowledge-runtime.ts
886439
- import { existsSync as existsSync83, readFileSync as readFileSync90 } from "fs";
886440
- import { join as join99 } from "path";
886962
+ import { existsSync as existsSync83, readFileSync as readFileSync91 } from "fs";
886963
+ import { join as join100 } from "path";
886441
886964
 
886442
886965
  // node_modules/@pellux/goodvibes-sdk/dist/browser-scoped.js
886443
886966
  init_dist();
@@ -886803,11 +887326,11 @@ function resolveDaemonConnection(runtime3) {
886803
887326
  const host = String(runtime3.configManager.get("controlPlane.host") ?? "127.0.0.1");
886804
887327
  const port = Number(runtime3.configManager.get("controlPlane.port") ?? 3421);
886805
887328
  const baseUrl = `http://${host}:${Number.isFinite(port) ? port : 3421}`;
886806
- const tokenPath = join99(runtime3.homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
887329
+ const tokenPath = join100(runtime3.homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
886807
887330
  if (!existsSync83(tokenPath))
886808
887331
  return { baseUrl, token: null, tokenPath };
886809
887332
  try {
886810
- const parsed = JSON.parse(readFileSync90(tokenPath, "utf-8"));
887333
+ const parsed = JSON.parse(readFileSync91(tokenPath, "utf-8"));
886811
887334
  const token = isRecord31(parsed) && typeof parsed.token === "string" ? parsed.token : null;
886812
887335
  return { baseUrl, token, tokenPath };
886813
887336
  } catch {
@@ -888135,7 +888658,7 @@ Run goodvibes-agent skills discover to inspect available skill files.`, 1);
888135
888658
  }
888136
888659
 
888137
888660
  // src/cli/memory-command.ts
888138
- import { mkdirSync as mkdirSync67, readFileSync as readFileSync91, writeFileSync as writeFileSync58 } from "fs";
888661
+ import { mkdirSync as mkdirSync67, readFileSync as readFileSync92, writeFileSync as writeFileSync58 } from "fs";
888139
888662
  import { dirname as dirname66, resolve as resolve40 } from "path";
888140
888663
  init_state3();
888141
888664
  var VALID_CLASSES2 = ["decision", "constraint", "incident", "pattern", "fact", "risk", "runbook", "architecture", "ownership"];
@@ -888415,7 +888938,7 @@ function isMemoryBundle(value) {
888415
888938
  return value.schemaVersion === "v1" && typeof value.exportedAt === "number" && (value.scope === "all" || typeof value.scope === "string" && isMemoryScope2(value.scope)) && typeof value.recordCount === "number" && typeof value.linkCount === "number" && Array.isArray(value.records) && value.records.every(isMemoryRecord) && Array.isArray(value.links) && value.links.every(isMemoryLink);
888416
888939
  }
888417
888940
  function readBundle(path7) {
888418
- const parsed = JSON.parse(readFileSync91(path7, "utf-8"));
888941
+ const parsed = JSON.parse(readFileSync92(path7, "utf-8"));
888419
888942
  if (!isMemoryBundle(parsed))
888420
888943
  throw new Error("Invalid Agent memory bundle.");
888421
888944
  for (const record2 of parsed.records) {
@@ -888738,6 +889261,12 @@ function parseTemplate(args2) {
888738
889261
  return normalized;
888739
889262
  throw new Error(`Unknown Agent starter profile template: ${raw}. Use profiles templates to list starters.`);
888740
889263
  }
889264
+ function parseCsvFlag2(args2, names2) {
889265
+ const raw = flagValue2(args2, names2);
889266
+ if (!raw)
889267
+ return;
889268
+ return raw.split(",").map((entry) => entry.trim()).filter(Boolean);
889269
+ }
888741
889270
  function profileLine2(profile5) {
888742
889271
  const created = profile5.createdAt ? ` created=${profile5.createdAt}` : "";
888743
889272
  const starter = profile5.starterTemplateId ? ` starter=${profile5.starterTemplateId}` : "";
@@ -888788,6 +889317,29 @@ function renderProfilesResult(result2) {
888788
889317
  ` source: ${result2.data.template.source}`,
888789
889318
  ` use: goodvibes-agent profiles create <name> --template ${result2.data.template.id} --yes`
888790
889319
  ].join(`
889320
+ `);
889321
+ }
889322
+ if (result2.kind === "agent.profiles.template.from_discovered" && result2.data?.template) {
889323
+ return [
889324
+ `Agent starter template created from discovered behavior: ${result2.data.template.id}`,
889325
+ ` name: ${result2.data.template.name}`,
889326
+ ` persona: ${result2.data.template.personaName}`,
889327
+ ` skills: ${result2.data.template.skillNames.join(", ")}`,
889328
+ ` routines: ${result2.data.template.routineNames.join(", ")}`,
889329
+ ` use: goodvibes-agent profiles create <name> --template ${result2.data.template.id} --yes`
889330
+ ].join(`
889331
+ `);
889332
+ }
889333
+ if (result2.kind === "agent.profiles.create_from_discovered" && result2.data?.profile && result2.data.template) {
889334
+ return [
889335
+ `Agent profile created from discovered behavior: ${result2.data.profile.id}`,
889336
+ ` home: ${result2.data.profile.homeDirectory}`,
889337
+ ` starter: ${result2.data.template.id}`,
889338
+ ` persona: ${result2.data.template.personaName}`,
889339
+ ` skills: ${result2.data.template.skillNames.join(", ")}`,
889340
+ ` routines: ${result2.data.template.routineNames.join(", ")}`,
889341
+ ` launch: ${result2.data.nextCommand ?? `goodvibes-agent --agent-profile ${result2.data.profile.id}`}`
889342
+ ].join(`
888791
889343
  `);
888792
889344
  }
888793
889345
  const profile5 = result2.data?.profile;
@@ -888831,6 +889383,51 @@ async function handleProfilesCommand(runtime3) {
888831
889383
  }
888832
889384
  if (sub === "templates" || sub === "starters") {
888833
889385
  const [templateAction, templateId, templatePath] = values2;
889386
+ if (templateAction === "from-discovered" || templateAction === "import-discovered") {
889387
+ if (!templateId) {
889388
+ const result5 = {
889389
+ ok: false,
889390
+ kind: "agent.profiles.error",
889391
+ error: "Usage: goodvibes-agent profiles templates from-discovered <id> [--name <name>] [--description <summary>] [--persona <name>] [--skills all|name,name] [--routines all|name,name] [--replace] --yes"
889392
+ };
889393
+ return {
889394
+ output: renderProfilesOutput(result5, runtime3.cli.flags.outputFormat),
889395
+ exitCode: 2
889396
+ };
889397
+ }
889398
+ if (!hasYes(rawRest)) {
889399
+ const result5 = {
889400
+ ok: false,
889401
+ kind: "agent.profiles.error",
889402
+ error: `Refusing to create Agent starter template ${templateId} from discovered behavior without --yes.`
889403
+ };
889404
+ return {
889405
+ output: renderProfilesOutput(result5, runtime3.cli.flags.outputFormat),
889406
+ exitCode: 2
889407
+ };
889408
+ }
889409
+ const template = await createAgentRuntimeProfileTemplateFromDiscovered({
889410
+ homeDirectory: runtime3.homeDirectory,
889411
+ workingDirectory: runtime3.workingDirectory
889412
+ }, {
889413
+ id: templateId,
889414
+ name: flagValue2(rawRest, ["--name"]) ?? undefined,
889415
+ description: flagValue2(rawRest, ["--description"]) ?? undefined,
889416
+ persona: flagValue2(rawRest, ["--persona"]) ?? undefined,
889417
+ skills: parseCsvFlag2(rawRest, ["--skills"]),
889418
+ routines: parseCsvFlag2(rawRest, ["--routines"]),
889419
+ replace: hasYes(rawRest) && rawRest.includes("--replace")
889420
+ });
889421
+ const result4 = {
889422
+ ok: true,
889423
+ kind: "agent.profiles.template.from_discovered",
889424
+ data: { template }
889425
+ };
889426
+ return {
889427
+ output: renderProfilesOutput(result4, runtime3.cli.flags.outputFormat),
889428
+ exitCode: 0
889429
+ };
889430
+ }
888834
889431
  if (templateAction === "export") {
888835
889432
  if (!templateId || !templatePath) {
888836
889433
  const result5 = {
@@ -888977,6 +889574,58 @@ async function handleProfilesCommand(runtime3) {
888977
889574
  exitCode: 0
888978
889575
  };
888979
889576
  }
889577
+ if (sub === "create-from-discovered" || sub === "create-discovered") {
889578
+ const name51 = values2[0];
889579
+ if (!name51) {
889580
+ const result4 = {
889581
+ ok: false,
889582
+ kind: "agent.profiles.error",
889583
+ error: "Usage: goodvibes-agent profiles create-from-discovered <name> [--template-id <id>] [--profile-name <display>] [--description <summary>] [--persona <name>] [--skills all|name,name] [--routines all|name,name] [--replace] --yes"
889584
+ };
889585
+ return {
889586
+ output: renderProfilesOutput(result4, runtime3.cli.flags.outputFormat),
889587
+ exitCode: 2
889588
+ };
889589
+ }
889590
+ if (!hasYes(rawRest)) {
889591
+ const result4 = {
889592
+ ok: false,
889593
+ kind: "agent.profiles.error",
889594
+ error: `Refusing to create Agent profile ${name51} from discovered behavior without --yes.`
889595
+ };
889596
+ return {
889597
+ output: renderProfilesOutput(result4, runtime3.cli.flags.outputFormat),
889598
+ exitCode: 2
889599
+ };
889600
+ }
889601
+ const created = await createAgentRuntimeProfileFromDiscovered({
889602
+ homeDirectory: runtime3.homeDirectory,
889603
+ workingDirectory: runtime3.workingDirectory
889604
+ }, {
889605
+ profileName: name51,
889606
+ templateId: flagValue2(rawRest, ["--template-id", "--starter-id"]) ?? undefined,
889607
+ name: flagValue2(rawRest, ["--profile-name", "--name"]) ?? undefined,
889608
+ description: flagValue2(rawRest, ["--description"]) ?? undefined,
889609
+ persona: flagValue2(rawRest, ["--persona"]) ?? undefined,
889610
+ skills: parseCsvFlag2(rawRest, ["--skills"]),
889611
+ routines: parseCsvFlag2(rawRest, ["--routines"]),
889612
+ replace: rawRest.includes("--replace")
889613
+ });
889614
+ const result3 = {
889615
+ ok: true,
889616
+ kind: "agent.profiles.create_from_discovered",
889617
+ data: {
889618
+ profile: created.profile,
889619
+ appliedTemplate: created.profile.starterTemplateApplication,
889620
+ template: created.template,
889621
+ nextCommand: `goodvibes-agent --agent-profile ${created.profile.id}`
889622
+ }
889623
+ };
889624
+ return {
889625
+ output: renderProfilesOutput(result3, runtime3.cli.flags.outputFormat),
889626
+ exitCode: 0
889627
+ };
889628
+ }
888980
889629
  if (sub === "delete" || sub === "remove") {
888981
889630
  const name51 = values2[0];
888982
889631
  if (!name51) {
@@ -889498,7 +890147,7 @@ function readAuthPaths(runtime3) {
889498
890147
  });
889499
890148
  const userStorePath = shellPaths3.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-users.json");
889500
890149
  const bootstrapCredentialPath = shellPaths3.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-bootstrap.txt");
889501
- const operatorTokenPath = join100(runtime3.homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
890150
+ const operatorTokenPath = join101(runtime3.homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
889502
890151
  return {
889503
890152
  userStorePath,
889504
890153
  userStorePresent: existsSync84(userStorePath),
@@ -890013,7 +890662,7 @@ async function prepareShellCliRuntime(argv, roots, binary2 = "goodvibes-agent")
890013
890662
  workingDirectory: bootstrapWorkingDir,
890014
890663
  homeDirectory: bootstrapHomeDirectory
890015
890664
  } = ownership;
890016
- configureActivityLogger(join101(bootstrapWorkingDir, ".goodvibes", "logs"));
890665
+ configureActivityLogger(join102(bootstrapWorkingDir, ".goodvibes", "logs"));
890017
890666
  const configManager = new ConfigManager({
890018
890667
  workingDir: bootstrapWorkingDir,
890019
890668
  homeDir: bootstrapHomeDirectory,
@@ -890064,7 +890713,7 @@ async function prepareShellCliRuntime(argv, roots, binary2 = "goodvibes-agent")
890064
890713
  });
890065
890714
  const userStorePath = shellPaths3.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-users.json");
890066
890715
  const bootstrapCredentialPath = shellPaths3.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-bootstrap.txt");
890067
- const operatorTokenPath = join101(bootstrapHomeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
890716
+ const operatorTokenPath = join102(bootstrapHomeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
890068
890717
  const onboardingMarkers = readOnboardingCheckMarkers(shellPaths3);
890069
890718
  const service = await buildCliServicePosture({
890070
890719
  configManager,
@@ -890202,7 +890851,7 @@ function applyInitialTuiCliState(options) {
890202
890851
 
890203
890852
  // src/audio/player.ts
890204
890853
  import { accessSync, constants as constants4 } from "fs";
890205
- import { delimiter, join as join102 } from "path";
890854
+ import { delimiter, join as join103 } from "path";
890206
890855
  import { spawn as spawn6 } from "child_process";
890207
890856
 
890208
890857
  class LocalStreamingAudioPlayer {
@@ -890299,7 +890948,7 @@ function findExecutable(name51, env2) {
890299
890948
  if (!dir)
890300
890949
  continue;
890301
890950
  for (const ext of extensions14) {
890302
- const candidate = join102(dir, `${name51}${ext}`);
890951
+ const candidate = join103(dir, `${name51}${ext}`);
890303
890952
  try {
890304
890953
  accessSync(candidate, constants4.X_OK);
890305
890954
  return candidate;