@pellux/goodvibes-agent 0.1.113 → 0.1.114

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.113";
816526
+ var _version = "0.1.114";
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 join89 } from "path";
841977
+ import { join as join91 } from "path";
841978
841978
 
841979
841979
  // src/input/command-registry.ts
841980
841980
  class CommandRegistry {
@@ -852664,6 +852664,100 @@ function registerDelegationRuntimeCommands(registry5) {
852664
852664
  });
852665
852665
  }
852666
852666
 
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
+
852667
852761
  // src/input/commands/personas-runtime.ts
852668
852762
  function parsePersonaArgs(args2) {
852669
852763
  const flags2 = new Map;
@@ -852737,6 +852831,84 @@ function renderPersona(persona, activePersonaId) {
852737
852831
  ].filter(Boolean).join(`
852738
852832
  `);
852739
852833
  }
852834
+ function summarizeDiscoveredPersona(persona) {
852835
+ const description = persona.description ? ` - ${persona.description}` : "";
852836
+ return ` ${persona.name} ${persona.origin}${description}
852837
+ path: ${persona.path}`;
852838
+ }
852839
+ function renderDiscoveredPersonas(personas) {
852840
+ if (personas.length === 0) {
852841
+ return [
852842
+ "Discovered Agent persona files",
852843
+ " No persona markdown files found in project/global Agent persona folders.",
852844
+ " Search roots: .goodvibes/personas, .goodvibes/agent/personas, .goodvibes/agents, ~/.goodvibes/personas, ~/.goodvibes/agent/personas, ~/.goodvibes/agents"
852845
+ ].join(`
852846
+ `);
852847
+ }
852848
+ return [
852849
+ `Discovered Agent persona files (${personas.length})`,
852850
+ ...personas.map(summarizeDiscoveredPersona),
852851
+ "",
852852
+ "Import one with: /personas import-discovered <name> --yes"
852853
+ ].join(`
852854
+ `);
852855
+ }
852856
+ function discoveredPersonaLookupValues(persona) {
852857
+ const slug = persona.name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
852858
+ const basename5 = persona.path.split(/[\\/]/).pop()?.replace(/\.md$/i, "") ?? "";
852859
+ return [persona.name, slug, persona.path, basename5].map((value) => value.trim().toLowerCase()).filter(Boolean);
852860
+ }
852861
+ function findDiscoveredPersona(personas, idOrName) {
852862
+ const lookup = idOrName.trim().toLowerCase();
852863
+ if (!lookup)
852864
+ return null;
852865
+ return personas.find((persona) => discoveredPersonaLookupValues(persona).includes(lookup)) ?? null;
852866
+ }
852867
+ function frontmatterList(persona, key) {
852868
+ const value = persona.frontmatter[key];
852869
+ if (!value)
852870
+ return [];
852871
+ return splitList(value);
852872
+ }
852873
+ async function importDiscoveredPersona(args2, ctx, personaRegistry) {
852874
+ const parsed = parsePersonaArgs(args2);
852875
+ const name51 = parsed.rest.join(" ").trim();
852876
+ if (!name51) {
852877
+ ctx.print("Usage: /personas import-discovered <name> [--use] --yes");
852878
+ return;
852879
+ }
852880
+ const discovered = findDiscoveredPersona(await discoverPersonas(requireShellPaths(ctx)), name51);
852881
+ if (!discovered) {
852882
+ ctx.print(`Unknown discovered Agent persona: ${name51}
852883
+ Run /personas discover to inspect available persona files.`);
852884
+ return;
852885
+ }
852886
+ if (!parsed.yes) {
852887
+ ctx.print([
852888
+ "Agent persona import preview",
852889
+ ` name: ${discovered.name}`,
852890
+ ` origin: ${discovered.origin}`,
852891
+ ` path: ${discovered.path}`,
852892
+ ` description: ${discovered.description || "(none)"}`,
852893
+ ` body characters: ${discovered.body.length}`,
852894
+ " next: rerun with --yes to import into the Agent-local persona registry"
852895
+ ].join(`
852896
+ `));
852897
+ return;
852898
+ }
852899
+ const persona = personaRegistry.create({
852900
+ name: discovered.name,
852901
+ description: discovered.description || `Imported persona from ${discovered.origin} markdown file.`,
852902
+ body: discovered.body,
852903
+ tags: frontmatterList(discovered, "tags"),
852904
+ triggers: frontmatterList(discovered, "triggers"),
852905
+ source: "imported",
852906
+ provenance: `discovered:${discovered.origin}:${discovered.path}`
852907
+ });
852908
+ if (parsed.flags.get("use") === "true")
852909
+ personaRegistry.setActive(persona.id);
852910
+ ctx.print(`Imported Agent persona ${persona.id}: ${persona.name}${parsed.flags.get("use") === "true" ? " (active)" : ""}`);
852911
+ }
852740
852912
  function requiredFlag(flags2, key) {
852741
852913
  const value = flags2.get(key)?.trim();
852742
852914
  if (!value)
@@ -852751,7 +852923,7 @@ function registerPersonasRuntimeCommands(registry5) {
852751
852923
  name: "personas",
852752
852924
  aliases: ["persona"],
852753
852925
  description: "Manage local GoodVibes Agent personas",
852754
- usage: "[list|search <query>|show <id>|create --name <name> --description <summary> --body <instructions>|update <id> [--name ...] [--description ...] [--body ...]|use <id>|active|clear|review <id>|stale <id> <reason...>|delete <id> --yes]",
852926
+ usage: "[list|discover|import-discovered <name> --yes|search <query>|show <id>|create --name <name> --description <summary> --body <instructions>|update <id> [--name ...] [--description ...] [--body ...]|use <id>|active|clear|review <id>|stale <id> <reason...>|delete <id> --yes]",
852755
852927
  async handler(args2, ctx) {
852756
852928
  const sub = (args2[0] ?? "list").toLowerCase();
852757
852929
  const registryStore = registryFromContext(ctx);
@@ -852760,6 +852932,14 @@ function registerPersonasRuntimeCommands(registry5) {
852760
852932
  ctx.print(renderList("Agent Personas", registryStore, registryStore.list()));
852761
852933
  return;
852762
852934
  }
852935
+ if (sub === "discover" || sub === "discovered") {
852936
+ ctx.print(renderDiscoveredPersonas(await discoverPersonas(requireShellPaths(ctx))));
852937
+ return;
852938
+ }
852939
+ if (sub === "import-discovered" || sub === "import-persona") {
852940
+ await importDiscoveredPersona(args2.slice(1), ctx, registryStore);
852941
+ return;
852942
+ }
852763
852943
  if (sub === "search") {
852764
852944
  const query2 = args2.slice(1).join(" ").trim();
852765
852945
  ctx.print(renderList(query2 ? `Agent Personas matching "${query2}"` : "Agent Personas", registryStore, registryStore.search(query2)));
@@ -852864,7 +853044,7 @@ function registerPersonasRuntimeCommands(registry5) {
852864
853044
  ctx.print(`Deleted Agent persona ${removed.id}: ${removed.name}`);
852865
853045
  return;
852866
853046
  }
852867
- ctx.print("Usage: /personas [list|search <query>|show <id>|create|update|use|active|clear|review|stale|delete]");
853047
+ ctx.print("Usage: /personas [list|discover|import-discovered|search <query>|show <id>|create|update|use|active|clear|review|stale|delete]");
852868
853048
  } catch (error51) {
852869
853049
  printError2(ctx, error51);
852870
853050
  }
@@ -852975,7 +853155,7 @@ function findDiscoveredSkill(skills, idOrName) {
852975
853155
  return null;
852976
853156
  return skills.find((skill) => discoveredSkillLookupValues(skill).includes(lookup)) ?? null;
852977
853157
  }
852978
- function frontmatterList(skill, key) {
853158
+ function frontmatterList2(skill, key) {
852979
853159
  const value = skill.frontmatter[key];
852980
853160
  if (!value)
852981
853161
  return [];
@@ -853011,8 +853191,8 @@ Run /agent-skills discover to inspect available skill files.`);
853011
853191
  name: discovered.name,
853012
853192
  description: discovered.description || `Imported skill from ${discovered.origin} skill file.`,
853013
853193
  procedure: discovered.body,
853014
- triggers: frontmatterList(discovered, "triggers"),
853015
- tags: frontmatterList(discovered, "tags"),
853194
+ triggers: frontmatterList2(discovered, "triggers"),
853195
+ tags: frontmatterList2(discovered, "tags"),
853016
853196
  enabled: parsed.flags.get("enabled") === "true",
853017
853197
  source: "imported",
853018
853198
  provenance: `discovered:${discovered.origin}:${discovered.path}`
@@ -853317,6 +853497,98 @@ function registerAgentSkillsRuntimeCommands(registry5) {
853317
853497
  });
853318
853498
  }
853319
853499
 
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
+
853320
853592
  // src/input/commands/routines-runtime.ts
853321
853593
  function parseRoutineArgs(args2) {
853322
853594
  const flags2 = new Map;
@@ -853400,9 +853672,86 @@ function renderRoutine(routine) {
853400
853672
  ].filter(Boolean).join(`
853401
853673
  `);
853402
853674
  }
853675
+ function summarizeDiscoveredRoutine(routine) {
853676
+ const description = routine.description ? ` - ${routine.description}` : "";
853677
+ return ` ${routine.name} ${routine.origin}${description}
853678
+ path: ${routine.path}`;
853679
+ }
853680
+ function renderDiscoveredRoutines(routines) {
853681
+ if (routines.length === 0) {
853682
+ return [
853683
+ "Discovered Agent routine files",
853684
+ " No routine markdown files found in project/global Agent routine folders.",
853685
+ " Search roots: .goodvibes/routines, .goodvibes/agent/routines, ~/.goodvibes/routines, ~/.goodvibes/agent/routines"
853686
+ ].join(`
853687
+ `);
853688
+ }
853689
+ return [
853690
+ `Discovered Agent routine files (${routines.length})`,
853691
+ ...routines.map(summarizeDiscoveredRoutine),
853692
+ "",
853693
+ "Import one with: /routines import-discovered <name> --yes"
853694
+ ].join(`
853695
+ `);
853696
+ }
853697
+ function discoveredRoutineLookupValues(routine) {
853698
+ const slug = routine.name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
853699
+ const basename5 = routine.path.split(/[\\/]/).pop()?.replace(/\.md$/i, "") ?? "";
853700
+ return [routine.name, slug, routine.path, basename5].map((value) => value.trim().toLowerCase()).filter(Boolean);
853701
+ }
853702
+ function findDiscoveredRoutine(routines, idOrName) {
853703
+ const lookup = idOrName.trim().toLowerCase();
853704
+ if (!lookup)
853705
+ return null;
853706
+ return routines.find((routine) => discoveredRoutineLookupValues(routine).includes(lookup)) ?? null;
853707
+ }
853708
+ function frontmatterList3(routine, key) {
853709
+ const value = routine.frontmatter[key];
853710
+ if (!value)
853711
+ return [];
853712
+ return splitList3(value);
853713
+ }
853403
853714
  function printError4(ctx, error51) {
853404
853715
  ctx.print(`Error: ${error51 instanceof Error ? error51.message : String(error51)}`);
853405
853716
  }
853717
+ async function importDiscoveredRoutine(args2, ctx, routineRegistry) {
853718
+ const parsed = parseRoutineArgs(args2);
853719
+ const name51 = parsed.rest.join(" ").trim();
853720
+ if (!name51) {
853721
+ ctx.print("Usage: /routines import-discovered <name> [--enabled] --yes");
853722
+ return;
853723
+ }
853724
+ const discovered = findDiscoveredRoutine(await discoverRoutines(requireShellPaths(ctx)), name51);
853725
+ if (!discovered) {
853726
+ ctx.print(`Unknown discovered Agent routine: ${name51}
853727
+ Run /routines discover to inspect available routine files.`);
853728
+ return;
853729
+ }
853730
+ if (!parsed.yes) {
853731
+ ctx.print([
853732
+ "Agent routine import preview",
853733
+ ` name: ${discovered.name}`,
853734
+ ` origin: ${discovered.origin}`,
853735
+ ` path: ${discovered.path}`,
853736
+ ` description: ${discovered.description || "(none)"}`,
853737
+ ` steps characters: ${discovered.steps.length}`,
853738
+ " next: rerun with --yes to import into the Agent-local routine registry"
853739
+ ].join(`
853740
+ `));
853741
+ return;
853742
+ }
853743
+ const routine = routineRegistry.create({
853744
+ name: discovered.name,
853745
+ description: discovered.description || `Imported routine from ${discovered.origin} markdown file.`,
853746
+ steps: discovered.steps,
853747
+ tags: frontmatterList3(discovered, "tags"),
853748
+ triggers: frontmatterList3(discovered, "triggers"),
853749
+ enabled: parsed.flags.get("enabled") === "true",
853750
+ source: "imported",
853751
+ provenance: `discovered:${discovered.origin}:${discovered.path}`
853752
+ });
853753
+ ctx.print(`Imported Agent routine ${routine.id}: ${routine.name}${routine.enabled ? " (enabled)" : ""}`);
853754
+ }
853406
853755
  async function promoteRoutine(args2, routineRegistry, ctx) {
853407
853756
  const parsed = parseRoutineSchedulePromotionArgs(args2);
853408
853757
  if (parsed.errors.length > 0) {
@@ -853444,6 +853793,14 @@ async function runRoutinesRuntimeCommand(args2, ctx) {
853444
853793
  ctx.print(renderList3("Enabled Agent Routines", routineRegistry, snapshot.enabledRoutines));
853445
853794
  return;
853446
853795
  }
853796
+ if (sub === "discover" || sub === "discovered") {
853797
+ ctx.print(renderDiscoveredRoutines(await discoverRoutines(requireShellPaths(ctx))));
853798
+ return;
853799
+ }
853800
+ if (sub === "import-discovered" || sub === "import-routine") {
853801
+ await importDiscoveredRoutine(args2.slice(1), ctx, routineRegistry);
853802
+ return;
853803
+ }
853447
853804
  if (sub === "search") {
853448
853805
  const query2 = args2.slice(1).join(" ").trim();
853449
853806
  ctx.print(renderList3(query2 ? `Agent Routines matching "${query2}"` : "Agent Routines", routineRegistry, routineRegistry.search(query2)));
@@ -853579,7 +853936,7 @@ async function runRoutinesRuntimeCommand(args2, ctx) {
853579
853936
  ctx.print(`Deleted Agent routine ${removed.id}: ${removed.name}`);
853580
853937
  return;
853581
853938
  }
853582
- ctx.print("Usage: /routines [list|enabled|search|show|receipts|reconcile|receipt|create|update|enable|disable|start|review|stale|promote|delete]");
853939
+ ctx.print("Usage: /routines [list|enabled|discover|import-discovered|search|show|receipts|reconcile|receipt|create|update|enable|disable|start|review|stale|promote|delete]");
853583
853940
  } catch (error51) {
853584
853941
  printError4(ctx, error51);
853585
853942
  }
@@ -853589,14 +853946,14 @@ function registerRoutinesRuntimeCommands(registry5) {
853589
853946
  name: "routines",
853590
853947
  aliases: ["routine"],
853591
853948
  description: "Manage local GoodVibes Agent routines",
853592
- usage: "[list|enabled|search <query>|show <id>|receipts|reconcile|receipt <id>|create --name <name> --description <summary> --steps <steps>|update <id> [--name ...] [--description ...] [--steps ...]|enable <id>|disable <id>|start <id>|review <id>|stale <id> <reason...>|promote <id> --cron <expr> [--delivery-channel slack] --yes|delete <id> --yes]",
853949
+ usage: "[list|enabled|discover|import-discovered <name> --yes|search <query>|show <id>|receipts|reconcile|receipt <id>|create --name <name> --description <summary> --steps <steps>|update <id> [--name ...] [--description ...] [--steps ...]|enable <id>|disable <id>|start <id>|review <id>|stale <id> <reason...>|promote <id> --cron <expr> [--delivery-channel slack] --yes|delete <id> --yes]",
853593
853950
  handler: runRoutinesRuntimeCommand
853594
853951
  });
853595
853952
  }
853596
853953
 
853597
853954
  // src/input/commands/channels-runtime.ts
853598
853955
  import { existsSync as existsSync72, readFileSync as readFileSync79 } from "fs";
853599
- import { join as join87 } from "path";
853956
+ import { join as join89 } from "path";
853600
853957
 
853601
853958
  // src/input/agent-workspace-channels.ts
853602
853959
  var AGENT_WORKSPACE_CHANNEL_SPECS = [
@@ -853807,7 +854164,7 @@ function resolveChannelDaemonConnection(context) {
853807
854164
  const host = typeof hostValue === "string" && hostValue.trim().length > 0 ? hostValue.trim() : "127.0.0.1";
853808
854165
  const port = typeof portValue === "number" && Number.isFinite(portValue) ? portValue : 3421;
853809
854166
  const homeDirectory = context.workspace?.shellPaths?.homeDirectory ?? process.env.HOME ?? "";
853810
- const tokenPath = join87(homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
854167
+ const tokenPath = join89(homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
853811
854168
  if (!existsSync72(tokenPath))
853812
854169
  return { baseUrl: `http://${host}:${port}`, token: null, tokenPath };
853813
854170
  try {
@@ -854903,7 +855260,7 @@ function registerBuiltinCommands(registry5) {
854903
855260
 
854904
855261
  // src/input/input-history.ts
854905
855262
  import { existsSync as existsSync73, mkdirSync as mkdirSync61, readFileSync as readFileSync80, writeFileSync as writeFileSync52 } from "fs";
854906
- import { dirname as dirname59, join as join88 } from "path";
855263
+ import { dirname as dirname59, join as join90 } from "path";
854907
855264
  class HistorySearch {
854908
855265
  getEntries;
854909
855266
  active = false;
@@ -854982,7 +855339,7 @@ function resolveHistoryPath2(options) {
854982
855339
  if (!userRoot) {
854983
855340
  throw new Error("InputHistory requires historyPath or an explicit userRoot/homeDirectory.");
854984
855341
  }
854985
- return join88(userRoot, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "input-history.json");
855342
+ return join90(userRoot, ".goodvibes", GOODVIBES_AGENT_SURFACE_ROOT, "input-history.json");
854986
855343
  }
854987
855344
 
854988
855345
  class InputHistory {
@@ -863784,7 +864141,7 @@ function createBootstrapShell(options) {
863784
864141
  hookActivityTracker: services.hookActivityTracker,
863785
864142
  hookWorkbench: services.hookWorkbench,
863786
864143
  mcpRegistry: services.mcpRegistry,
863787
- daemonHomeDir: join89(services.homeDirectory, ".goodvibes", "daemon")
864144
+ daemonHomeDir: join91(services.homeDirectory, ".goodvibes", "daemon")
863788
864145
  });
863789
864146
  services.panelManager.prewarmRegistered();
863790
864147
  const systemMessageRouter = createSystemMessageRouter(conversation, systemMessagesPanel, (kind2) => {
@@ -866199,7 +866556,7 @@ import { dirname as dirname61 } from "path";
866199
866556
  // src/runtime/onboarding/verify.ts
866200
866557
  init_config8();
866201
866558
  import { existsSync as existsSync75 } from "fs";
866202
- import { join as join90 } from "path";
866559
+ import { join as join92 } from "path";
866203
866560
  function getNow(deps) {
866204
866561
  return deps.clock?.() ?? Date.now();
866205
866562
  }
@@ -866280,7 +866637,7 @@ function verifyAuthOperation(_deps, operation) {
866280
866637
  }
866281
866638
  function verifyCreateAgentProfileOperation(deps, operation) {
866282
866639
  const resolution2 = resolveAgentRuntimeProfileHome(deps.shellPaths.homeDirectory, operation.name);
866283
- const ok3 = existsSync75(join90(resolution2.homeDirectory, "profile.json"));
866640
+ const ok3 = existsSync75(join92(resolution2.homeDirectory, "profile.json"));
866284
866641
  return {
866285
866642
  id: `agent-profile:${resolution2.id}`,
866286
866643
  status: ok3 ? "pass" : "fail",
@@ -868337,7 +868694,7 @@ class AutocompleteEngine {
868337
868694
 
868338
868695
  // src/input/file-picker.ts
868339
868696
  import { readdir as readdir6 } from "fs/promises";
868340
- import { join as join91, relative as relative15 } from "path";
868697
+ import { join as join93, relative as relative15 } from "path";
868341
868698
 
868342
868699
  class FilePickerModal {
868343
868700
  shellPaths;
@@ -868470,7 +868827,7 @@ class FilePickerModal {
868470
868827
  continue;
868471
868828
  if (entry.name === "node_modules" || entry.name === "dist")
868472
868829
  continue;
868473
- const fullPath = join91(dir, entry.name);
868830
+ const fullPath = join93(dir, entry.name);
868474
868831
  const relPath = relative15(this.shellPaths.workingDirectory, fullPath);
868475
868832
  if (entry.isDirectory()) {
868476
868833
  files.push(relPath + "/");
@@ -871900,7 +872257,7 @@ function splitCommaList(value) {
871900
872257
  return value.split(",").map((entry) => entry.trim()).filter(Boolean);
871901
872258
  }
871902
872259
  function isAgentWorkspaceBasicCommandEditorKind(kind2) {
871903
- 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 === "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";
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";
871904
872261
  }
871905
872262
  function createAgentWorkspaceBasicCommandEditor(kind2) {
871906
872263
  if (kind2 === "knowledge-bookmarks") {
@@ -872090,6 +872447,34 @@ function createAgentWorkspaceBasicCommandEditor(kind2) {
872090
872447
  ]
872091
872448
  };
872092
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
+ }
872093
872478
  return {
872094
872479
  kind: kind2,
872095
872480
  mode: "create",
@@ -872460,6 +872845,66 @@ function buildAgentWorkspaceBasicCommandEditorSubmission(editor, readField, comm
872460
872845
  }
872461
872846
  };
872462
872847
  }
872848
+ if (editor.kind === "persona-discovery-import") {
872849
+ if (!isAffirmative2(readField("confirm"))) {
872850
+ return {
872851
+ kind: "editor",
872852
+ editor: { ...editor, message: "Discovered persona import not confirmed. Type yes, then press Enter." },
872853
+ status: "Agent persona import not confirmed."
872854
+ };
872855
+ }
872856
+ const parts2 = [
872857
+ "/personas",
872858
+ "import-discovered",
872859
+ quoteSlashCommandArg(readField("name"))
872860
+ ];
872861
+ if (isAffirmative2(readField("use")))
872862
+ parts2.push("--use");
872863
+ parts2.push("--yes");
872864
+ const command9 = parts2.join(" ");
872865
+ return {
872866
+ kind: "dispatch",
872867
+ command: command9,
872868
+ status: "Opening discovered persona import.",
872869
+ actionResult: {
872870
+ kind: "dispatched",
872871
+ title: "Opening discovered persona import",
872872
+ detail: "The workspace handed a confirmed local persona import command to the shell-owned command router.",
872873
+ command: command9,
872874
+ safety: "safe"
872875
+ }
872876
+ };
872877
+ }
872878
+ if (editor.kind === "routine-discovery-import") {
872879
+ if (!isAffirmative2(readField("confirm"))) {
872880
+ return {
872881
+ kind: "editor",
872882
+ editor: { ...editor, message: "Discovered routine import not confirmed. Type yes, then press Enter." },
872883
+ status: "Agent routine import not confirmed."
872884
+ };
872885
+ }
872886
+ const parts2 = [
872887
+ "/routines",
872888
+ "import-discovered",
872889
+ quoteSlashCommandArg(readField("name"))
872890
+ ];
872891
+ if (isAffirmative2(readField("enabled")))
872892
+ parts2.push("--enabled");
872893
+ parts2.push("--yes");
872894
+ const command9 = parts2.join(" ");
872895
+ return {
872896
+ kind: "dispatch",
872897
+ command: command9,
872898
+ status: "Opening discovered routine import.",
872899
+ actionResult: {
872900
+ kind: "dispatched",
872901
+ title: "Opening discovered routine import",
872902
+ detail: "The workspace handed a confirmed local routine import command to the shell-owned command router.",
872903
+ command: command9,
872904
+ safety: "safe"
872905
+ }
872906
+ };
872907
+ }
872463
872908
  const commandParts = [
872464
872909
  "/agent-skills bundle create",
872465
872910
  "--name",
@@ -873034,6 +873479,8 @@ var AGENT_WORKSPACE_CATEGORIES = [
873034
873479
  actions: [
873035
873480
  { id: "personas-list", label: "List personas", detail: "Print the full local persona library.", command: "/personas list", kind: "command", safety: "read-only" },
873036
873481
  { id: "personas-active", label: "Show active persona", detail: "Inspect the active local persona applied to new turns.", command: "/personas active", kind: "command", safety: "read-only" },
873482
+ { id: "personas-discover", label: "Discover persona files", detail: "Scan project and global Agent persona folders for persona markdown without importing it.", command: "/personas discover", kind: "command", safety: "read-only" },
873483
+ { id: "personas-import-discovered", label: "Import discovered persona", detail: "Open an in-workspace form that imports one reviewed persona markdown file into the Agent-local persona registry after typed confirmation.", editorKind: "persona-discovery-import", kind: "editor", safety: "safe" },
873037
873484
  { id: "personas-prev", label: "Previous persona", detail: "Move the local persona selection up without changing active state.", localKind: "persona", selectionDelta: -1, kind: "local-selection", safety: "safe" },
873038
873485
  { id: "personas-next", label: "Next persona", detail: "Move the local persona selection down without changing active state.", localKind: "persona", selectionDelta: 1, kind: "local-selection", safety: "safe" },
873039
873486
  { id: "personas-create", label: "Create persona", detail: "Open an in-workspace form for a local persona that writes Agent-local state only.", editorKind: "persona", kind: "editor", safety: "safe" },
@@ -873076,6 +873523,8 @@ var AGENT_WORKSPACE_CATEGORIES = [
873076
873523
  actions: [
873077
873524
  { id: "routines-list", label: "List routines", detail: "Print the full local Agent routine library.", command: "/routines list", kind: "command", safety: "read-only" },
873078
873525
  { id: "routines-enabled", label: "Enabled routines", detail: "Show routines available for direct use.", command: "/routines enabled", kind: "command", safety: "read-only" },
873526
+ { id: "routines-discover", label: "Discover routine files", detail: "Scan project and global Agent routine folders for routine markdown without importing it.", command: "/routines discover", kind: "command", safety: "read-only" },
873527
+ { id: "routines-import-discovered", label: "Import discovered routine", detail: "Open an in-workspace form that imports one reviewed routine markdown file into the Agent-local routine registry after typed confirmation.", editorKind: "routine-discovery-import", kind: "editor", safety: "safe" },
873079
873528
  { id: "routines-prev", label: "Previous routine", detail: "Move the local routine selection up without changing enabled state.", localKind: "routine", selectionDelta: -1, kind: "local-selection", safety: "safe" },
873080
873529
  { id: "routines-next", label: "Next routine", detail: "Move the local routine selection down without changing enabled state.", localKind: "routine", selectionDelta: 1, kind: "local-selection", safety: "safe" },
873081
873530
  { id: "routines-create", label: "Create routine", detail: "Open an in-workspace form for a repeatable local workflow that writes Agent-local state only.", editorKind: "routine", kind: "editor", safety: "safe" },
@@ -883063,7 +883512,7 @@ function wireShellUiOpeners(options) {
883063
883512
 
883064
883513
  // src/cli/entrypoint.ts
883065
883514
  import { existsSync as existsSync85 } from "fs";
883066
- import { join as join99 } from "path";
883515
+ import { join as join101 } from "path";
883067
883516
  // src/cli/parser.ts
883068
883517
  var COMMAND_ALIASES = {
883069
883518
  run: "run",
@@ -883428,7 +883877,7 @@ function parseGoodVibesCli(argv, binary2 = "goodvibes-agent") {
883428
883877
  }
883429
883878
  // src/cli/help.ts
883430
883879
  import { existsSync as existsSync79, readFileSync as readFileSync87 } from "fs";
883431
- import { dirname as dirname63, join as join92 } from "path";
883880
+ import { dirname as dirname63, join as join94 } from "path";
883432
883881
  import { fileURLToPath as fileURLToPath4 } from "url";
883433
883882
  function readJsonVersion(path7) {
883434
883883
  try {
@@ -883442,7 +883891,7 @@ function readJsonVersion(path7) {
883442
883891
  }
883443
883892
  function getPackageVersion() {
883444
883893
  const here = dirname63(fileURLToPath4(import.meta.url));
883445
- return readJsonVersion(join92(here, "..", "..", "package.json")) ?? VERSION;
883894
+ return readJsonVersion(join94(here, "..", "..", "package.json")) ?? VERSION;
883446
883895
  }
883447
883896
  function renderGoodVibesVersion(binary2 = "goodvibes-agent") {
883448
883897
  return `${binary2} ${getPackageVersion()}`;
@@ -883582,6 +884031,8 @@ var COMMAND_HELP = {
883582
884031
  usage: [
883583
884032
  "personas list",
883584
884033
  "personas active",
884034
+ "personas discover",
884035
+ "personas import-discovered <name> [--use] --yes",
883585
884036
  "personas search <query>",
883586
884037
  "personas show <id>",
883587
884038
  "personas create --name <name> --description <summary> --body <instructions> [--tags a,b] [--triggers a,b] [--use]",
@@ -883595,6 +884046,8 @@ var COMMAND_HELP = {
883595
884046
  summary: "Manage Agent-local personas for the serial main conversation. Personas do not spawn worker agents.",
883596
884047
  examples: [
883597
884048
  "personas list",
884049
+ "personas discover",
884050
+ 'personas import-discovered "Travel Planner" --use --yes',
883598
884051
  'personas create --name "Travel Planner" --description "Plan trips" --body "Compare options before booking" --use',
883599
884052
  "personas review travel-planner",
883600
884053
  "personas delete travel-planner --yes"
@@ -883660,15 +884113,19 @@ var COMMAND_HELP = {
883660
884113
  usage: [
883661
884114
  "routines list",
883662
884115
  "routines enabled",
884116
+ "routines discover",
884117
+ "routines import-discovered <name> [--enabled] --yes",
883663
884118
  "routines show <id>",
883664
884119
  "routines receipts",
883665
884120
  "routines reconcile",
883666
884121
  "routines receipt <receipt-id>",
883667
884122
  "routines promote <id> (--cron <expr>|--every <interval>|--at <iso-time>) [--timezone <tz>] [--name <schedule-name>] [--provider <id>] [--model <model>] [--delivery-channel <channel[:route[:label]]>|--delivery-route <route[:label]>|--delivery-webhook <url>|--delivery-link <url>] [--disabled] --yes"
883668
884123
  ],
883669
- summary: "Inspect Agent-local routines, review local promotion receipts, reconcile receipts against live connected schedules, and explicitly promote a reviewed routine into a GoodVibes schedule. Without --yes, promote only prints the schedules.create preview.",
884124
+ summary: "Inspect and import Agent-local routines, review local promotion receipts, reconcile receipts against live connected schedules, and explicitly promote a reviewed routine into a GoodVibes schedule. Without --yes, promote only prints the schedules.create preview.",
883670
884125
  examples: [
883671
884126
  "routines list",
884127
+ "routines discover",
884128
+ 'routines import-discovered "Daily Brief" --enabled --yes',
883672
884129
  "routines show daily-operations-sweep",
883673
884130
  "routines receipts",
883674
884131
  "routines reconcile",
@@ -884175,7 +884632,7 @@ function renderOnboardingCliStatus(options) {
884175
884632
  }
884176
884633
  // src/cli/external-runtime.ts
884177
884634
  import { existsSync as existsSync80, readFileSync as readFileSync88 } from "fs";
884178
- import { join as join93 } from "path";
884635
+ import { join as join95 } from "path";
884179
884636
  function isRecord29(value) {
884180
884637
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
884181
884638
  }
@@ -884189,7 +884646,7 @@ function resolveBaseUrl2(configManager) {
884189
884646
  return `http://${host}:${Number.isFinite(port) ? port : 3421}`;
884190
884647
  }
884191
884648
  function readOperatorToken(homeDirectory) {
884192
- const path7 = join93(homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
884649
+ const path7 = join95(homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
884193
884650
  if (!existsSync80(path7))
884194
884651
  return { token: null, path: path7 };
884195
884652
  try {
@@ -884567,7 +885024,7 @@ function applyRuntimeCommandEndpointFlagOverrides(configManager, command8, flags
884567
885024
  }
884568
885025
  // src/cli/bundle-command.ts
884569
885026
  import { existsSync as existsSync82, mkdirSync as mkdirSync65, readFileSync as readFileSync89, writeFileSync as writeFileSync56 } from "fs";
884570
- import { dirname as dirname64, join as join95 } from "path";
885027
+ import { dirname as dirname64, join as join97 } from "path";
884571
885028
 
884572
885029
  // src/cli/provider-classification.ts
884573
885030
  var SUBSCRIPTION_PROVIDERS = new Set([
@@ -884658,7 +885115,7 @@ function classifyProviderSetup(input) {
884658
885115
  // src/cli/service-posture.ts
884659
885116
  import { closeSync as closeSync4, existsSync as existsSync81, openSync as openSync4, readSync as readSync2, statSync as statSync21 } from "fs";
884660
885117
  import net3 from "net";
884661
- import { isAbsolute as isAbsolute13, join as join94 } from "path";
885118
+ import { isAbsolute as isAbsolute13, join as join96 } from "path";
884662
885119
 
884663
885120
  // src/cli/redaction.ts
884664
885121
  var REDACTED_VALUE = "<redacted>";
@@ -884828,7 +885285,7 @@ function resolveConfiguredLogPath(runtime3) {
884828
885285
  const trimmed2 = value.trim();
884829
885286
  if (!trimmed2)
884830
885287
  return;
884831
- return isAbsolute13(trimmed2) ? trimmed2 : join94(runtime3.homeDirectory, trimmed2);
885288
+ return isAbsolute13(trimmed2) ? trimmed2 : join96(runtime3.homeDirectory, trimmed2);
884832
885289
  }
884833
885290
  function createExternalDaemonLifecycle(logPath) {
884834
885291
  return {
@@ -884937,7 +885394,7 @@ function readAuthPosture(runtime3) {
884937
885394
  });
884938
885395
  const userStorePath = shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-users.json");
884939
885396
  const bootstrapCredentialPath = shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-bootstrap.txt");
884940
- const operatorTokenPath = join95(runtime3.homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
885397
+ const operatorTokenPath = join97(runtime3.homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
884941
885398
  return {
884942
885399
  userStorePath,
884943
885400
  userStorePresent: existsSync82(userStorePath),
@@ -885097,7 +885554,7 @@ async function handleBundleCommand(runtime3) {
885097
885554
  }
885098
885555
  // src/cli/management.ts
885099
885556
  import { existsSync as existsSync84 } from "fs";
885100
- import { join as join98 } from "path";
885557
+ import { join as join100 } from "path";
885101
885558
  import { spawn as spawn5 } from "child_process";
885102
885559
  import { networkInterfaces as networkInterfaces4 } from "os";
885103
885560
 
@@ -885124,7 +885581,7 @@ function formatProviderAuthRoute(route) {
885124
885581
 
885125
885582
  // src/cli/management-commands.ts
885126
885583
  import { mkdirSync as mkdirSync66, writeFileSync as writeFileSync57 } from "fs";
885127
- import { dirname as dirname65, join as join96 } from "path";
885584
+ import { dirname as dirname65, join as join98 } from "path";
885128
885585
  init_config8();
885129
885586
  init_config8();
885130
885587
  init_config8();
@@ -885441,7 +885898,7 @@ async function handleTasks(runtime3) {
885441
885898
  });
885442
885899
  }
885443
885900
  async function renderPairing(runtime3) {
885444
- const daemonHomeDir = join96(runtime3.homeDirectory, ".goodvibes", "daemon");
885901
+ const daemonHomeDir = join98(runtime3.homeDirectory, ".goodvibes", "daemon");
885445
885902
  const tokenRecord = getOrCreateCompanionToken(GOODVIBES_AGENT_PAIRING_SURFACE, { daemonHomeDir });
885446
885903
  const binding = resolveRuntimeEndpointBinding(runtime3.configManager, "controlPlane");
885447
885904
  const daemonUrl = `http://${urlHostForBindHost2(binding.host)}:${binding.port}`;
@@ -885980,7 +886437,7 @@ var DELEGATION_METHOD = {
885980
886437
 
885981
886438
  // src/cli/agent-knowledge-runtime.ts
885982
886439
  import { existsSync as existsSync83, readFileSync as readFileSync90 } from "fs";
885983
- import { join as join97 } from "path";
886440
+ import { join as join99 } from "path";
885984
886441
 
885985
886442
  // node_modules/@pellux/goodvibes-sdk/dist/browser-scoped.js
885986
886443
  init_dist();
@@ -886346,7 +886803,7 @@ function resolveDaemonConnection(runtime3) {
886346
886803
  const host = String(runtime3.configManager.get("controlPlane.host") ?? "127.0.0.1");
886347
886804
  const port = Number(runtime3.configManager.get("controlPlane.port") ?? 3421);
886348
886805
  const baseUrl = `http://${host}:${Number.isFinite(port) ? port : 3421}`;
886349
- const tokenPath = join97(runtime3.homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
886806
+ const tokenPath = join99(runtime3.homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
886350
886807
  if (!existsSync83(tokenPath))
886351
886808
  return { baseUrl, token: null, tokenPath };
886352
886809
  try {
@@ -887132,6 +887589,48 @@ function renderPersona2(persona, activePersonaId) {
887132
887589
  ].filter((line2) => Boolean(line2)).join(`
887133
887590
  `);
887134
887591
  }
887592
+ function summarizeDiscoveredPersona2(persona) {
887593
+ const description = persona.description ? ` - ${persona.description}` : "";
887594
+ return [
887595
+ ` ${persona.name} ${persona.origin}${description}`,
887596
+ ` path: ${persona.path}`
887597
+ ].join(`
887598
+ `);
887599
+ }
887600
+ function renderDiscoveredPersonaList(personas) {
887601
+ if (personas.length === 0) {
887602
+ return [
887603
+ "Discovered Agent persona files",
887604
+ " No persona markdown files found in Agent persona folders.",
887605
+ " Search roots: .goodvibes/personas, .goodvibes/agent/personas, .goodvibes/agents, ~/.goodvibes/personas, ~/.goodvibes/agent/personas, ~/.goodvibes/agents"
887606
+ ].join(`
887607
+ `);
887608
+ }
887609
+ return [
887610
+ `Discovered Agent persona files (${personas.length})`,
887611
+ ...personas.map(summarizeDiscoveredPersona2),
887612
+ "",
887613
+ "Import one with: goodvibes-agent personas import-discovered <name> --yes"
887614
+ ].join(`
887615
+ `);
887616
+ }
887617
+ function discoveredPersonaLookupValues2(persona) {
887618
+ const slug = persona.name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
887619
+ const basename6 = persona.path.split(/[\\/]/).pop()?.replace(/\.md$/i, "") ?? "";
887620
+ return [persona.name, slug, persona.path, basename6].map((value) => value.trim().toLowerCase()).filter(Boolean);
887621
+ }
887622
+ function findDiscoveredPersona2(personas, idOrName) {
887623
+ const lookup = idOrName.trim().toLowerCase();
887624
+ if (!lookup)
887625
+ return null;
887626
+ return personas.find((persona) => discoveredPersonaLookupValues2(persona).includes(lookup)) ?? null;
887627
+ }
887628
+ function discoveredPersonaFrontmatterList(persona, key) {
887629
+ const value = persona.frontmatter[key];
887630
+ if (!value)
887631
+ return [];
887632
+ return value.split(",").map((entry) => entry.trim()).filter(Boolean);
887633
+ }
887135
887634
  function summarizeSkill2(skill) {
887136
887635
  const enabled = skill.enabled ? "enabled" : "disabled";
887137
887636
  const tags = skill.tags.length > 0 ? ` tags=${skill.tags.join(",")}` : "";
@@ -887255,7 +887754,7 @@ function renderBundle2(bundle) {
887255
887754
  `);
887256
887755
  }
887257
887756
  function usagePersonas() {
887258
- return "Usage: goodvibes-agent personas [list|active|search <query>|show <id>|create|update <id>|use <id>|clear|review <id>|stale <id> <reason>|delete <id> --yes]";
887757
+ return "Usage: goodvibes-agent personas [list|active|discover|import-discovered <name> --yes|search <query>|show <id>|create|update <id>|use <id>|clear|review <id>|stale <id> <reason>|delete <id> --yes]";
887259
887758
  }
887260
887759
  function usageSkills() {
887261
887760
  return "Usage: goodvibes-agent skills [list|enabled|active|discover|import-discovered <name> --yes|search <query>|show <id>|create|update <id>|enable <id>|disable <id>|review <id>|stale <id> <reason>|delete <id> --yes|bundle ...]";
@@ -887284,6 +887783,45 @@ async function handlePersonasCommand(runtime3) {
887284
887783
  return failure(runtime3, "agent.personas.active_missing", "No active Agent persona.", 1);
887285
887784
  return success3(runtime3, "agent.personas.active", active, renderPersona2(active, active.id));
887286
887785
  }
887786
+ if (normalized === "discover") {
887787
+ const discovered = await discoverPersonas(shellPaths(runtime3));
887788
+ return success3(runtime3, "agent.personas.discover", { personas: discovered }, renderDiscoveredPersonaList(discovered));
887789
+ }
887790
+ if (normalized === "import-discovered" || normalized === "import-persona") {
887791
+ const options = parseOptions(rest);
887792
+ const name51 = options.positionals.join(" ").trim();
887793
+ if (!name51)
887794
+ return failure(runtime3, "invalid_persona_command", "Usage: goodvibes-agent personas import-discovered <name> [--use] --yes", 2);
887795
+ const discovered = findDiscoveredPersona2(await discoverPersonas(shellPaths(runtime3)), name51);
887796
+ if (!discovered) {
887797
+ return failure(runtime3, "persona_discovery_not_found", `Unknown discovered Agent persona: ${name51}
887798
+ Run goodvibes-agent personas discover to inspect available persona files.`, 1);
887799
+ }
887800
+ if (!hasFlag3(options, "yes")) {
887801
+ return success3(runtime3, "agent.personas.import_discovered.preview", { persona: discovered }, [
887802
+ "Agent persona import preview",
887803
+ ` name: ${discovered.name}`,
887804
+ ` origin: ${discovered.origin}`,
887805
+ ` path: ${discovered.path}`,
887806
+ ` description: ${discovered.description || "(none)"}`,
887807
+ ` body characters: ${discovered.body.length}`,
887808
+ " next: rerun with --yes to import into the Agent-local persona registry"
887809
+ ].join(`
887810
+ `));
887811
+ }
887812
+ const persona = registry5.create({
887813
+ name: discovered.name,
887814
+ description: discovered.description || `Imported persona from ${discovered.origin} markdown file.`,
887815
+ body: discovered.body,
887816
+ tags: discoveredPersonaFrontmatterList(discovered, "tags"),
887817
+ triggers: discoveredPersonaFrontmatterList(discovered, "triggers"),
887818
+ source: "imported",
887819
+ provenance: `discovered:${discovered.origin}:${discovered.path}`
887820
+ });
887821
+ if (hasFlag3(options, "use"))
887822
+ registry5.setActive(persona.id);
887823
+ return success3(runtime3, "agent.personas.import_discovered", persona, `Imported Agent persona ${persona.id}: ${persona.name}${hasFlag3(options, "use") ? " (active)" : ""}`);
887824
+ }
887287
887825
  if (normalized === "search" || normalized === "find") {
887288
887826
  const query2 = rest.join(" ").trim();
887289
887827
  const results = registry5.search(query2);
@@ -888511,17 +889049,87 @@ function routineRegistry(runtime3) {
888511
889049
  homeDirectory: runtime3.homeDirectory
888512
889050
  }));
888513
889051
  }
889052
+ function shellPaths2(runtime3) {
889053
+ return createShellPathService2({
889054
+ workingDirectory: runtime3.workingDirectory,
889055
+ homeDirectory: runtime3.homeDirectory
889056
+ });
889057
+ }
888514
889058
  function routineReceiptStore(runtime3) {
888515
889059
  return RoutineScheduleReceiptStore.fromShellPaths(createShellPathService2({
888516
889060
  workingDirectory: runtime3.workingDirectory,
888517
889061
  homeDirectory: runtime3.homeDirectory
888518
889062
  }));
888519
889063
  }
889064
+ function splitList6(value) {
889065
+ if (!value)
889066
+ return [];
889067
+ return value.split(",").map((entry) => entry.trim()).filter(Boolean);
889068
+ }
889069
+ function parseImportFlags(args2) {
889070
+ const positionals = [];
889071
+ let enabled = false;
889072
+ let yes = false;
889073
+ for (const arg of args2) {
889074
+ if (arg === "--enabled") {
889075
+ enabled = true;
889076
+ continue;
889077
+ }
889078
+ if (arg === "--yes") {
889079
+ yes = true;
889080
+ continue;
889081
+ }
889082
+ positionals.push(arg);
889083
+ }
889084
+ return { name: positionals.join(" ").trim(), enabled, yes };
889085
+ }
888520
889086
  function summarizeRoutine2(routine) {
888521
889087
  const enabled = routine.enabled ? "enabled" : "disabled";
888522
889088
  const tags = routine.tags.length > 0 ? ` tags=${routine.tags.join(",")}` : "";
888523
889089
  return ` ${routine.id} ${enabled} ${routine.reviewState} starts=${routine.startCount} ${routine.name} - ${routine.description}${tags}`;
888524
889090
  }
889091
+ function summarizeDiscoveredRoutine2(routine) {
889092
+ const description = routine.description ? ` - ${routine.description}` : "";
889093
+ return [
889094
+ ` ${routine.name} ${routine.origin}${description}`,
889095
+ ` path: ${routine.path}`
889096
+ ].join(`
889097
+ `);
889098
+ }
889099
+ function renderDiscoveredRoutineList(routines) {
889100
+ if (routines.length === 0) {
889101
+ return [
889102
+ "Discovered Agent routine files",
889103
+ " No routine markdown files found in Agent routine folders.",
889104
+ " Search roots: .goodvibes/routines, .goodvibes/agent/routines, ~/.goodvibes/routines, ~/.goodvibes/agent/routines"
889105
+ ].join(`
889106
+ `);
889107
+ }
889108
+ return [
889109
+ `Discovered Agent routine files (${routines.length})`,
889110
+ ...routines.map(summarizeDiscoveredRoutine2),
889111
+ "",
889112
+ "Import one with: goodvibes-agent routines import-discovered <name> --yes"
889113
+ ].join(`
889114
+ `);
889115
+ }
889116
+ function discoveredRoutineLookupValues2(routine) {
889117
+ const slug = routine.name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
889118
+ const basename6 = routine.path.split(/[\\/]/).pop()?.replace(/\.md$/i, "") ?? "";
889119
+ return [routine.name, slug, routine.path, basename6].map((value) => value.trim().toLowerCase()).filter(Boolean);
889120
+ }
889121
+ function findDiscoveredRoutine2(routines, idOrName) {
889122
+ const lookup = idOrName.trim().toLowerCase();
889123
+ if (!lookup)
889124
+ return null;
889125
+ return routines.find((routine) => discoveredRoutineLookupValues2(routine).includes(lookup)) ?? null;
889126
+ }
889127
+ function discoveredRoutineFrontmatterList(routine, key) {
889128
+ const value = routine.frontmatter[key];
889129
+ if (!value)
889130
+ return [];
889131
+ return splitList6(value);
889132
+ }
888525
889133
  function renderRoutineList(title, path7, routines) {
888526
889134
  if (routines.length === 0) {
888527
889135
  return [
@@ -888640,6 +889248,84 @@ async function handleRoutinesCommand(runtime3) {
888640
889248
  exitCode: 0
888641
889249
  };
888642
889250
  }
889251
+ if (normalized === "discover") {
889252
+ const discovered = await discoverRoutines(shellPaths2(runtime3));
889253
+ const value = {
889254
+ ok: true,
889255
+ kind: "agent.routines.discover",
889256
+ data: { routines: discovered }
889257
+ };
889258
+ return {
889259
+ output: jsonOrText3(runtime3, value, renderDiscoveredRoutineList(discovered)),
889260
+ exitCode: 0
889261
+ };
889262
+ }
889263
+ if (normalized === "import-discovered" || normalized === "import-routine") {
889264
+ const parsed = parseImportFlags(rest);
889265
+ if (!parsed.name) {
889266
+ const failure3 = {
889267
+ ok: false,
889268
+ kind: "invalid_routine_command",
889269
+ error: "Usage: goodvibes-agent routines import-discovered <name> [--enabled] --yes"
889270
+ };
889271
+ return {
889272
+ output: runtime3.cli.flags.outputFormat === "json" ? JSON.stringify(failure3, null, 2) : failure3.error,
889273
+ exitCode: 2
889274
+ };
889275
+ }
889276
+ const discovered = findDiscoveredRoutine2(await discoverRoutines(shellPaths2(runtime3)), parsed.name);
889277
+ if (!discovered) {
889278
+ const failure3 = {
889279
+ ok: false,
889280
+ kind: "routine_discovery_not_found",
889281
+ error: `Unknown discovered Agent routine: ${parsed.name}
889282
+ Run goodvibes-agent routines discover to inspect available routine files.`
889283
+ };
889284
+ return {
889285
+ output: runtime3.cli.flags.outputFormat === "json" ? JSON.stringify(failure3, null, 2) : failure3.error,
889286
+ exitCode: 1
889287
+ };
889288
+ }
889289
+ if (!parsed.yes) {
889290
+ const value2 = {
889291
+ ok: true,
889292
+ kind: "agent.routines.import_discovered.preview",
889293
+ data: { routine: discovered }
889294
+ };
889295
+ return {
889296
+ output: jsonOrText3(runtime3, value2, [
889297
+ "Agent routine import preview",
889298
+ ` name: ${discovered.name}`,
889299
+ ` origin: ${discovered.origin}`,
889300
+ ` path: ${discovered.path}`,
889301
+ ` description: ${discovered.description || "(none)"}`,
889302
+ ` steps characters: ${discovered.steps.length}`,
889303
+ " next: rerun with --yes to import into the Agent-local routine registry"
889304
+ ].join(`
889305
+ `)),
889306
+ exitCode: 0
889307
+ };
889308
+ }
889309
+ const routine = registry5.create({
889310
+ name: discovered.name,
889311
+ description: discovered.description || `Imported routine from ${discovered.origin} markdown file.`,
889312
+ steps: discovered.steps,
889313
+ tags: discoveredRoutineFrontmatterList(discovered, "tags"),
889314
+ triggers: discoveredRoutineFrontmatterList(discovered, "triggers"),
889315
+ enabled: parsed.enabled,
889316
+ source: "imported",
889317
+ provenance: `discovered:${discovered.origin}:${discovered.path}`
889318
+ });
889319
+ const value = {
889320
+ ok: true,
889321
+ kind: "agent.routines.import_discovered",
889322
+ data: routine
889323
+ };
889324
+ return {
889325
+ output: jsonOrText3(runtime3, value, `Imported Agent routine ${routine.id}: ${routine.name}${routine.enabled ? " (enabled)" : ""}`),
889326
+ exitCode: 0
889327
+ };
889328
+ }
888643
889329
  if (normalized === "show") {
888644
889330
  const id = rest[0];
888645
889331
  if (!id)
@@ -888704,7 +889390,7 @@ async function handleRoutinesCommand(runtime3) {
888704
889390
  return handleRoutinePromotion(runtime3, rest);
888705
889391
  }
888706
889392
  return {
888707
- output: "Usage: goodvibes-agent routines [list|enabled|show <id>|receipts|reconcile|receipt <id>|promote <id> (--cron <expr>|--every <interval>|--at <iso-time>) [--delivery-channel <channel>|--delivery-route <route>|--delivery-webhook <url>] --yes]",
889393
+ output: "Usage: goodvibes-agent routines [list|enabled|discover|import-discovered <name> --yes|show <id>|receipts|reconcile|receipt <id>|promote <id> (--cron <expr>|--every <interval>|--at <iso-time>) [--delivery-channel <channel>|--delivery-route <route>|--delivery-webhook <url>] --yes]",
888708
889394
  exitCode: 2
888709
889395
  };
888710
889396
  }
@@ -888806,13 +889492,13 @@ async function withRuntimeServices(runtime3, fn) {
888806
889492
  }
888807
889493
  }
888808
889494
  function readAuthPaths(runtime3) {
888809
- const shellPaths2 = createShellPathService2({
889495
+ const shellPaths3 = createShellPathService2({
888810
889496
  workingDirectory: runtime3.workingDirectory,
888811
889497
  homeDirectory: runtime3.homeDirectory
888812
889498
  });
888813
- const userStorePath = shellPaths2.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-users.json");
888814
- const bootstrapCredentialPath = shellPaths2.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-bootstrap.txt");
888815
- const operatorTokenPath = join98(runtime3.homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
889499
+ const userStorePath = shellPaths3.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-users.json");
889500
+ const bootstrapCredentialPath = shellPaths3.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-bootstrap.txt");
889501
+ const operatorTokenPath = join100(runtime3.homeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
888816
889502
  return {
888817
889503
  userStorePath,
888818
889504
  userStorePresent: existsSync84(userStorePath),
@@ -889327,7 +890013,7 @@ async function prepareShellCliRuntime(argv, roots, binary2 = "goodvibes-agent")
889327
890013
  workingDirectory: bootstrapWorkingDir,
889328
890014
  homeDirectory: bootstrapHomeDirectory
889329
890015
  } = ownership;
889330
- configureActivityLogger(join99(bootstrapWorkingDir, ".goodvibes", "logs"));
890016
+ configureActivityLogger(join101(bootstrapWorkingDir, ".goodvibes", "logs"));
889331
890017
  const configManager = new ConfigManager({
889332
890018
  workingDir: bootstrapWorkingDir,
889333
890019
  homeDir: bootstrapHomeDirectory,
@@ -889372,14 +890058,14 @@ async function prepareShellCliRuntime(argv, roots, binary2 = "goodvibes-agent")
889372
890058
  process.exit(2);
889373
890059
  }
889374
890060
  if (cli.command === "status" || cli.command === "doctor" || cli.command === "onboarding" && cli.commandArgs[0] === "status") {
889375
- const shellPaths2 = createShellPathService2({
890061
+ const shellPaths3 = createShellPathService2({
889376
890062
  workingDirectory: bootstrapWorkingDir,
889377
890063
  homeDirectory: bootstrapHomeDirectory
889378
890064
  });
889379
- const userStorePath = shellPaths2.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-users.json");
889380
- const bootstrapCredentialPath = shellPaths2.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-bootstrap.txt");
889381
- const operatorTokenPath = join99(bootstrapHomeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
889382
- const onboardingMarkers = readOnboardingCheckMarkers(shellPaths2);
890065
+ const userStorePath = shellPaths3.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-users.json");
890066
+ const bootstrapCredentialPath = shellPaths3.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, "auth-bootstrap.txt");
890067
+ const operatorTokenPath = join101(bootstrapHomeDirectory, ".goodvibes", "daemon", "operator-tokens.json");
890068
+ const onboardingMarkers = readOnboardingCheckMarkers(shellPaths3);
889383
890069
  const service = await buildCliServicePosture({
889384
890070
  configManager,
889385
890071
  workingDirectory: bootstrapWorkingDir,
@@ -889493,8 +890179,8 @@ function getInteractiveTerminalLaunchError(input) {
889493
890179
  `);
889494
890180
  }
889495
890181
  function applyInitialTuiCliState(options) {
889496
- const { cli, input, commandRegistry, commandContext, shellPaths: shellPaths2, render } = options;
889497
- const globalOnboardingMarker = readOnboardingCheckMarker(shellPaths2, "user");
890182
+ const { cli, input, commandRegistry, commandContext, shellPaths: shellPaths3, render } = options;
890183
+ const globalOnboardingMarker = readOnboardingCheckMarker(shellPaths3, "user");
889498
890184
  const seededPrompt = cli.flags.prompt ?? (cli.rawCommand === undefined && cli.positionals.length > 0 ? cli.positionals.join(" ") : undefined);
889499
890185
  if (cli.command === "onboarding") {
889500
890186
  input.openOnboardingWizard({ mode: "edit", reset: true });
@@ -889516,7 +890202,7 @@ function applyInitialTuiCliState(options) {
889516
890202
 
889517
890203
  // src/audio/player.ts
889518
890204
  import { accessSync, constants as constants4 } from "fs";
889519
- import { delimiter, join as join100 } from "path";
890205
+ import { delimiter, join as join102 } from "path";
889520
890206
  import { spawn as spawn6 } from "child_process";
889521
890207
 
889522
890208
  class LocalStreamingAudioPlayer {
@@ -889613,7 +890299,7 @@ function findExecutable(name51, env2) {
889613
890299
  if (!dir)
889614
890300
  continue;
889615
890301
  for (const ext of extensions14) {
889616
- const candidate = join100(dir, `${name51}${ext}`);
890302
+ const candidate = join102(dir, `${name51}${ext}`);
889617
890303
  try {
889618
890304
  accessSync(candidate, constants4.X_OK);
889619
890305
  return candidate;