hubify 1.0.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +193 -75
  2. package/dist/index.js +2869 -519
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7,9 +7,9 @@ import {
7
7
  } from "./chunk-FW7BS3MW.js";
8
8
 
9
9
  // src/index.ts
10
- import { Command as Command53 } from "commander";
11
- import chalk56 from "chalk";
12
- import fs26 from "fs";
10
+ import { Command as Command58 } from "commander";
11
+ import chalk61 from "chalk";
12
+ import fs28 from "fs";
13
13
 
14
14
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
15
15
  var external_exports = {};
@@ -489,8 +489,8 @@ function getErrorMap() {
489
489
 
490
490
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
491
491
  var makeIssue = (params) => {
492
- const { data, path: path26, errorMaps, issueData } = params;
493
- const fullPath = [...path26, ...issueData.path || []];
492
+ const { data, path: path27, errorMaps, issueData } = params;
493
+ const fullPath = [...path27, ...issueData.path || []];
494
494
  const fullIssue = {
495
495
  ...issueData,
496
496
  path: fullPath
@@ -606,11 +606,11 @@ var errorUtil;
606
606
 
607
607
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
608
608
  var ParseInputLazyPath = class {
609
- constructor(parent, value, path26, key) {
609
+ constructor(parent, value, path27, key) {
610
610
  this._cachedPath = [];
611
611
  this.parent = parent;
612
612
  this.data = value;
613
- this._path = path26;
613
+ this._path = path27;
614
614
  this._key = key;
615
615
  }
616
616
  get path() {
@@ -4410,7 +4410,7 @@ var rl = readline.createInterface({
4410
4410
  input: process.stdin,
4411
4411
  output: process.stdout
4412
4412
  });
4413
- var question = (prompt) => new Promise((resolve11) => rl.question(prompt, resolve11));
4413
+ var question = (prompt) => new Promise((resolve12) => rl.question(prompt, resolve12));
4414
4414
  var initCommand = new Command("init").description("Initialize Hubify in the current project or globally").option("--agent-id <id>", "Set agent ID").option("--platform <name>", "Set platform (claude-code, cursor, etc.)").option("--global", "Initialize global config (~/.hubify)").option("--non-interactive", "Skip prompts, use defaults").action(async (options) => {
4415
4415
  const spinner = ora();
4416
4416
  const isGlobal = options.global;
@@ -5806,15 +5806,15 @@ var challengesCommand = new Command5("challenges").description("View and respond
5806
5806
  var respondCommand = new Command5("respond").description("Respond to a verification challenge").argument("<challenge-id>", "Challenge ID to respond to").option("--agent-id <id>", "Agent ID (default: cli-user)").option("--output <text>", "Full output from re-execution").option("--output-file <path>", "Read output from file").action(async (challengeId, options) => {
5807
5807
  const spinner = ora5();
5808
5808
  const client = getClient();
5809
- const fs27 = await import("fs");
5809
+ const fs29 = await import("fs");
5810
5810
  const resolvedAgentId = options.agentId || process.env.HUBIFY_AGENT_ID || "cli-user";
5811
5811
  try {
5812
5812
  let output = options.output;
5813
5813
  if (options.outputFile) {
5814
- if (!fs27.existsSync(options.outputFile)) {
5814
+ if (!fs29.existsSync(options.outputFile)) {
5815
5815
  throw new Error(`Output file not found: ${options.outputFile}`);
5816
5816
  }
5817
- output = fs27.readFileSync(options.outputFile, "utf-8");
5817
+ output = fs29.readFileSync(options.outputFile, "utf-8");
5818
5818
  }
5819
5819
  if (!output) {
5820
5820
  throw new Error("Must provide --output or --output-file");
@@ -5923,11 +5923,11 @@ function formatVerificationLevel(level) {
5923
5923
  }
5924
5924
  async function readStdinJson() {
5925
5925
  if (process.stdin.isTTY) return {};
5926
- const raw = await new Promise((resolve11, reject) => {
5926
+ const raw = await new Promise((resolve12, reject) => {
5927
5927
  let data = "";
5928
5928
  process.stdin.setEncoding("utf8");
5929
5929
  process.stdin.on("data", (chunk) => data += chunk);
5930
- process.stdin.on("end", () => resolve11(data));
5930
+ process.stdin.on("end", () => resolve12(data));
5931
5931
  process.stdin.on("error", reject);
5932
5932
  });
5933
5933
  const trimmed = raw.trim();
@@ -5974,7 +5974,7 @@ Skill not found: ${skill}
5974
5974
  \u{1F504} Checking ${skillsToUpdate.length} skill(s) for updates...
5975
5975
  `));
5976
5976
  spinner.start("Checking for updates...");
5977
- await new Promise((resolve11) => setTimeout(resolve11, 500));
5977
+ await new Promise((resolve12) => setTimeout(resolve12, 500));
5978
5978
  spinner.stop();
5979
5979
  const updates = skillsToUpdate.map((name) => ({
5980
5980
  name,
@@ -6002,7 +6002,7 @@ Skill not found: ${skill}
6002
6002
  }
6003
6003
  spinner.start("Applying updates...");
6004
6004
  for (const update of availableUpdates) {
6005
- await new Promise((resolve11) => setTimeout(resolve11, 200));
6005
+ await new Promise((resolve12) => setTimeout(resolve12, 200));
6006
6006
  }
6007
6007
  spinner.succeed(`Updated ${availableUpdates.length} skill(s)`);
6008
6008
  console.log();
@@ -6837,9 +6837,9 @@ async function fetchSkillMd(entry) {
6837
6837
  `SKILL.md`
6838
6838
  ];
6839
6839
  for (const branch of branches) {
6840
- for (const path26 of paths) {
6840
+ for (const path27 of paths) {
6841
6841
  try {
6842
- const url = `https://raw.githubusercontent.com/${entry.owner}/${entry.repo}/${branch}/${path26}`;
6842
+ const url = `https://raw.githubusercontent.com/${entry.owner}/${entry.repo}/${branch}/${path27}`;
6843
6843
  const response = await fetch(url);
6844
6844
  if (response.ok) {
6845
6845
  return await response.text();
@@ -8119,7 +8119,7 @@ var createReadline = () => readline2.createInterface({
8119
8119
  input: process.stdin,
8120
8120
  output: process.stdout
8121
8121
  });
8122
- var question2 = (rl4, prompt) => new Promise((resolve11) => rl4.question(prompt, resolve11));
8122
+ var question2 = (rl4, prompt) => new Promise((resolve12) => rl4.question(prompt, resolve12));
8123
8123
  function getAnthropicApiKey() {
8124
8124
  if (process.env.ANTHROPIC_API_KEY) {
8125
8125
  return process.env.ANTHROPIC_API_KEY;
@@ -14580,11 +14580,11 @@ async function fetchGitHubApi2(endpoint) {
14580
14580
  return null;
14581
14581
  }
14582
14582
  }
14583
- async function fetchRawContent2(owner, repo, path26, branch = "main") {
14583
+ async function fetchRawContent2(owner, repo, path27, branch = "main") {
14584
14584
  const branches = [branch, "master"];
14585
14585
  for (const b of branches) {
14586
14586
  try {
14587
- const url = `https://raw.githubusercontent.com/${owner}/${repo}/${b}/${path26}`;
14587
+ const url = `https://raw.githubusercontent.com/${owner}/${repo}/${b}/${path27}`;
14588
14588
  const headers = { "User-Agent": "hubify-cli" };
14589
14589
  const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
14590
14590
  if (token) {
@@ -14934,7 +14934,7 @@ function formatDuration2(ms) {
14934
14934
  }
14935
14935
  async function runSeedCommand(source, options) {
14936
14936
  const { spawn } = await import("child_process");
14937
- return new Promise((resolve11) => {
14937
+ return new Promise((resolve12) => {
14938
14938
  const args = [source.commandName];
14939
14939
  if (options.dryRun) args.push("--dry-run");
14940
14940
  if (options.force) args.push("--force");
@@ -14955,7 +14955,7 @@ async function runSeedCommand(source, options) {
14955
14955
  const importMatch = stdout.match(/Imported:\s*(\d+)/);
14956
14956
  const skipMatch = stdout.match(/Skipped:\s*(\d+)/);
14957
14957
  const failMatch = stdout.match(/Failed:\s*(\d+)/);
14958
- resolve11({
14958
+ resolve12({
14959
14959
  imported: importMatch ? parseInt(importMatch[1]) : 0,
14960
14960
  skipped: skipMatch ? parseInt(skipMatch[1]) : 0,
14961
14961
  failed: failMatch ? parseInt(failMatch[1]) : code !== 0 ? source.skillCount : 0,
@@ -14963,7 +14963,7 @@ async function runSeedCommand(source, options) {
14963
14963
  });
14964
14964
  });
14965
14965
  proc.on("error", () => {
14966
- resolve11({
14966
+ resolve12({
14967
14967
  imported: 0,
14968
14968
  skipped: 0,
14969
14969
  failed: source.skillCount,
@@ -15673,8 +15673,8 @@ soulCommand.command("create").description("Create a new soul interactively").act
15673
15673
  output: process.stdout
15674
15674
  });
15675
15675
  const question5 = (prompt) => {
15676
- return new Promise((resolve11) => {
15677
- rl4.question(prompt, resolve11);
15676
+ return new Promise((resolve12) => {
15677
+ rl4.question(prompt, resolve12);
15678
15678
  });
15679
15679
  };
15680
15680
  try {
@@ -15911,8 +15911,8 @@ soulCommand.command("fork").argument("<name>", "Name of the soul to fork").descr
15911
15911
  output: process.stdout
15912
15912
  });
15913
15913
  const question5 = (prompt) => {
15914
- return new Promise((resolve11) => {
15915
- rl4.question(prompt, resolve11);
15914
+ return new Promise((resolve12) => {
15915
+ rl4.question(prompt, resolve12);
15916
15916
  });
15917
15917
  };
15918
15918
  const nameInput = await question5(
@@ -20869,11 +20869,11 @@ squadCommand.command("init").description("Initialize a local squad from a pack t
20869
20869
  return;
20870
20870
  }
20871
20871
  spinner.text = "Generating local files...";
20872
- const fs27 = await import("fs");
20873
- const path26 = await import("path");
20872
+ const fs29 = await import("fs");
20873
+ const path27 = await import("path");
20874
20874
  const dir = options.dir || ".hubify";
20875
- const basePath = path26.resolve(process.cwd(), dir);
20876
- fs27.mkdirSync(basePath, { recursive: true });
20875
+ const basePath = path27.resolve(process.cwd(), dir);
20876
+ fs29.mkdirSync(basePath, { recursive: true });
20877
20877
  const squadMd = [
20878
20878
  `# ${pack.display_name}`,
20879
20879
  "",
@@ -20901,7 +20901,7 @@ squadCommand.command("init").description("Initialize a local squad from a pack t
20901
20901
  ""
20902
20902
  ].filter(Boolean).join("\n"))
20903
20903
  ].join("\n");
20904
- fs27.writeFileSync(path26.join(basePath, "squad.md"), squadMd);
20904
+ fs29.writeFileSync(path27.join(basePath, "squad.md"), squadMd);
20905
20905
  const missionMd = [
20906
20906
  `# Mission Brief`,
20907
20907
  "",
@@ -20922,12 +20922,12 @@ ${pack.default_phases.map((p, i) => `${i + 1}. ${p.name}`).join("\n")}` : "",
20922
20922
  `## Notes`,
20923
20923
  `<!-- Additional context, constraints, or references -->`
20924
20924
  ].join("\n");
20925
- fs27.writeFileSync(path26.join(basePath, "mission.md"), missionMd);
20926
- const agentsDir = path26.join(basePath, "agents");
20927
- fs27.mkdirSync(agentsDir, { recursive: true });
20925
+ fs29.writeFileSync(path27.join(basePath, "mission.md"), missionMd);
20926
+ const agentsDir = path27.join(basePath, "agents");
20927
+ fs29.mkdirSync(agentsDir, { recursive: true });
20928
20928
  for (const member of pack.members) {
20929
- const memberDir = path26.join(agentsDir, member.role);
20930
- fs27.mkdirSync(memberDir, { recursive: true });
20929
+ const memberDir = path27.join(agentsDir, member.role);
20930
+ fs29.mkdirSync(memberDir, { recursive: true });
20931
20931
  const agentMd = [
20932
20932
  `# Agent: ${member.role}`,
20933
20933
  "",
@@ -20943,7 +20943,7 @@ ${pack.default_phases.map((p, i) => `${i + 1}. ${p.name}`).join("\n")}` : "",
20943
20943
  member.default_tools ? `## Tools
20944
20944
  ${member.default_tools.map((t) => `- ${t}`).join("\n")}` : ""
20945
20945
  ].join("\n");
20946
- fs27.writeFileSync(path26.join(memberDir, "agent.md"), agentMd);
20946
+ fs29.writeFileSync(path27.join(memberDir, "agent.md"), agentMd);
20947
20947
  const soulMd = [
20948
20948
  `# Soul: ${member.soul_name}`,
20949
20949
  "",
@@ -20956,7 +20956,7 @@ ${member.default_tools.map((t) => `- ${t}`).join("\n")}` : ""
20956
20956
  `## Responsibilities`,
20957
20957
  ...member.responsibilities.map((r) => `- ${r}`)
20958
20958
  ].join("\n");
20959
- fs27.writeFileSync(path26.join(memberDir, "soul.md"), soulMd);
20959
+ fs29.writeFileSync(path27.join(memberDir, "soul.md"), soulMd);
20960
20960
  }
20961
20961
  spinner.succeed(`Squad initialized in ${dir}/`);
20962
20962
  console.log();
@@ -21084,6 +21084,70 @@ squadCommand.command("event").description("Post a manual event to the squad acti
21084
21084
  process.exit(1);
21085
21085
  }
21086
21086
  });
21087
+ squadCommand.command("pause <squad-id>").description("Pause a deployed squad (disables standups and autonomy)").option("--owner <id>", "Owner user ID").action(async (squadId, options) => {
21088
+ const spinner = ora26();
21089
+ try {
21090
+ spinner.start("Pausing squad...");
21091
+ const client = getClient();
21092
+ await client.mutation(
21093
+ toFunctionName(api.squads.pauseSquad),
21094
+ { squad_id: squadId, owner_id: options.owner || "" }
21095
+ );
21096
+ spinner.succeed("Squad paused");
21097
+ console.log(chalk29.yellow("\n Standups and autonomy processing disabled."));
21098
+ console.log(chalk29.gray(" Use `hubify squad resume` to re-enable.\n"));
21099
+ } catch (error) {
21100
+ spinner.fail("Failed to pause squad");
21101
+ console.error(chalk29.red(error instanceof Error ? error.message : "Unknown error"));
21102
+ process.exit(1);
21103
+ }
21104
+ });
21105
+ squadCommand.command("resume <squad-id>").description("Resume a paused squad (re-enables standups and autonomy)").option("--owner <id>", "Owner user ID").action(async (squadId, options) => {
21106
+ const spinner = ora26();
21107
+ try {
21108
+ spinner.start("Resuming squad...");
21109
+ const client = getClient();
21110
+ await client.mutation(
21111
+ toFunctionName(api.squads.resumeSquad),
21112
+ { squad_id: squadId, owner_id: options.owner || "" }
21113
+ );
21114
+ spinner.succeed("Squad resumed");
21115
+ console.log(chalk29.green("\n Standups and autonomy processing re-enabled.\n"));
21116
+ } catch (error) {
21117
+ spinner.fail("Failed to resume squad");
21118
+ console.error(chalk29.red(error instanceof Error ? error.message : "Unknown error"));
21119
+ process.exit(1);
21120
+ }
21121
+ });
21122
+ squadCommand.command("remove <squad-id>").description("Remove a deployed squad from your workspace (marks as deprecated)").option("--owner <id>", "Owner user ID").option("--force", "Skip confirmation").action(async (squadId, options) => {
21123
+ const spinner = ora26();
21124
+ try {
21125
+ if (!options.force) {
21126
+ const readline7 = await import("readline");
21127
+ const rl4 = readline7.createInterface({ input: process.stdin, output: process.stdout });
21128
+ const answer = await new Promise((resolve12) => {
21129
+ rl4.question(chalk29.yellow(" Remove this squad? This cannot be undone. (y/N): "), resolve12);
21130
+ });
21131
+ rl4.close();
21132
+ if (answer.toLowerCase() !== "y") {
21133
+ console.log(chalk29.gray(" Cancelled.\n"));
21134
+ return;
21135
+ }
21136
+ }
21137
+ spinner.start("Removing squad...");
21138
+ const client = getClient();
21139
+ await client.mutation(
21140
+ toFunctionName(api.squads.removeSquad),
21141
+ { squad_id: squadId, owner_id: options.owner || "" }
21142
+ );
21143
+ spinner.succeed("Squad removed");
21144
+ console.log(chalk29.red("\n Squad deprecated and removed from workspace.\n"));
21145
+ } catch (error) {
21146
+ spinner.fail("Failed to remove squad");
21147
+ console.error(chalk29.red(error instanceof Error ? error.message : "Unknown error"));
21148
+ process.exit(1);
21149
+ }
21150
+ });
21087
21151
 
21088
21152
  // src/commands/skill-gen.ts
21089
21153
  import { Command as Command27 } from "commander";
@@ -21663,7 +21727,7 @@ async function promptForResult() {
21663
21727
  input: process.stdin,
21664
21728
  output: process.stdout
21665
21729
  });
21666
- return new Promise((resolve11) => {
21730
+ return new Promise((resolve12) => {
21667
21731
  console.log();
21668
21732
  console.log(chalk31.cyan(" Execution complete. Please report the result:"));
21669
21733
  console.log();
@@ -21675,11 +21739,11 @@ async function promptForResult() {
21675
21739
  rl4.close();
21676
21740
  const choice = answer.toLowerCase().trim();
21677
21741
  if (choice === "s" || choice === "success") {
21678
- resolve11(true);
21742
+ resolve12(true);
21679
21743
  } else if (choice === "f" || choice === "failed" || choice === "fail") {
21680
- resolve11(false);
21744
+ resolve12(false);
21681
21745
  } else {
21682
- resolve11(void 0);
21746
+ resolve12(void 0);
21683
21747
  }
21684
21748
  });
21685
21749
  });
@@ -21799,7 +21863,7 @@ var rl2 = readline5.createInterface({
21799
21863
  input: process.stdin,
21800
21864
  output: process.stdout
21801
21865
  });
21802
- var question3 = (prompt) => new Promise((resolve11) => rl2.question(prompt, resolve11));
21866
+ var question3 = (prompt) => new Promise((resolve12) => rl2.question(prompt, resolve12));
21803
21867
  var hubInitCommand = new Command29("workspace-init").description("Initialize a Hubify hub in the current directory").option("--name <name>", "Hub name (defaults to directory name)").option("--non-interactive", "Skip prompts, use defaults").action(async (options) => {
21804
21868
  const spinner = ora29();
21805
21869
  try {
@@ -22052,6 +22116,188 @@ function saveConnectState(state) {
22052
22116
  if (!fs13.existsSync(dir)) fs13.mkdirSync(dir, { recursive: true });
22053
22117
  fs13.writeFileSync(HUBIFY_STATE_FILE, JSON.stringify(state, null, 2));
22054
22118
  }
22119
+ function collectDirFiles(dirPath, extensions) {
22120
+ const files = [];
22121
+ let bundle = "";
22122
+ let totalBytes = 0;
22123
+ if (!fs13.existsSync(dirPath)) return { files, bundle, totalBytes };
22124
+ const entries = fs13.readdirSync(dirPath);
22125
+ for (const entry of entries) {
22126
+ if (!extensions.some((ext) => entry.endsWith(ext))) continue;
22127
+ const fullPath = path13.join(dirPath, entry);
22128
+ try {
22129
+ const stat = fs13.statSync(fullPath);
22130
+ const content = fs13.readFileSync(fullPath, "utf-8");
22131
+ const hash = hashContent(content);
22132
+ files.push({ path: entry, size: stat.size, hash, mtime: stat.mtimeMs });
22133
+ bundle += `
22134
+
22135
+ ### ${entry}
22136
+
22137
+ ${content}`;
22138
+ totalBytes += stat.size;
22139
+ } catch {
22140
+ }
22141
+ }
22142
+ return { files, bundle: bundle.trimStart(), totalBytes };
22143
+ }
22144
+ async function pushContextFile(filePath, contextType, hubId, machineId) {
22145
+ if (!fs13.existsSync(filePath)) return null;
22146
+ const content = fs13.readFileSync(filePath, "utf-8");
22147
+ const stat = fs13.statSync(filePath);
22148
+ const fileHash = hashContent(content);
22149
+ const client = getClient();
22150
+ const result = await client.mutation(toFunctionName(api.workspaceSync.pushWorkspaceContext), {
22151
+ hub_id: hubId,
22152
+ local_machine_id: machineId,
22153
+ context_type: contextType,
22154
+ content,
22155
+ file_hash: fileHash,
22156
+ timestamp: stat.mtimeMs,
22157
+ metadata: {
22158
+ file_count: 1,
22159
+ total_size: content.length
22160
+ }
22161
+ });
22162
+ return { status: result.status, bytes: content.length };
22163
+ }
22164
+ async function pushContextDir(dirPath, contextType, extensions, hubId, machineId) {
22165
+ const { files, bundle, totalBytes } = collectDirFiles(dirPath, extensions);
22166
+ if (files.length === 0) return null;
22167
+ const bundleHash = hashContent(bundle);
22168
+ const client = getClient();
22169
+ const result = await client.mutation(toFunctionName(api.workspaceSync.pushWorkspaceContext), {
22170
+ hub_id: hubId,
22171
+ local_machine_id: machineId,
22172
+ context_type: contextType,
22173
+ content: bundle,
22174
+ file_hash: bundleHash,
22175
+ timestamp: Date.now(),
22176
+ metadata: {
22177
+ file_count: files.length,
22178
+ total_size: totalBytes,
22179
+ files
22180
+ }
22181
+ });
22182
+ return { status: result.status, fileCount: files.length, bytes: totalBytes };
22183
+ }
22184
+ async function pullWorkspaceContextToLocal(projectRoot, hubId) {
22185
+ const client = getClient();
22186
+ let pulled = 0;
22187
+ let unchanged = 0;
22188
+ let bytes = 0;
22189
+ const contexts = await client.query(toFunctionName(api.workspaceSync.pullWorkspaceContext), {
22190
+ hub_id: hubId
22191
+ });
22192
+ for (const [contextType, data] of Object.entries(contexts)) {
22193
+ if (!data?.content) continue;
22194
+ const fileMap = {
22195
+ soul: path13.join(projectRoot, "SOUL.md"),
22196
+ memory: path13.join(projectRoot, "MEMORY.md"),
22197
+ agents: path13.join(projectRoot, "AGENTS.md")
22198
+ };
22199
+ if (fileMap[contextType]) {
22200
+ const localPath = fileMap[contextType];
22201
+ const localHash = fs13.existsSync(localPath) ? hashContent(fs13.readFileSync(localPath, "utf-8")) : null;
22202
+ if (localHash === data.file_hash) {
22203
+ unchanged++;
22204
+ continue;
22205
+ }
22206
+ const localMtime = fs13.existsSync(localPath) ? fs13.statSync(localPath).mtimeMs : 0;
22207
+ if (data.file_timestamp && localMtime > data.file_timestamp) {
22208
+ unchanged++;
22209
+ continue;
22210
+ }
22211
+ fs13.writeFileSync(localPath, data.content, "utf-8");
22212
+ bytes += data.content.length;
22213
+ pulled++;
22214
+ } else if (contextType === "memories" && data.content) {
22215
+ const memoriesDir = path13.join(projectRoot, "memory");
22216
+ if (!fs13.existsSync(memoriesDir)) {
22217
+ fs13.mkdirSync(memoriesDir, { recursive: true });
22218
+ }
22219
+ const outPath = path13.join(memoriesDir, "cloud-sync.md");
22220
+ const localHash = fs13.existsSync(outPath) ? hashContent(fs13.readFileSync(outPath, "utf-8")) : null;
22221
+ if (localHash !== data.file_hash) {
22222
+ fs13.writeFileSync(outPath, data.content, "utf-8");
22223
+ bytes += data.content.length;
22224
+ pulled++;
22225
+ } else {
22226
+ unchanged++;
22227
+ }
22228
+ }
22229
+ }
22230
+ return { pulled, unchanged, bytes };
22231
+ }
22232
+ async function pushFullWorkspaceContext(projectRoot, hubId, machineId) {
22233
+ const contextTypes = [];
22234
+ let totalFiles = 0;
22235
+ let totalBytes = 0;
22236
+ let unchanged = 0;
22237
+ const soulResult = await pushContextFile(
22238
+ path13.join(projectRoot, "SOUL.md"),
22239
+ "soul",
22240
+ hubId,
22241
+ machineId
22242
+ ).catch(() => null);
22243
+ if (soulResult) {
22244
+ if (soulResult.status === "unchanged") {
22245
+ unchanged++;
22246
+ } else {
22247
+ contextTypes.push("soul");
22248
+ totalFiles++;
22249
+ totalBytes += soulResult.bytes;
22250
+ }
22251
+ }
22252
+ const agentsResult = await pushContextFile(
22253
+ path13.join(projectRoot, "AGENTS.md"),
22254
+ "agents",
22255
+ hubId,
22256
+ machineId
22257
+ ).catch(() => null);
22258
+ if (agentsResult) {
22259
+ if (agentsResult.status === "unchanged") {
22260
+ unchanged++;
22261
+ } else {
22262
+ contextTypes.push("agents");
22263
+ totalFiles++;
22264
+ totalBytes += agentsResult.bytes;
22265
+ }
22266
+ }
22267
+ const memResult = await pushContextDir(
22268
+ path13.join(projectRoot, "memory"),
22269
+ "memories",
22270
+ [".md"],
22271
+ hubId,
22272
+ machineId
22273
+ ).catch(() => null);
22274
+ if (memResult) {
22275
+ if (memResult.status === "unchanged") {
22276
+ unchanged++;
22277
+ } else {
22278
+ contextTypes.push("memories");
22279
+ totalFiles += memResult.fileCount;
22280
+ totalBytes += memResult.bytes;
22281
+ }
22282
+ }
22283
+ const skillsResult = await pushContextDir(
22284
+ path13.join(projectRoot, "skills"),
22285
+ "skills",
22286
+ [".md", ".ts", ".js", ".yaml", ".yml"],
22287
+ hubId,
22288
+ machineId
22289
+ ).catch(() => null);
22290
+ if (skillsResult) {
22291
+ if (skillsResult.status === "unchanged") {
22292
+ unchanged++;
22293
+ } else {
22294
+ contextTypes.push("skills");
22295
+ totalFiles += skillsResult.fileCount;
22296
+ totalBytes += skillsResult.bytes;
22297
+ }
22298
+ }
22299
+ return { contextTypes, totalFiles, totalBytes, unchanged };
22300
+ }
22055
22301
  async function pushLocalMemoryToHub(memoryDir, hubId, agentId, platform2, cache) {
22056
22302
  if (!fs13.existsSync(memoryDir)) return { pushed: 0, unchanged: 0 };
22057
22303
  const client = getClient();
@@ -22144,7 +22390,7 @@ async function pullHubMemoryToLocal(memoryDir, hubId, agentId, cache) {
22144
22390
  }
22145
22391
  return { pulled };
22146
22392
  }
22147
- var createHubConnectCommand = () => new Command30("connect").description("Connect this machine to a Hubify hub and start local\u2194cloud memory sync").option("--platform <name>", "Platform name (openclaw, claude-code, cursor, etc.)").option("--hub-id <id>", "Hub ID (overrides HUB.yaml)").option("--subdomain <name>", "Hub subdomain (e.g. 'houston' for houston.hubify.com)").option("--memory-dir <path>", "Local memory directory to sync (default: ~/clawd/memory)").option("--watch", "Keep process running and watch for file changes").option("--once", "Sync once and exit (no watch loop)").action(async (options) => {
22393
+ var createHubConnectCommand = () => new Command30("connect").description("Connect this machine to a Hubify hub and start local\u2194cloud memory sync").option("--platform <name>", "Platform name (openclaw, claude-code, cursor, etc.)").option("--hub-id <id>", "Hub ID (overrides HUB.yaml)").option("--subdomain <name>", "Hub subdomain (e.g. 'houston' for houston.hubify.com)").option("--memory-dir <path>", "Local memory directory to sync (default: ~/clawd/memory)").option("--watch", "Keep process running and watch for file changes").option("--once", "Sync once and exit (no watch loop)").option("--full", "Sync full workspace context (SOUL.md, AGENTS.md, memory/, skills/) in addition to memory files").action(async (options) => {
22148
22394
  const spinner = ora30();
22149
22395
  try {
22150
22396
  console.log(chalk33.cyan("\n\u{1F517} Hubify Connect \u2014 Local \u2194 Cloud Sync\n"));
@@ -22250,6 +22496,33 @@ var createHubConnectCommand = () => new Command30("connect").description("Connec
22250
22496
  state.last_sync_at = Date.now();
22251
22497
  saveConnectState(state);
22252
22498
  console.log(chalk33.green(` \u2705 Pushed: ${pushResult.pushed} files | Pulled: ${pullResult.pulled} files | Unchanged: ${pushResult.unchanged}`));
22499
+ if (options.full) {
22500
+ console.log(chalk33.cyan("\n\u{1F4E6} Full workspace context sync...\n"));
22501
+ const projectRoot = process.cwd();
22502
+ try {
22503
+ const wsSpinner = ora30("Pushing workspace context (SOUL.md, AGENTS.md, memory/, skills/)...").start();
22504
+ const wsResult = await pushFullWorkspaceContext(projectRoot, hubId, machineId);
22505
+ wsSpinner.succeed(
22506
+ `Workspace push complete \u2014 ` + chalk33.green(`${wsResult.totalFiles} files`) + chalk33.gray(` (${(wsResult.totalBytes / 1024).toFixed(1)} KB)`) + (wsResult.unchanged > 0 ? chalk33.gray(` ${wsResult.unchanged} unchanged`) : "")
22507
+ );
22508
+ if (wsResult.contextTypes.length > 0) {
22509
+ console.log(chalk33.gray(` Context types: ${wsResult.contextTypes.join(", ")}`));
22510
+ }
22511
+ } catch (err) {
22512
+ const msg = err instanceof Error ? err.message : String(err);
22513
+ console.log(chalk33.yellow(` Warning: workspace context push failed (${msg})`));
22514
+ }
22515
+ try {
22516
+ const pullSpinner = ora30("Pulling workspace context from cloud...").start();
22517
+ const wsPull = await pullWorkspaceContextToLocal(projectRoot, hubId);
22518
+ pullSpinner.succeed(
22519
+ `Workspace pull complete \u2014 ` + chalk33.green(`${wsPull.pulled} files updated`) + chalk33.gray(` ${wsPull.unchanged} already in sync`) + (wsPull.bytes > 0 ? chalk33.gray(` (${(wsPull.bytes / 1024).toFixed(1)} KB)`) : "")
22520
+ );
22521
+ } catch (err) {
22522
+ const msg = err instanceof Error ? err.message : String(err);
22523
+ console.log(chalk33.yellow(` Warning: workspace context pull failed (${msg})`));
22524
+ }
22525
+ }
22253
22526
  if (options.once) {
22254
22527
  console.log(chalk33.gray("\n Sync complete (--once mode). Exiting.\n"));
22255
22528
  process.exit(0);
@@ -22268,6 +22541,18 @@ var createHubConnectCommand = () => new Command30("connect").description("Connec
22268
22541
  if (p.pushed > 0 || q.pulled > 0) {
22269
22542
  console.log(chalk33.gray(` [${now}] \u2191 ${p.pushed} pushed \u2193 ${q.pulled} pulled`));
22270
22543
  }
22544
+ if (options.full) {
22545
+ const projectRoot = process.cwd();
22546
+ const wsResult = await pushFullWorkspaceContext(projectRoot, hubId, machineId).catch(() => null);
22547
+ const wsPull = await pullWorkspaceContextToLocal(projectRoot, hubId).catch(() => null);
22548
+ if (wsResult && (wsResult.totalFiles > 0 || wsResult.unchanged === 0)) {
22549
+ const pulled = wsPull?.pulled ?? 0;
22550
+ const pushed = wsResult.totalFiles;
22551
+ if (pushed > 0 || pulled > 0) {
22552
+ console.log(chalk33.gray(` [${now}] workspace \u2191 ${pushed} ctx \u2193 ${pulled} ctx`));
22553
+ }
22554
+ }
22555
+ }
22271
22556
  state.last_sync_at = Date.now();
22272
22557
  saveConnectState(state);
22273
22558
  } catch (err) {
@@ -22305,9 +22590,12 @@ var createHubConnectCommand = () => new Command30("connect").description("Connec
22305
22590
  } else {
22306
22591
  console.log(chalk33.green("\n\u2705 Hub connected!\n"));
22307
22592
  console.log(chalk33.white("Next steps:"));
22308
- console.log(chalk33.cyan(" hubify connect --watch") + chalk33.gray(" \u2014 keep running and auto-sync"));
22309
- console.log(chalk33.cyan(" hubify status") + chalk33.gray(" \u2014 show sync status & connected machines"));
22310
- console.log(chalk33.cyan(" hubify connect --once") + chalk33.gray(" \u2014 sync once and exit"));
22593
+ console.log(chalk33.cyan(" hubify connect --watch") + chalk33.gray(" \u2014 keep running and auto-sync"));
22594
+ console.log(chalk33.cyan(" hubify connect --watch --full") + chalk33.gray(" \u2014 auto-sync + full workspace context"));
22595
+ console.log(chalk33.cyan(" hubify status") + chalk33.gray(" \u2014 show sync status & connected machines"));
22596
+ console.log(chalk33.cyan(" hubify sync push") + chalk33.gray(" \u2014 push workspace context once"));
22597
+ console.log(chalk33.cyan(" hubify sync pull") + chalk33.gray(" \u2014 pull workspace context from cloud"));
22598
+ console.log(chalk33.cyan(" hubify connect --once") + chalk33.gray(" \u2014 sync once and exit"));
22311
22599
  console.log();
22312
22600
  console.log(chalk33.gray(` State saved to: ${HUBIFY_STATE_FILE}`));
22313
22601
  console.log();
@@ -22681,14 +22969,14 @@ ${content}`,
22681
22969
  }
22682
22970
  return stats;
22683
22971
  }
22684
- function createApiProxy(path26 = []) {
22972
+ function createApiProxy(path27 = []) {
22685
22973
  return new Proxy(() => {
22686
22974
  }, {
22687
22975
  get(_target, prop) {
22688
- return createApiProxy([...path26, prop]);
22976
+ return createApiProxy([...path27, prop]);
22689
22977
  },
22690
22978
  apply() {
22691
- return path26.join(":");
22979
+ return path27.join(":");
22692
22980
  }
22693
22981
  });
22694
22982
  }
@@ -23307,7 +23595,7 @@ var rl3 = readline6.createInterface({
23307
23595
  input: process.stdin,
23308
23596
  output: process.stdout
23309
23597
  });
23310
- var question4 = (prompt) => new Promise((resolve11) => rl3.question(prompt, resolve11));
23598
+ var question4 = (prompt) => new Promise((resolve12) => rl3.question(prompt, resolve12));
23311
23599
  var hubCommand = new Command34("hub").description("Manage .hub manifest files for skills and agents");
23312
23600
  var initSubcommand = new Command34("init").description("Create a .hub manifest file for a skill, agent, or soul").argument("[directory]", "Directory containing the skill/agent (default: current directory)").option("--type <type>", "Type: skill, agent, or soul", "skill").option("--name <name>", "Name for the .hub file").option("--non-interactive", "Skip prompts, use defaults").action(async (directory, options) => {
23313
23601
  const spinner = ora34();
@@ -24166,6 +24454,8 @@ import chalk38 from "chalk";
24166
24454
  import ora35 from "ora";
24167
24455
  import fs19 from "fs";
24168
24456
  import path19 from "path";
24457
+ import crypto5 from "crypto";
24458
+ import os10 from "os";
24169
24459
  function readHubifyFrameworkType(workDir) {
24170
24460
  const configPath = path19.join(workDir, "hubify.json");
24171
24461
  if (!fs19.existsSync(configPath)) return null;
@@ -24384,9 +24674,406 @@ var statsCommand3 = new Command35("stats").description("Show sync statistics").a
24384
24674
  throw error;
24385
24675
  }
24386
24676
  });
24677
+ function hashContent3(content) {
24678
+ return crypto5.createHash("sha256").update(content).digest("hex");
24679
+ }
24680
+ function collectDirFiles2(dirPath, extensions) {
24681
+ const files = [];
24682
+ let bundle = "";
24683
+ let totalBytes = 0;
24684
+ if (!fs19.existsSync(dirPath)) return { files, bundle, totalBytes };
24685
+ for (const entry of fs19.readdirSync(dirPath)) {
24686
+ if (!extensions.some((ext) => entry.endsWith(ext))) continue;
24687
+ const fullPath = path19.join(dirPath, entry);
24688
+ try {
24689
+ const stat = fs19.statSync(fullPath);
24690
+ const content = fs19.readFileSync(fullPath, "utf-8");
24691
+ files.push({ path: entry, size: stat.size, hash: hashContent3(content), mtime: stat.mtimeMs });
24692
+ bundle += `
24693
+
24694
+ ### ${entry}
24695
+
24696
+ ${content}`;
24697
+ totalBytes += stat.size;
24698
+ } catch {
24699
+ }
24700
+ }
24701
+ return { files, bundle: bundle.trimStart(), totalBytes };
24702
+ }
24703
+ function resolveHubId(options) {
24704
+ if (options.hub) return options.hub;
24705
+ const stateFile = path19.join(os10.homedir(), ".hubify", "connect-state.json");
24706
+ if (fs19.existsSync(stateFile)) {
24707
+ try {
24708
+ const state = JSON.parse(fs19.readFileSync(stateFile, "utf-8"));
24709
+ if (state.hub_id) return state.hub_id;
24710
+ } catch {
24711
+ }
24712
+ }
24713
+ let dir = process.cwd();
24714
+ while (dir !== "/" && dir !== os10.homedir()) {
24715
+ const yamlPath = path19.join(dir, "HUB.yaml");
24716
+ if (fs19.existsSync(yamlPath)) {
24717
+ try {
24718
+ const lines = fs19.readFileSync(yamlPath, "utf-8").split("\n");
24719
+ for (const line of lines) {
24720
+ const m = line.match(/^\s*id\s*:\s*(.+)/);
24721
+ if (m) return m[1].trim().replace(/^["']|["']$/g, "");
24722
+ }
24723
+ } catch {
24724
+ }
24725
+ }
24726
+ dir = path19.dirname(dir);
24727
+ }
24728
+ return null;
24729
+ }
24730
+ function getMachineId2() {
24731
+ const stateFile = path19.join(os10.homedir(), ".hubify", "connect-state.json");
24732
+ if (fs19.existsSync(stateFile)) {
24733
+ try {
24734
+ const state = JSON.parse(fs19.readFileSync(stateFile, "utf-8"));
24735
+ if (state.machine_id) return state.machine_id;
24736
+ } catch {
24737
+ }
24738
+ }
24739
+ return crypto5.createHash("sha256").update(os10.hostname()).digest("hex").slice(0, 16);
24740
+ }
24741
+ var pushCommand = new Command35("push").description("Push local workspace context (SOUL.md, AGENTS.md, memory/, skills/) to Convex hub").option("--hub <id>", "Hub ID (default: from connect-state or HUB.yaml)").option("--dir <path>", "Project root to sync from (default: current directory)").option("--dry-run", "Show what would be pushed without actually pushing").action(async (options) => {
24742
+ const spinner = ora35();
24743
+ const client = getClient();
24744
+ console.log(chalk38.cyan("\n Workspace Sync \u2014 Push\n"));
24745
+ const hubId = resolveHubId(options);
24746
+ if (!hubId) {
24747
+ console.log(chalk38.red(" No hub ID found."));
24748
+ console.log(chalk38.yellow(" Run 'hubify connect' first, or pass --hub <id>"));
24749
+ process.exit(1);
24750
+ }
24751
+ const machineId = getMachineId2();
24752
+ const projectRoot = options.dir ? path19.resolve(options.dir) : process.cwd();
24753
+ console.log(chalk38.gray(` Hub: ${hubId.slice(0, 20)}...`));
24754
+ console.log(chalk38.gray(` Root: ${projectRoot}`));
24755
+ if (options.dryRun) console.log(chalk38.yellow(" Mode: dry-run (no writes)\n"));
24756
+ else console.log();
24757
+ const results = [];
24758
+ let totalConflicts = 0;
24759
+ const soulPath = path19.join(projectRoot, "SOUL.md");
24760
+ spinner.start("Checking SOUL.md...");
24761
+ if (fs19.existsSync(soulPath)) {
24762
+ try {
24763
+ const content = fs19.readFileSync(soulPath, "utf-8");
24764
+ const stat = fs19.statSync(soulPath);
24765
+ const fileHash = hashContent3(content);
24766
+ const conflictCheck = await client.query(toFunctionName(api.workspaceSync.checkSyncStatus), {
24767
+ hub_id: hubId,
24768
+ local_file_hashes: { soul: fileHash }
24769
+ });
24770
+ if (!conflictCheck.in_sync) totalConflicts += conflictCheck.conflicts.length;
24771
+ if (!options.dryRun) {
24772
+ const res = await client.mutation(toFunctionName(api.workspaceSync.pushWorkspaceContext), {
24773
+ hub_id: hubId,
24774
+ local_machine_id: machineId,
24775
+ context_type: "soul",
24776
+ content,
24777
+ file_hash: fileHash,
24778
+ timestamp: stat.mtimeMs,
24779
+ metadata: { file_count: 1, total_size: content.length }
24780
+ });
24781
+ results.push({ type: "soul (SOUL.md)", status: res.status, files: 1, bytes: content.length });
24782
+ spinner.succeed(`SOUL.md \u2014 ${res.status} (${content.length} bytes)`);
24783
+ } else {
24784
+ results.push({ type: "soul (SOUL.md)", status: "dry-run", files: 1, bytes: content.length });
24785
+ spinner.info(`SOUL.md \u2014 would push (${content.length} bytes)`);
24786
+ }
24787
+ } catch (err) {
24788
+ spinner.fail(`SOUL.md failed: ${err instanceof Error ? err.message : err}`);
24789
+ }
24790
+ } else {
24791
+ spinner.info("SOUL.md \u2014 not found, skipping");
24792
+ }
24793
+ const agentsPath = path19.join(projectRoot, "AGENTS.md");
24794
+ spinner.start("Checking AGENTS.md...");
24795
+ if (fs19.existsSync(agentsPath)) {
24796
+ try {
24797
+ const content = fs19.readFileSync(agentsPath, "utf-8");
24798
+ const stat = fs19.statSync(agentsPath);
24799
+ const fileHash = hashContent3(content);
24800
+ const conflictCheck = await client.query(toFunctionName(api.workspaceSync.checkSyncStatus), {
24801
+ hub_id: hubId,
24802
+ local_file_hashes: { agents: fileHash }
24803
+ });
24804
+ if (!conflictCheck.in_sync) totalConflicts += conflictCheck.conflicts.length;
24805
+ if (!options.dryRun) {
24806
+ const res = await client.mutation(toFunctionName(api.workspaceSync.pushWorkspaceContext), {
24807
+ hub_id: hubId,
24808
+ local_machine_id: machineId,
24809
+ context_type: "agents",
24810
+ content,
24811
+ file_hash: fileHash,
24812
+ timestamp: stat.mtimeMs,
24813
+ metadata: { file_count: 1, total_size: content.length }
24814
+ });
24815
+ results.push({ type: "agents (AGENTS.md)", status: res.status, files: 1, bytes: content.length });
24816
+ spinner.succeed(`AGENTS.md \u2014 ${res.status} (${content.length} bytes)`);
24817
+ } else {
24818
+ results.push({ type: "agents (AGENTS.md)", status: "dry-run", files: 1, bytes: content.length });
24819
+ spinner.info(`AGENTS.md \u2014 would push (${content.length} bytes)`);
24820
+ }
24821
+ } catch (err) {
24822
+ spinner.fail(`AGENTS.md failed: ${err instanceof Error ? err.message : err}`);
24823
+ }
24824
+ } else {
24825
+ spinner.info("AGENTS.md \u2014 not found, skipping");
24826
+ }
24827
+ const memoryDir = path19.join(projectRoot, "memory");
24828
+ spinner.start("Checking memory/...");
24829
+ const memData = collectDirFiles2(memoryDir, [".md"]);
24830
+ if (memData.files.length > 0) {
24831
+ try {
24832
+ const bundleHash = hashContent3(memData.bundle);
24833
+ const conflictCheck = await client.query(toFunctionName(api.workspaceSync.checkSyncStatus), {
24834
+ hub_id: hubId,
24835
+ local_file_hashes: { memories: bundleHash }
24836
+ });
24837
+ if (!conflictCheck.in_sync) totalConflicts += conflictCheck.conflicts.length;
24838
+ if (!options.dryRun) {
24839
+ const res = await client.mutation(toFunctionName(api.workspaceSync.pushWorkspaceContext), {
24840
+ hub_id: hubId,
24841
+ local_machine_id: machineId,
24842
+ context_type: "memories",
24843
+ content: memData.bundle,
24844
+ file_hash: bundleHash,
24845
+ timestamp: Date.now(),
24846
+ metadata: { file_count: memData.files.length, total_size: memData.totalBytes, files: memData.files }
24847
+ });
24848
+ results.push({ type: "memories (memory/)", status: res.status, files: memData.files.length, bytes: memData.totalBytes });
24849
+ spinner.succeed(`memory/ \u2014 ${res.status} (${memData.files.length} files, ${(memData.totalBytes / 1024).toFixed(1)} KB)`);
24850
+ } else {
24851
+ results.push({ type: "memories (memory/)", status: "dry-run", files: memData.files.length, bytes: memData.totalBytes });
24852
+ spinner.info(`memory/ \u2014 would push (${memData.files.length} files, ${(memData.totalBytes / 1024).toFixed(1)} KB)`);
24853
+ }
24854
+ } catch (err) {
24855
+ spinner.fail(`memory/ failed: ${err instanceof Error ? err.message : err}`);
24856
+ }
24857
+ } else {
24858
+ spinner.info("memory/ \u2014 no .md files found, skipping");
24859
+ }
24860
+ const skillsDir = path19.join(projectRoot, "skills");
24861
+ spinner.start("Checking skills/...");
24862
+ const skillsData = collectDirFiles2(skillsDir, [".md", ".ts", ".js", ".yaml", ".yml"]);
24863
+ if (skillsData.files.length > 0) {
24864
+ try {
24865
+ const bundleHash = hashContent3(skillsData.bundle);
24866
+ const conflictCheck = await client.query(toFunctionName(api.workspaceSync.checkSyncStatus), {
24867
+ hub_id: hubId,
24868
+ local_file_hashes: { skills: bundleHash }
24869
+ });
24870
+ if (!conflictCheck.in_sync) totalConflicts += conflictCheck.conflicts.length;
24871
+ if (!options.dryRun) {
24872
+ const res = await client.mutation(toFunctionName(api.workspaceSync.pushWorkspaceContext), {
24873
+ hub_id: hubId,
24874
+ local_machine_id: machineId,
24875
+ context_type: "skills",
24876
+ content: skillsData.bundle,
24877
+ file_hash: bundleHash,
24878
+ timestamp: Date.now(),
24879
+ metadata: { file_count: skillsData.files.length, total_size: skillsData.totalBytes, files: skillsData.files }
24880
+ });
24881
+ results.push({ type: "skills (skills/)", status: res.status, files: skillsData.files.length, bytes: skillsData.totalBytes });
24882
+ spinner.succeed(`skills/ \u2014 ${res.status} (${skillsData.files.length} files, ${(skillsData.totalBytes / 1024).toFixed(1)} KB)`);
24883
+ } else {
24884
+ results.push({ type: "skills (skills/)", status: "dry-run", files: skillsData.files.length, bytes: skillsData.totalBytes });
24885
+ spinner.info(`skills/ \u2014 would push (${skillsData.files.length} files, ${(skillsData.totalBytes / 1024).toFixed(1)} KB)`);
24886
+ }
24887
+ } catch (err) {
24888
+ spinner.fail(`skills/ failed: ${err instanceof Error ? err.message : err}`);
24889
+ }
24890
+ } else {
24891
+ spinner.info("skills/ \u2014 no files found, skipping");
24892
+ }
24893
+ const totalFiles = results.reduce((n, r) => n + r.files, 0);
24894
+ const totalBytes = results.reduce((n, r) => n + r.bytes, 0);
24895
+ const pushed = results.filter((r) => r.status !== "unchanged" && r.status !== "dry-run").length;
24896
+ const unchanged = results.filter((r) => r.status === "unchanged").length;
24897
+ console.log(chalk38.cyan("\n Push Summary\n"));
24898
+ console.log(chalk38.white(" Context types: ") + chalk38.yellow(results.length.toString()));
24899
+ console.log(chalk38.white(" Files synced: ") + chalk38.green(totalFiles.toString()));
24900
+ console.log(chalk38.white(" Bytes pushed: ") + chalk38.gray(`${(totalBytes / 1024).toFixed(1)} KB`));
24901
+ console.log(chalk38.white(" Unchanged: ") + chalk38.gray(unchanged.toString()));
24902
+ if (totalConflicts > 0) {
24903
+ console.log(chalk38.white(" Conflicts: ") + chalk38.red(totalConflicts.toString()));
24904
+ console.log(chalk38.yellow("\n Resolve conflicts with: hubify sync resolve --hub <id>"));
24905
+ }
24906
+ console.log();
24907
+ process.exit(0);
24908
+ });
24909
+ var pullCommand = new Command35("pull").description("Pull latest workspace context from Convex hub to local files").option("--hub <id>", "Hub ID (default: from connect-state or HUB.yaml)").option("--dir <path>", "Project root to write files into (default: current directory)").option("--dry-run", "Show what would be written without making changes").option("--force", "Overwrite local files even if local version is newer").action(async (options) => {
24910
+ const spinner = ora35();
24911
+ const client = getClient();
24912
+ console.log(chalk38.cyan("\n Workspace Sync \u2014 Pull\n"));
24913
+ const hubId = resolveHubId(options);
24914
+ if (!hubId) {
24915
+ console.log(chalk38.red(" No hub ID found."));
24916
+ console.log(chalk38.yellow(" Run 'hubify connect' first, or pass --hub <id>"));
24917
+ process.exit(1);
24918
+ }
24919
+ const projectRoot = options.dir ? path19.resolve(options.dir) : process.cwd();
24920
+ console.log(chalk38.gray(` Hub: ${hubId.slice(0, 20)}...`));
24921
+ console.log(chalk38.gray(` Root: ${projectRoot}`));
24922
+ if (options.dryRun) console.log(chalk38.yellow(" Mode: dry-run (no writes)\n"));
24923
+ else console.log();
24924
+ spinner.start("Fetching workspace context from cloud...");
24925
+ let contexts;
24926
+ try {
24927
+ contexts = await client.query(toFunctionName(api.workspaceSync.pullWorkspaceContext), {
24928
+ hub_id: hubId
24929
+ });
24930
+ spinner.succeed(`Fetched ${Object.keys(contexts).length} context type(s) from cloud`);
24931
+ } catch (err) {
24932
+ spinner.fail(`Pull failed: ${err instanceof Error ? err.message : err}`);
24933
+ process.exit(1);
24934
+ }
24935
+ let pulled = 0;
24936
+ let unchanged = 0;
24937
+ let conflicts = 0;
24938
+ let totalBytes = 0;
24939
+ const writtenFiles = [];
24940
+ const fileMap = {
24941
+ soul: path19.join(projectRoot, "SOUL.md"),
24942
+ memory: path19.join(projectRoot, "MEMORY.md"),
24943
+ agents: path19.join(projectRoot, "AGENTS.md")
24944
+ };
24945
+ for (const [contextType, data] of Object.entries(contexts)) {
24946
+ if (!data?.content) {
24947
+ console.log(chalk38.gray(` ${contextType}: (empty, skipping)`));
24948
+ continue;
24949
+ }
24950
+ const syncedAt = new Date(data.synced_at).toLocaleString();
24951
+ if (fileMap[contextType]) {
24952
+ const localPath = fileMap[contextType];
24953
+ const localExists = fs19.existsSync(localPath);
24954
+ const localContent = localExists ? fs19.readFileSync(localPath, "utf-8") : null;
24955
+ const localHash = localContent ? hashContent3(localContent) : null;
24956
+ if (localHash === data.file_hash) {
24957
+ console.log(chalk38.gray(` ${path19.basename(localPath)} \u2014 already in sync`));
24958
+ unchanged++;
24959
+ continue;
24960
+ }
24961
+ const localMtime = localExists ? fs19.statSync(localPath).mtimeMs : 0;
24962
+ const isConflict = localExists && !options.force && data.file_timestamp && localMtime > data.file_timestamp;
24963
+ if (isConflict) {
24964
+ console.log(
24965
+ chalk38.yellow(` ${path19.basename(localPath)} \u2014 CONFLICT`) + chalk38.gray(` (local: ${new Date(localMtime).toLocaleString()}, cloud: ${syncedAt})`)
24966
+ );
24967
+ console.log(chalk38.gray(` Use --force to overwrite local, or 'hubify sync resolve' to choose`));
24968
+ conflicts++;
24969
+ continue;
24970
+ }
24971
+ if (!options.dryRun) {
24972
+ fs19.writeFileSync(localPath, data.content, "utf-8");
24973
+ writtenFiles.push(path19.basename(localPath));
24974
+ }
24975
+ console.log(
24976
+ chalk38.green(` ${path19.basename(localPath)} \u2014 ${options.dryRun ? "would update" : "updated"}`) + chalk38.gray(` (${data.content.length} bytes, synced ${syncedAt})`)
24977
+ );
24978
+ pulled++;
24979
+ totalBytes += data.content.length;
24980
+ } else if (contextType === "memories") {
24981
+ const memoriesDir = path19.join(projectRoot, "memory");
24982
+ if (data.metadata?.files && Array.isArray(data.metadata.files)) {
24983
+ if (!options.dryRun) fs19.mkdirSync(memoriesDir, { recursive: true });
24984
+ const sections = data.content.split(/\n\n### /);
24985
+ let fileCount = 0;
24986
+ for (const section of sections) {
24987
+ const newlineIdx = section.indexOf("\n");
24988
+ if (newlineIdx === -1) continue;
24989
+ const filename = section.slice(0, newlineIdx).replace(/^### /, "");
24990
+ const fileContent = section.slice(newlineIdx + 2);
24991
+ const outPath = path19.join(memoriesDir, filename);
24992
+ const localHash = fs19.existsSync(outPath) ? hashContent3(fs19.readFileSync(outPath, "utf-8")) : null;
24993
+ const cloudHash = hashContent3(fileContent);
24994
+ if (localHash === cloudHash) {
24995
+ unchanged++;
24996
+ continue;
24997
+ }
24998
+ const localMtime = fs19.existsSync(outPath) ? fs19.statSync(outPath).mtimeMs : 0;
24999
+ const isConflict = fs19.existsSync(outPath) && !options.force && data.file_timestamp && localMtime > data.file_timestamp;
25000
+ if (isConflict) {
25001
+ conflicts++;
25002
+ continue;
25003
+ }
25004
+ if (!options.dryRun) fs19.writeFileSync(outPath, fileContent, "utf-8");
25005
+ fileCount++;
25006
+ totalBytes += fileContent.length;
25007
+ }
25008
+ console.log(
25009
+ chalk38.green(` memory/ \u2014 ${options.dryRun ? "would update" : "updated"} ${fileCount} file(s)`) + chalk38.gray(` (synced ${syncedAt})`)
25010
+ );
25011
+ pulled += fileCount;
25012
+ } else {
25013
+ const outPath = path19.join(memoriesDir, "cloud-sync.md");
25014
+ if (!options.dryRun) {
25015
+ fs19.mkdirSync(memoriesDir, { recursive: true });
25016
+ fs19.writeFileSync(outPath, data.content, "utf-8");
25017
+ }
25018
+ console.log(
25019
+ chalk38.green(` memory/cloud-sync.md \u2014 ${options.dryRun ? "would update" : "updated"}`) + chalk38.gray(` (${data.content.length} bytes)`)
25020
+ );
25021
+ pulled++;
25022
+ totalBytes += data.content.length;
25023
+ }
25024
+ } else if (contextType === "skills") {
25025
+ const skillsDir = path19.join(projectRoot, "skills");
25026
+ if (!options.dryRun) fs19.mkdirSync(skillsDir, { recursive: true });
25027
+ const sections = data.content.split(/\n\n### /);
25028
+ let fileCount = 0;
25029
+ for (const section of sections) {
25030
+ const newlineIdx = section.indexOf("\n");
25031
+ if (newlineIdx === -1) continue;
25032
+ const filename = section.slice(0, newlineIdx).replace(/^### /, "");
25033
+ const fileContent = section.slice(newlineIdx + 2);
25034
+ const outPath = path19.join(skillsDir, filename);
25035
+ const localHash = fs19.existsSync(outPath) ? hashContent3(fs19.readFileSync(outPath, "utf-8")) : null;
25036
+ if (localHash === hashContent3(fileContent)) {
25037
+ unchanged++;
25038
+ continue;
25039
+ }
25040
+ const localMtime = fs19.existsSync(outPath) ? fs19.statSync(outPath).mtimeMs : 0;
25041
+ const isConflict = fs19.existsSync(outPath) && !options.force && data.file_timestamp && localMtime > data.file_timestamp;
25042
+ if (isConflict) {
25043
+ conflicts++;
25044
+ continue;
25045
+ }
25046
+ if (!options.dryRun) fs19.writeFileSync(outPath, fileContent, "utf-8");
25047
+ fileCount++;
25048
+ totalBytes += fileContent.length;
25049
+ }
25050
+ if (fileCount > 0) {
25051
+ console.log(
25052
+ chalk38.green(` skills/ \u2014 ${options.dryRun ? "would update" : "updated"} ${fileCount} file(s)`) + chalk38.gray(` (synced ${syncedAt})`)
25053
+ );
25054
+ pulled += fileCount;
25055
+ } else {
25056
+ console.log(chalk38.gray(` skills/ \u2014 already in sync (${sections.length - 1} skills)`));
25057
+ unchanged++;
25058
+ }
25059
+ }
25060
+ }
25061
+ console.log(chalk38.cyan("\n Pull Summary\n"));
25062
+ console.log(chalk38.white(" Files updated: ") + chalk38.green(pulled.toString()));
25063
+ console.log(chalk38.white(" Bytes received: ") + chalk38.gray(`${(totalBytes / 1024).toFixed(1)} KB`));
25064
+ console.log(chalk38.white(" Unchanged: ") + chalk38.gray(unchanged.toString()));
25065
+ if (conflicts > 0) {
25066
+ console.log(chalk38.white(" Conflicts: ") + chalk38.red(conflicts.toString()));
25067
+ console.log(chalk38.yellow("\n Use --force to overwrite local files, or resolve manually."));
25068
+ }
25069
+ console.log();
25070
+ process.exit(0);
25071
+ });
24387
25072
  syncCommand.addCommand(statusCommand);
24388
25073
  syncCommand.addCommand(logsCommand);
24389
25074
  syncCommand.addCommand(statsCommand3);
25075
+ syncCommand.addCommand(pushCommand);
25076
+ syncCommand.addCommand(pullCommand);
24390
25077
 
24391
25078
  // src/commands/test.ts
24392
25079
  import { Command as Command36 } from "commander";
@@ -24547,7 +25234,7 @@ echo "=== Test Complete ==="
24547
25234
  }
24548
25235
  async function mockSandboxExecution(skillContent, skillName, criteria) {
24549
25236
  console.log(chalk39.yellow("\n \u26A0 E2B API key not configured - running mock sandbox test\n"));
24550
- await new Promise((resolve11) => setTimeout(resolve11, 1500));
25237
+ await new Promise((resolve12) => setTimeout(resolve12, 1500));
24551
25238
  const securityViolations = [];
24552
25239
  if (/curl.*\|.*sh|wget.*\|.*bash|rm\s+-rf\s+\//i.test(skillContent)) {
24553
25240
  securityViolations.push("Dangerous shell pattern detected");
@@ -25744,6 +26431,7 @@ function formatTrajectory(trajectory) {
25744
26431
  import { Command as Command40 } from "commander";
25745
26432
  import chalk43 from "chalk";
25746
26433
  import ora40 from "ora";
26434
+ import { execSync } from "child_process";
25747
26435
  function timeAgo(ts) {
25748
26436
  const delta = Date.now() - ts;
25749
26437
  if (delta < 6e4) return "just now";
@@ -26010,32 +26698,255 @@ var publishSubcommand = new Command40("publish").description("Publish research f
26010
26698
  spinner.fail(error.message || "Failed to publish findings");
26011
26699
  }
26012
26700
  });
26013
- researchCommand.addCommand(listSubcommand2);
26014
- researchCommand.addCommand(proposeSubcommand);
26015
- researchCommand.addCommand(updateSubcommand2);
26016
- researchCommand.addCommand(joinSubcommand);
26017
- researchCommand.addCommand(viewSubcommand);
26018
- researchCommand.addCommand(approveSubcommand);
26019
- researchCommand.addCommand(startSubcommand);
26020
- researchCommand.addCommand(completeSubcommand);
26021
- researchCommand.addCommand(publishSubcommand);
26022
-
26023
- // src/commands/auth.ts
26024
- import { Command as Command41 } from "commander";
26025
- import chalk44 from "chalk";
26026
- import ora41 from "ora";
26027
- import fs21 from "fs";
26028
- import path21 from "path";
26029
- import os10 from "os";
26030
- import crypto5 from "crypto";
26031
- var CREDENTIALS_DIR = path21.join(os10.homedir(), ".hubify");
26032
- var CREDENTIALS_FILE = path21.join(CREDENTIALS_DIR, "credentials.json");
26033
- function hashToken(token) {
26034
- return crypto5.createHash("sha256").update(token).digest("hex");
26035
- }
26036
- function loadCredentials() {
26701
+ var toolsCommand = new Command40("tools").description("Manage the hubify-research Python toolkit on workspaces");
26702
+ var toolsCheckSubcommand = new Command40("check").description("Validate research environment (API keys + connectivity)").option("--test", "Also run connectivity tests").action(async (options) => {
26703
+ const spinner = ora40("Checking research environment...").start();
26037
26704
  try {
26038
- if (fs21.existsSync(CREDENTIALS_FILE)) {
26705
+ const cmd = options.test ? "python3 -m hubify_research check --test" : "python3 -m hubify_research check";
26706
+ const output = execSync(cmd, { encoding: "utf-8", timeout: 3e4 });
26707
+ spinner.stop();
26708
+ console.log(output);
26709
+ } catch (error) {
26710
+ spinner.fail("Environment check failed");
26711
+ if (error.stdout) console.log(error.stdout);
26712
+ if (error.stderr) console.error(chalk43.red(error.stderr));
26713
+ }
26714
+ });
26715
+ var toolsInstallSubcommand = new Command40("install").description("Install hubify-research toolkit (pip install)").option("--dev", "Install in development mode (editable)").action(async (options) => {
26716
+ const spinner = ora40("Installing hubify-research...").start();
26717
+ try {
26718
+ const cmd = options.dev ? "pip install -e packages/sdk/python/" : "pip install hubify-research";
26719
+ const output = execSync(cmd, { encoding: "utf-8", timeout: 12e4 });
26720
+ spinner.succeed("hubify-research installed");
26721
+ console.log(chalk43.gray(output.trim().split("\n").slice(-3).join("\n")));
26722
+ } catch (error) {
26723
+ spinner.fail("Installation failed");
26724
+ if (error.stderr) console.error(chalk43.red(error.stderr));
26725
+ }
26726
+ });
26727
+ toolsCommand.addCommand(toolsCheckSubcommand);
26728
+ toolsCommand.addCommand(toolsInstallSubcommand);
26729
+ var searchSubcommand2 = new Command40("search").description("Search literature across NASA ADS, arXiv, Semantic Scholar, Perplexity").argument("<query>", "Search query").option("--category <cat>", "arXiv category filter (e.g., cs.AI, astro-ph.CO)").action(async (query, options) => {
26730
+ const spinner = ora40("Searching literature...").start();
26731
+ try {
26732
+ const env = { ...process.env, HUBIFY_SEARCH_QUERY: query };
26733
+ if (options.category) env.HUBIFY_SEARCH_CATEGORY = options.category;
26734
+ const output = execSync(
26735
+ `python3 -c "import os, json; from hubify_research.literature import search; print(json.dumps(search(os.environ['HUBIFY_SEARCH_QUERY'], max_results=5, category=os.environ.get('HUBIFY_SEARCH_CATEGORY')), indent=2, default=str))"`,
26736
+ { encoding: "utf-8", timeout: 6e4, env }
26737
+ );
26738
+ spinner.stop();
26739
+ console.log(output);
26740
+ } catch (error) {
26741
+ spinner.fail("Search failed");
26742
+ if (error.stdout) console.log(error.stdout);
26743
+ if (error.stderr) console.error(chalk43.red(error.stderr));
26744
+ }
26745
+ });
26746
+ var verifySubcommand = new Command40("verify").description("Verify a mathematical equation via Wolfram Alpha + DeepSeek R1").argument("<equation>", "Mathematical expression to verify").option("--expected <value>", "Expected result for comparison").action(async (equation, options) => {
26747
+ const spinner = ora40("Verifying equation...").start();
26748
+ try {
26749
+ const expected = options.expected || "";
26750
+ const output = execSync(
26751
+ `python3 -c "import os, json; from hubify_research.computation import verify_equation; print(json.dumps(verify_equation(os.environ['EQ'], os.environ['EX']), indent=2, default=str))"`,
26752
+ {
26753
+ encoding: "utf-8",
26754
+ timeout: 18e4,
26755
+ env: { ...process.env, EQ: equation, EX: expected }
26756
+ }
26757
+ );
26758
+ spinner.stop();
26759
+ console.log(output);
26760
+ } catch (error) {
26761
+ spinner.fail("Verification failed");
26762
+ if (error.stdout) console.log(error.stdout);
26763
+ if (error.stderr) console.error(chalk43.red(error.stderr));
26764
+ }
26765
+ });
26766
+ var gpuCommand = new Command40("gpu").description("Manage RunPod GPU pods for research");
26767
+ var gpuStatusSubcommand = new Command40("status").description("Show RunPod pod status").argument("[pod-id]", "Specific pod ID (optional)").action(async (podId) => {
26768
+ const spinner = ora40("Loading GPU status...").start();
26769
+ try {
26770
+ if (podId && !/^[a-zA-Z0-9_-]+$/.test(podId)) {
26771
+ spinner.fail("Invalid pod ID format");
26772
+ return;
26773
+ }
26774
+ const cmd = podId ? `python3 -m hubify_research gpu status ${podId}` : "python3 -m hubify_research gpu status";
26775
+ const output = execSync(cmd, { encoding: "utf-8", timeout: 3e4 });
26776
+ spinner.stop();
26777
+ console.log(output);
26778
+ } catch (error) {
26779
+ spinner.fail("Failed to get GPU status");
26780
+ if (error.stdout) console.log(error.stdout);
26781
+ if (error.stderr) console.error(chalk43.red(error.stderr));
26782
+ }
26783
+ });
26784
+ var gpuCreateSubcommand = new Command40("create").description("Create a new RunPod GPU pod").option("--name <name>", "Pod name", "hubify-research").option("--gpu <type>", "GPU type", "NVIDIA RTX 4090").action(async (options) => {
26785
+ const spinner = ora40(`Creating RunPod pod (${options.gpu})...`).start();
26786
+ try {
26787
+ const output = execSync(
26788
+ `python3 -c "import os, json; from hubify_research.gpu.runpod import create_pod; print(json.dumps(create_pod(name=os.environ['POD_NAME'], gpu_type=os.environ['GPU_TYPE']), indent=2, default=str))"`,
26789
+ { encoding: "utf-8", timeout: 6e4, env: { ...process.env, POD_NAME: options.name, GPU_TYPE: options.gpu } }
26790
+ );
26791
+ spinner.succeed("Pod created");
26792
+ console.log(output);
26793
+ } catch (error) {
26794
+ spinner.fail("Failed to create pod");
26795
+ if (error.stdout) console.log(error.stdout);
26796
+ if (error.stderr) console.error(chalk43.red(error.stderr));
26797
+ }
26798
+ });
26799
+ var gpuListSubcommand = new Command40("list").description("List available GPU types with pricing").action(async () => {
26800
+ const spinner = ora40("Loading GPU types...").start();
26801
+ try {
26802
+ const output = execSync("python3 -m hubify_research gpu gpus", {
26803
+ encoding: "utf-8",
26804
+ timeout: 3e4
26805
+ });
26806
+ spinner.stop();
26807
+ console.log(output);
26808
+ } catch (error) {
26809
+ spinner.fail("Failed to list GPUs");
26810
+ if (error.stderr) console.error(chalk43.red(error.stderr));
26811
+ }
26812
+ });
26813
+ gpuCommand.addCommand(gpuStatusSubcommand);
26814
+ gpuCommand.addCommand(gpuCreateSubcommand);
26815
+ gpuCommand.addCommand(gpuListSubcommand);
26816
+ var labsCommand = new Command40("labs").description("Manage research labs \u2014 dedicated research workspaces");
26817
+ var labsCreateSubcommand = new Command40("create").description("Create a new research lab").argument("<name>", "Lab name").option("--compute <tier>", "Compute tier: e2b, fly, or runpod", "e2b").option("--budget-usd <amount>", "Budget in USD").option("--budget-hours <hours>", "Time budget in hours").action(async (name, options) => {
26818
+ const spinner = ora40("Creating research lab...").start();
26819
+ try {
26820
+ const client = getClient();
26821
+ const result = await client.mutation(toFunctionName(api.researchLabs.createResearchLab), {
26822
+ name,
26823
+ compute_tier: options.compute,
26824
+ auto_publish_findings: true,
26825
+ budget_usd: options.budgetUsd ? parseFloat(options.budgetUsd) : void 0,
26826
+ budget_hours: options.budgetHours ? parseFloat(options.budgetHours) : void 0
26827
+ });
26828
+ spinner.succeed(`Research lab created: ${name}`);
26829
+ console.log(chalk43.gray(` Hub ID: ${result.hub_id}`));
26830
+ } catch (error) {
26831
+ spinner.fail("Failed to create research lab");
26832
+ console.error(chalk43.red(error.message));
26833
+ }
26834
+ });
26835
+ var labsSummarySubcommand = new Command40("summary").description("Get research lab summary \u2014 missions, experiments, findings").argument("<hub-id>", "Hub ID of the research lab").action(async (hubId) => {
26836
+ const spinner = ora40("Loading lab summary...").start();
26837
+ try {
26838
+ const client = getClient();
26839
+ const summary = await client.query(toFunctionName(api.researchLabs.getLabSummary), {
26840
+ hub_id: hubId
26841
+ });
26842
+ spinner.stop();
26843
+ if (!summary) {
26844
+ console.log(chalk43.yellow("Research lab not found"));
26845
+ return;
26846
+ }
26847
+ console.log(chalk43.bold(`
26848
+ ${summary.hub_name} (${summary.hub_type})`));
26849
+ console.log(chalk43.gray(" " + "\u2500".repeat(40)));
26850
+ console.log(` Missions: ${summary.missions.active} active / ${summary.missions.total} total`);
26851
+ console.log(` Experiments: ${summary.experiments.total} run ($${summary.experiments.total_cost_usd.toFixed(2)})`);
26852
+ console.log(` Best metric: ${summary.experiments.best_metric.toFixed(4)}`);
26853
+ console.log(` Findings: ${summary.knowledge.findings} published`);
26854
+ console.log(` Threads: ${summary.knowledge.total_threads} (score: ${summary.knowledge.total_score})`);
26855
+ } catch (error) {
26856
+ spinner.fail("Failed to load summary");
26857
+ console.error(chalk43.red(error.message));
26858
+ }
26859
+ });
26860
+ var labsListSubcommand = new Command40("list").description("List all research labs").action(async () => {
26861
+ const spinner = ora40("Loading research labs...").start();
26862
+ try {
26863
+ const client = getClient();
26864
+ const labs = await client.query(toFunctionName(api.researchLabs.listLabs), {});
26865
+ spinner.stop();
26866
+ if (labs.length === 0) {
26867
+ console.log(chalk43.yellow("No research labs found. Create one with: hubify research labs create <name>"));
26868
+ return;
26869
+ }
26870
+ console.log(chalk43.bold(`
26871
+ Research Labs (${labs.length})`));
26872
+ for (const lab of labs) {
26873
+ const tier = lab.research_config?.compute_tier ?? "\u2014";
26874
+ console.log(` ${chalk43.cyan(lab.name)} [${tier}] \u2014 ${lab._id}`);
26875
+ }
26876
+ } catch (error) {
26877
+ spinner.fail("Failed to list labs");
26878
+ console.error(chalk43.red(error.message));
26879
+ }
26880
+ });
26881
+ var labsToolkitSubcommand = new Command40("toolkit").description("Show research toolkit status and capabilities").action(async () => {
26882
+ const client = getClient();
26883
+ const status = await client.query(toFunctionName(api.researchLabs.getToolkitStatus), {});
26884
+ console.log(chalk43.bold(`
26885
+ ${status.toolkit} v${status.version}`));
26886
+ console.log(chalk43.gray(" " + "\u2500".repeat(40)));
26887
+ for (const mod of status.modules) {
26888
+ console.log(` ${chalk43.cyan(mod.name.padEnd(16))} ${mod.description}`);
26889
+ }
26890
+ console.log(`
26891
+ Install: ${chalk43.green(status.install)}`);
26892
+ console.log(` Check: ${chalk43.green(status.cli)}`);
26893
+ });
26894
+ labsCommand.addCommand(labsCreateSubcommand);
26895
+ labsCommand.addCommand(labsSummarySubcommand);
26896
+ labsCommand.addCommand(labsListSubcommand);
26897
+ labsCommand.addCommand(labsToolkitSubcommand);
26898
+ var findingCommand = new Command40("finding").description("Publish a research finding to knowledge threads").argument("<title>", "Finding title").option("--hub <hub-id>", "Hub ID to publish to").option("--mission <mission-id>", "Link to research mission").option("--body <body>", "Finding body (detailed description)").option("--confidence <score>", "Confidence score 0-1").option("--tags <tags>", "Comma-separated tags").action(async (title, options) => {
26899
+ const spinner = ora40("Publishing finding...").start();
26900
+ try {
26901
+ const client = getClient();
26902
+ const result = await client.mutation(toFunctionName(api.researchLabs.publishFinding), {
26903
+ hub_id: options.hub,
26904
+ title,
26905
+ body: options.body || title,
26906
+ mission_id: options.mission || void 0,
26907
+ author_agent_id: "cli-user",
26908
+ tags: options.tags ? options.tags.split(",").map((t) => t.trim()) : void 0,
26909
+ confidence: options.confidence ? parseFloat(options.confidence) : void 0
26910
+ });
26911
+ spinner.succeed("Finding published");
26912
+ console.log(chalk43.gray(` Thread ID: ${result.thread_id}`));
26913
+ } catch (error) {
26914
+ spinner.fail("Failed to publish finding");
26915
+ console.error(chalk43.red(error.message));
26916
+ }
26917
+ });
26918
+ researchCommand.addCommand(listSubcommand2);
26919
+ researchCommand.addCommand(proposeSubcommand);
26920
+ researchCommand.addCommand(updateSubcommand2);
26921
+ researchCommand.addCommand(joinSubcommand);
26922
+ researchCommand.addCommand(viewSubcommand);
26923
+ researchCommand.addCommand(approveSubcommand);
26924
+ researchCommand.addCommand(startSubcommand);
26925
+ researchCommand.addCommand(completeSubcommand);
26926
+ researchCommand.addCommand(publishSubcommand);
26927
+ researchCommand.addCommand(toolsCommand);
26928
+ researchCommand.addCommand(searchSubcommand2);
26929
+ researchCommand.addCommand(verifySubcommand);
26930
+ researchCommand.addCommand(gpuCommand);
26931
+ researchCommand.addCommand(labsCommand);
26932
+ researchCommand.addCommand(findingCommand);
26933
+
26934
+ // src/commands/auth.ts
26935
+ import { Command as Command41 } from "commander";
26936
+ import chalk44 from "chalk";
26937
+ import ora41 from "ora";
26938
+ import fs21 from "fs";
26939
+ import path21 from "path";
26940
+ import os11 from "os";
26941
+ import crypto6 from "crypto";
26942
+ var CREDENTIALS_DIR = path21.join(os11.homedir(), ".hubify");
26943
+ var CREDENTIALS_FILE = path21.join(CREDENTIALS_DIR, "credentials.json");
26944
+ function hashToken(token) {
26945
+ return crypto6.createHash("sha256").update(token).digest("hex");
26946
+ }
26947
+ function loadCredentials() {
26948
+ try {
26949
+ if (fs21.existsSync(CREDENTIALS_FILE)) {
26039
26950
  const raw = fs21.readFileSync(CREDENTIALS_FILE, "utf-8");
26040
26951
  return JSON.parse(raw);
26041
26952
  }
@@ -26919,7 +27830,7 @@ ingestCommand.command("logs").description("View ingest operation logs").option("
26919
27830
  import { Command as Command46 } from "commander";
26920
27831
  import chalk48 from "chalk";
26921
27832
  import ora45 from "ora";
26922
- var labsCommand = new Command46("labs").description("Hubify Labs \u2014 autonomous experiment swarms and research DAGs").addCommand(labsStatusCommand()).addCommand(labsMissionCommand()).addCommand(labsFrontierCommand()).addCommand(labsDagCommand()).addCommand(labsBestPathCommand()).addCommand(labsChannelsCommand()).addCommand(labsLaunchCommand()).addCommand(labsLaunchResearchCommand()).addCommand(labsListExperimentableCommand()).addCommand(labsSuggestCommand());
27833
+ var labsCommand2 = new Command46("labs").description("Hubify Labs \u2014 autonomous experiment swarms and research DAGs").addCommand(labsStatusCommand()).addCommand(labsMissionCommand()).addCommand(labsFrontierCommand()).addCommand(labsDagCommand()).addCommand(labsBestPathCommand()).addCommand(labsChannelsCommand()).addCommand(labsLaunchCommand()).addCommand(labsLaunchResearchCommand()).addCommand(labsListExperimentableCommand()).addCommand(labsSuggestCommand());
26923
27834
  function labsStatusCommand() {
26924
27835
  return new Command46("status").description("Show active experiment missions").option("--limit <n>", "Max missions to show", "10").option("--json", "Output as JSON").action(async (options) => {
26925
27836
  const spinner = ora45("Fetching experiment missions...").start();
@@ -27106,16 +28017,16 @@ function labsBestPathCommand() {
27106
28017
  const spinner = ora45("Tracing best path...").start();
27107
28018
  try {
27108
28019
  const client = getClient();
27109
- const path26 = await client.query(
28020
+ const path27 = await client.query(
27110
28021
  toFunctionName(api.experimentDag.getBestPath),
27111
28022
  { mission_id: missionId }
27112
28023
  );
27113
28024
  spinner.stop();
27114
28025
  if (options.json) {
27115
- console.log(JSON.stringify(path26, null, 2));
28026
+ console.log(JSON.stringify(path27, null, 2));
27116
28027
  return;
27117
28028
  }
27118
- const nodes = path26;
28029
+ const nodes = path27;
27119
28030
  if (nodes.length === 0) {
27120
28031
  console.log(chalk48.dim("\n No best path found.\n"));
27121
28032
  return;
@@ -28170,57 +29081,78 @@ function typeIcon(type) {
28170
29081
  return chalk55.blue("FINDING");
28171
29082
  case "technique":
28172
29083
  return chalk55.white("TECHNIQUE");
29084
+ case "experiment_result":
29085
+ return chalk55.yellow("EXPERIMENT");
29086
+ case "failure_lesson":
29087
+ return chalk55.red("FAILURE");
28173
29088
  case "failure-lesson":
28174
29089
  return chalk55.red("FAILURE");
28175
29090
  default:
28176
29091
  return chalk55.dim(type.toUpperCase());
28177
29092
  }
28178
29093
  }
29094
+ function toBackendType(type) {
29095
+ const map = {
29096
+ "failure-lesson": "failure_lesson",
29097
+ "experiment-result": "experiment_result"
29098
+ };
29099
+ return map[type] ?? type;
29100
+ }
28179
29101
  function collectiveFeedCommand() {
28180
- return new Command52("feed").description("Show the global collective intelligence feed").option("--limit <n>", "Max entries", "50").option("--type <type>", "Filter: learning, evolution, improvement, all", "all").option("--json", "Output as JSON").action(async (options) => {
29102
+ return new Command52("feed").description("Show the global collective intelligence feed").option("--limit <n>", "Max entries", "50").option("--type <type>", "Filter: learning, pattern, finding, technique, experiment-result, failure-lesson, all", "all").option("--json", "Output as JSON").action(async (options) => {
28181
29103
  const spinner = ora51("Pulling collective intelligence feed...").start();
28182
29104
  try {
28183
29105
  const client = getClient();
28184
- const [feed, recentLearnings] = await Promise.all([
29106
+ const limit = parseInt(options.limit);
29107
+ const collectiveArgs = { limit };
29108
+ if (options.type !== "all") {
29109
+ collectiveArgs.type = toBackendType(options.type);
29110
+ }
29111
+ const [collectiveFeed, singularityFeed] = await Promise.all([
28185
29112
  client.query(
28186
- toFunctionName(api.singularity.getIntelligenceFeed),
28187
- { limit: parseInt(options.limit), type: options.type }
29113
+ toFunctionName(api.collective.getFeed),
29114
+ collectiveArgs
28188
29115
  ),
28189
29116
  client.query(
28190
- toFunctionName(api.learning.getRecentEnriched),
28191
- { limit: parseInt(options.limit) }
28192
- )
29117
+ toFunctionName(api.singularity.getIntelligenceFeed),
29118
+ { limit, type: options.type }
29119
+ ).catch(() => [])
29120
+ // graceful fallback if singularity unavailable
28193
29121
  ]);
28194
29122
  spinner.stop();
29123
+ const collectiveEntries = collectiveFeed;
29124
+ const singularityEntries = singularityFeed;
28195
29125
  if (options.json) {
28196
- console.log(JSON.stringify({ feed, recentLearnings }, null, 2));
29126
+ console.log(JSON.stringify({ collective: collectiveEntries, singularity: singularityEntries }, null, 2));
28197
29127
  return;
28198
29128
  }
28199
- const feedEntries = feed;
28200
- const learningEntries = recentLearnings;
28201
29129
  const unified = [];
28202
- for (const entry of feedEntries) {
29130
+ for (const entry of collectiveEntries) {
28203
29131
  unified.push({
28204
29132
  type: entry.type ?? "learning",
28205
- title: entry.title ?? entry.skill_name ?? "\u2014",
28206
- detail: entry.details ?? entry.description ?? "",
28207
- source: entry.agent_id ?? "network",
28208
- timestamp: entry.timestamp ?? entry._creationTime ?? Date.now()
29133
+ title: entry.title ?? "\u2014",
29134
+ detail: entry.content ?? "",
29135
+ source: entry.source_agent_id ?? "collective",
29136
+ timestamp: entry.created_at ?? entry._creationTime ?? Date.now(),
29137
+ origin: "collective"
28209
29138
  });
28210
29139
  }
28211
- for (const log of learningEntries) {
28212
- const type = log.improvement ? "improvement" : log.result === "fail" ? "failure-lesson" : "learning";
28213
- if (options.type !== "all" && options.type !== type) continue;
29140
+ for (const entry of singularityEntries) {
29141
+ const isDupe = unified.some(
29142
+ (u) => u.title === (entry.title ?? entry.skill_name) && Math.abs(u.timestamp - (entry.timestamp ?? 0)) < 1e3
29143
+ );
29144
+ if (isDupe) continue;
28214
29145
  unified.push({
28215
- type,
28216
- title: log.skillName ?? log.skill_name ?? "unknown",
28217
- detail: log.improvement ?? log.note ?? log.error_message ?? `${log.result} execution`,
28218
- source: log.agent_id ?? "unknown",
28219
- timestamp: log._creationTime ?? Date.now()
29146
+ type: entry.type ?? "learning",
29147
+ title: entry.title ?? entry.skill_name ?? "\u2014",
29148
+ detail: entry.details ?? entry.description ?? "",
29149
+ source: entry.agent_id ?? "network",
29150
+ timestamp: entry.timestamp ?? entry._creationTime ?? Date.now(),
29151
+ origin: "singularity"
28220
29152
  });
28221
29153
  }
28222
29154
  unified.sort((a, b) => b.timestamp - a.timestamp);
28223
- const display = unified.slice(0, parseInt(options.limit));
29155
+ const display = unified.slice(0, limit);
28224
29156
  if (display.length === 0) {
28225
29157
  console.log(chalk55.dim("\n No collective intelligence entries found.\n"));
28226
29158
  return;
@@ -28237,7 +29169,7 @@ function collectiveFeedCommand() {
28237
29169
  const detail = entry.detail.length > 120 ? entry.detail.slice(0, 117) + "..." : entry.detail;
28238
29170
  console.log(` ${chalk55.dim(detail)}`);
28239
29171
  }
28240
- console.log(` ${chalk55.dim("source:")} ${chalk55.dim(entry.source)}`);
29172
+ console.log(` ${chalk55.dim("source:")} ${chalk55.dim(entry.source)} ${chalk55.dim("via")} ${chalk55.dim(entry.origin)}`);
28241
29173
  console.log();
28242
29174
  }
28243
29175
  } catch (error) {
@@ -28247,8 +29179,8 @@ function collectiveFeedCommand() {
28247
29179
  });
28248
29180
  }
28249
29181
  function collectiveShareCommand() {
28250
- return new Command52("share").description("Share an insight to the collective intelligence").argument("<type>", "Insight type: learning, pattern, finding, technique, failure-lesson").argument("<content>", "The insight content to share").option("--skill <name>", "Link to a skill name").option("--confidence <n>", "Confidence score 0-1", "0.7").option("--tags <tags>", "Comma-separated tags").option("--context <ctx>", "What you were doing when you learned this").option("--agent <id>", "Agent ID (defaults to cli-agent)").option("--json", "Output as JSON").action(async (type, content, options) => {
28251
- const validTypes = ["learning", "pattern", "finding", "technique", "failure-lesson"];
29182
+ return new Command52("share").description("Share an insight to the collective intelligence").argument("<type>", "Insight type: learning, pattern, finding, technique, experiment-result, failure-lesson").argument("<content>", "The insight content to share").option("--skill <name>", "Link to a skill name").option("--confidence <n>", "Confidence score 0-1", "0.7").option("--tags <tags>", "Comma-separated tags").option("--context <ctx>", "What you were doing when you learned this").option("--agent <id>", "Agent ID (defaults to cli-agent)").option("--workspace <id>", "Workspace ID").option("--json", "Output as JSON").action(async (type, content, options) => {
29183
+ const validTypes = ["learning", "pattern", "finding", "technique", "experiment-result", "failure-lesson"];
28252
29184
  if (!validTypes.includes(type)) {
28253
29185
  console.log(chalk55.red(`
28254
29186
  Invalid type: ${type}`));
@@ -28259,32 +29191,23 @@ function collectiveShareCommand() {
28259
29191
  const spinner = ora51("Sharing insight to collective...").start();
28260
29192
  try {
28261
29193
  const client = getClient();
28262
- const skillName = options.skill ?? "general";
28263
29194
  const agentId = options.agent ?? "cli-agent";
28264
29195
  const confidence = parseFloat(options.confidence);
28265
- const resultMap = {
28266
- "learning": "success",
28267
- "pattern": "success",
28268
- "finding": "success",
28269
- "technique": "success",
28270
- "failure-lesson": "fail"
28271
- };
28272
29196
  const tags = options.tags ? options.tags.split(",").map((t) => t.trim()) : [];
28273
- const contextNote = options.context ? `
28274
- [context] ${options.context}` : "";
28275
- const tagNote = tags.length > 0 ? `
28276
- [tags] ${tags.join(", ")}` : "";
28277
- const fullNote = `[${type}] ${content}${contextNote}${tagNote}`;
29197
+ const title = content.length > 80 ? content.slice(0, 77) + "..." : content;
29198
+ const backendType = toBackendType(type);
28278
29199
  const result = await client.mutation(
28279
- toFunctionName(api.learning.report),
29200
+ toFunctionName(api.collective.shareInsight),
28280
29201
  {
28281
- skill_name: skillName,
28282
- skill_version: "latest",
28283
- agent_id: agentId,
28284
- platform: "cli",
28285
- result: resultMap[type],
28286
- note: fullNote,
28287
- improvement: type === "pattern" || type === "technique" ? content : void 0
29202
+ type: backendType,
29203
+ title,
29204
+ content,
29205
+ context: options.context,
29206
+ source_agent_id: agentId,
29207
+ source_workspace_id: options.workspace,
29208
+ source_skill_name: options.skill,
29209
+ tags: tags.length > 0 ? tags : void 0,
29210
+ confidence
28288
29211
  }
28289
29212
  );
28290
29213
  spinner.stop();
@@ -28293,10 +29216,13 @@ function collectiveShareCommand() {
28293
29216
  return;
28294
29217
  }
28295
29218
  console.log(chalk55.bold("\n Insight shared to collective"));
29219
+ console.log(` ${chalk55.dim("id:")} ${result?.id ?? "\u2014"}`);
28296
29220
  console.log(` ${chalk55.dim("type:")} ${typeIcon(type)}`);
28297
- console.log(` ${chalk55.dim("skill:")} ${skillName}`);
29221
+ if (options.skill) {
29222
+ console.log(` ${chalk55.dim("skill:")} ${options.skill}`);
29223
+ }
28298
29224
  console.log(` ${chalk55.dim("confidence:")} ${confidence}`);
28299
- console.log(` ${chalk55.dim("content:")} ${content.length > 80 ? content.slice(0, 77) + "..." : content}`);
29225
+ console.log(` ${chalk55.dim("content:")} ${title}`);
28300
29226
  if (tags.length > 0) {
28301
29227
  console.log(` ${chalk55.dim("tags:")} ${tags.join(", ")}`);
28302
29228
  }
@@ -28309,8 +29235,6 @@ function collectiveShareCommand() {
28309
29235
  } catch (error) {
28310
29236
  spinner.fail("Failed to share insight");
28311
29237
  console.error(chalk55.red(error.message));
28312
- console.log(chalk55.dim("\n Make sure the skill exists in the registry."));
28313
- console.log(chalk55.dim(" Use --skill <name> to link to a specific skill.\n"));
28314
29238
  }
28315
29239
  });
28316
29240
  }
@@ -28319,28 +29243,50 @@ function collectiveTrendingCommand() {
28319
29243
  const spinner = ora51("Analyzing network trends...").start();
28320
29244
  try {
28321
29245
  const client = getClient();
28322
- const [trending, feed] = await Promise.all([
29246
+ const days = parseInt(options.days);
29247
+ const limit = parseInt(options.limit);
29248
+ const [collectiveTrending, singularityTrending] = await Promise.all([
28323
29249
  client.query(
28324
- toFunctionName(api.singularity.getTrendingSkills),
28325
- { days: parseInt(options.days), limit: parseInt(options.limit) }
29250
+ toFunctionName(api.collective.getTrending),
29251
+ { days, limit }
28326
29252
  ),
28327
29253
  client.query(
28328
- toFunctionName(api.singularity.getIntelligenceFeed),
28329
- { limit: 10, type: "all" }
28330
- )
29254
+ toFunctionName(api.singularity.getTrendingSkills),
29255
+ { days, limit }
29256
+ ).catch(() => [])
28331
29257
  ]);
28332
29258
  spinner.stop();
29259
+ const insights = collectiveTrending;
29260
+ const skills = singularityTrending;
28333
29261
  if (options.json) {
28334
- console.log(JSON.stringify({ trending, feed }, null, 2));
29262
+ console.log(JSON.stringify({ insights, skills }, null, 2));
28335
29263
  return;
28336
29264
  }
28337
- const skills = trending;
28338
- const feedEntries = feed;
28339
29265
  console.log(chalk55.bold(`
28340
- Trending in the Collective (last ${options.days} days)
29266
+ Trending in the Collective (last ${days} days)
28341
29267
  `));
29268
+ if (insights.length > 0) {
29269
+ console.log(chalk55.dim(" --- Top validated insights ---\n"));
29270
+ for (let i = 0; i < insights.length; i++) {
29271
+ const ins = insights[i];
29272
+ const impact = (ins.validations ?? 0) + (ins.applications ?? 0);
29273
+ const time = relativeTime(ins.created_at ?? ins._creationTime ?? Date.now());
29274
+ console.log(
29275
+ ` ${chalk55.dim(`${(i + 1).toString().padStart(2)}.`)} ${typeIcon(ins.type)} ${chalk55.bold(ins.title ?? "\u2014")} ${chalk55.dim(time)}`
29276
+ );
29277
+ console.log(
29278
+ ` ${ins.validations ?? 0} validations ${ins.applications ?? 0} applications impact: ${impact} conf: ${((ins.confidence ?? 0) * 100).toFixed(0)}%`
29279
+ );
29280
+ if (ins.content) {
29281
+ const content = ins.content.length > 100 ? ins.content.slice(0, 97) + "..." : ins.content;
29282
+ console.log(` ${chalk55.dim(content)}`);
29283
+ }
29284
+ }
29285
+ } else {
29286
+ console.log(chalk55.dim(" No trending insights in the last " + days + " days."));
29287
+ }
28342
29288
  if (skills.length > 0) {
28343
- console.log(chalk55.dim(" --- Skills the network is learning about ---\n"));
29289
+ console.log(chalk55.dim("\n --- Trending skills (network-wide) ---\n"));
28344
29290
  for (let i = 0; i < skills.length; i++) {
28345
29291
  const s = skills[i];
28346
29292
  const rate = (s.success_rate * 100).toFixed(0);
@@ -28352,20 +29298,6 @@ function collectiveTrendingCommand() {
28352
29298
  ` ${s.executions} executions ${bar} ${rate}% success ${s.unique_agents} agents`
28353
29299
  );
28354
29300
  }
28355
- } else {
28356
- console.log(chalk55.dim(" No trending skills in the last " + options.days + " days."));
28357
- }
28358
- if (feedEntries.length > 0) {
28359
- console.log(chalk55.dim("\n --- Active intelligence ---\n"));
28360
- for (const entry of feedEntries) {
28361
- const time = relativeTime(entry.timestamp ?? entry._creationTime ?? Date.now());
28362
- console.log(
28363
- ` ${typeIcon(entry.type ?? "learning")} ${chalk55.bold(entry.title ?? "\u2014")} ${chalk55.dim(time)}`
28364
- );
28365
- if (entry.details) {
28366
- console.log(` ${chalk55.dim(entry.details)}`);
28367
- }
28368
- }
28369
29301
  }
28370
29302
  console.log();
28371
29303
  } catch (error) {
@@ -28375,57 +29307,34 @@ function collectiveTrendingCommand() {
28375
29307
  });
28376
29308
  }
28377
29309
  function collectiveSearchCommand() {
28378
- return new Command52("search").description("Search collective knowledge").argument("<query>", "Search query").option("--limit <n>", "Max results", "20").option("--json", "Output as JSON").action(async (query, options) => {
29310
+ return new Command52("search").description("Search collective knowledge").argument("<query>", "Search query").option("--type <type>", "Filter by type").option("--limit <n>", "Max results", "20").option("--json", "Output as JSON").action(async (query, options) => {
28379
29311
  const spinner = ora51(`Searching collective for "${query}"...`).start();
28380
29312
  try {
28381
29313
  const client = getClient();
28382
29314
  const limit = parseInt(options.limit);
28383
29315
  let results = [];
28384
- let source = "knowledge";
29316
+ let source = "collective";
28385
29317
  try {
28386
- const knowledgeResults = await client.query(
28387
- toFunctionName(api.hubKnowledge.searchAll),
28388
- { query, limit }
29318
+ const searchArgs = { query, limit };
29319
+ if (options.type) {
29320
+ searchArgs.type = toBackendType(options.type);
29321
+ }
29322
+ const collectiveResults = await client.query(
29323
+ toFunctionName(api.collective.search),
29324
+ searchArgs
28389
29325
  );
28390
- results = knowledgeResults;
29326
+ results = collectiveResults;
28391
29327
  } catch {
28392
- source = "feed";
28393
- const [feed, learnings] = await Promise.all([
28394
- client.query(
28395
- toFunctionName(api.singularity.getIntelligenceFeed),
28396
- { limit, type: "all" }
28397
- ),
28398
- client.query(
28399
- toFunctionName(api.learning.getRecentEnriched),
28400
- { limit }
28401
- )
28402
- ]);
28403
- const feedEntries = feed;
28404
- const learningEntries = learnings;
28405
- const queryLower = query.toLowerCase();
28406
- for (const entry of feedEntries) {
28407
- const text = `${entry.title ?? ""} ${entry.description ?? ""} ${entry.details ?? ""}`.toLowerCase();
28408
- if (text.includes(queryLower)) {
28409
- results.push({
28410
- type: entry.type ?? "learning",
28411
- title: entry.title ?? "\u2014",
28412
- content: entry.description ?? entry.details ?? "",
28413
- timestamp: entry.timestamp,
28414
- source: "feed"
28415
- });
28416
- }
28417
- }
28418
- for (const log of learningEntries) {
28419
- const text = `${log.skillName ?? ""} ${log.note ?? ""} ${log.improvement ?? ""} ${log.error_message ?? ""}`.toLowerCase();
28420
- if (text.includes(queryLower)) {
28421
- results.push({
28422
- type: log.improvement ? "improvement" : "learning",
28423
- title: log.skillName ?? log.skill_name ?? "\u2014",
28424
- content: log.note ?? log.improvement ?? log.error_message ?? "",
28425
- timestamp: log._creationTime,
28426
- source: log.agent_id ?? "unknown"
28427
- });
28428
- }
29328
+ source = "knowledge";
29329
+ try {
29330
+ const knowledgeResults = await client.query(
29331
+ toFunctionName(api.hubKnowledge.searchAll),
29332
+ { query, limit }
29333
+ );
29334
+ results = knowledgeResults;
29335
+ } catch {
29336
+ source = "none";
29337
+ results = [];
28429
29338
  }
28430
29339
  }
28431
29340
  spinner.stop();
@@ -28443,7 +29352,7 @@ function collectiveSearchCommand() {
28443
29352
  Collective Search: "${query}" (${results.length} results, via ${source})
28444
29353
  `));
28445
29354
  for (const r of results.slice(0, limit)) {
28446
- const time = r.timestamp ? relativeTime(r.timestamp) : "";
29355
+ const time = r.created_at ?? r.timestamp ?? r._creationTime ? relativeTime(r.created_at ?? r.timestamp ?? r._creationTime) : "";
28447
29356
  const rType = r.type ?? r.kind ?? "knowledge";
28448
29357
  console.log(
28449
29358
  ` ${typeIcon(rType)} ${chalk55.bold(r.title ?? r.name ?? "\u2014")} ${chalk55.dim(time)}`
@@ -28453,8 +29362,11 @@ function collectiveSearchCommand() {
28453
29362
  const truncated = content.length > 120 ? content.slice(0, 117) + "..." : content;
28454
29363
  console.log(` ${chalk55.dim(truncated)}`);
28455
29364
  }
28456
- if (r.source) {
28457
- console.log(` ${chalk55.dim("source:")} ${r.source}`);
29365
+ if (r.source_agent_id ?? r.source) {
29366
+ console.log(` ${chalk55.dim("source:")} ${r.source_agent_id ?? r.source}`);
29367
+ }
29368
+ if (r.tags && r.tags.length > 0) {
29369
+ console.log(` ${chalk55.dim("tags:")} ${r.tags.join(", ")}`);
28458
29370
  }
28459
29371
  console.log();
28460
29372
  }
@@ -28465,105 +29377,96 @@ function collectiveSearchCommand() {
28465
29377
  });
28466
29378
  }
28467
29379
  function collectiveInsightsCommand() {
28468
- return new Command52("insights").description("Aggregated view: top patterns, common failures, most validated learnings").option("--days <n>", "Lookback period in days", "30").option("--json", "Output as JSON").action(async (options) => {
29380
+ return new Command52("insights").description("Aggregated view: breakdown by type, validations, applications, unique agents/workspaces").option("--days <n>", "Lookback period for trending", "30").option("--json", "Output as JSON").action(async (options) => {
28469
29381
  const spinner = ora51("Aggregating collective insights...").start();
28470
29382
  try {
28471
29383
  const client = getClient();
28472
29384
  const days = parseInt(options.days);
28473
- const [trending, feed, recentLearnings] = await Promise.all([
29385
+ const [stats, trending] = await Promise.all([
28474
29386
  client.query(
28475
- toFunctionName(api.singularity.getTrendingSkills),
28476
- { days, limit: 50 }
28477
- ),
28478
- client.query(
28479
- toFunctionName(api.singularity.getIntelligenceFeed),
28480
- { limit: 10, type: "all" }
29387
+ toFunctionName(api.collective.getStats),
29388
+ {}
28481
29389
  ),
28482
29390
  client.query(
28483
- toFunctionName(api.learning.getRecentEnriched),
28484
- { limit: 50 }
29391
+ toFunctionName(api.collective.getTrending),
29392
+ { days, limit: 50 }
28485
29393
  )
28486
29394
  ]);
28487
29395
  spinner.stop();
28488
- const skills = trending;
28489
- const feedEntries = feed;
28490
- const learnings = recentLearnings;
29396
+ const s = stats;
29397
+ const trendingInsights = trending;
28491
29398
  if (options.json) {
28492
- console.log(JSON.stringify({ trending: skills, feed: feedEntries, learnings }, null, 2));
29399
+ console.log(JSON.stringify({ stats: s, trending: trendingInsights }, null, 2));
28493
29400
  return;
28494
29401
  }
28495
29402
  console.log(chalk55.bold(`
28496
- Collective Insights (last ${days} days)
29403
+ Collective Intelligence Overview
28497
29404
  `));
28498
- const topSkills = skills.filter((s) => s.success_rate >= 0.8).slice(0, 5);
28499
- if (topSkills.length > 0) {
28500
- console.log(chalk55.dim(" --- Most validated skills ---\n"));
28501
- for (const s of topSkills) {
28502
- const rate = (s.success_rate * 100).toFixed(0);
29405
+ const byType = s.by_type ?? {};
29406
+ const typeEntries = Object.entries(byType).sort((a, b) => b[1] - a[1]);
29407
+ if (typeEntries.length > 0) {
29408
+ console.log(chalk55.dim(" --- Insight breakdown by type ---\n"));
29409
+ for (const [typeName, count] of typeEntries) {
29410
+ const bar = miniBar(Math.min(count / Math.max(s.total_insights, 1), 1));
28503
29411
  console.log(
28504
- ` ${chalk55.green("+")} ${chalk55.bold(s.name)} \u2014 ${rate}% success across ${s.unique_agents} agents (${s.executions} runs)`
29412
+ ` ${typeIcon(typeName)} ${chalk55.bold(String(count).padStart(5))} ${bar} ${typeName}`
28505
29413
  );
28506
29414
  }
28507
29415
  console.log();
28508
29416
  }
28509
- const failures = learnings.filter((l) => l.result === "fail");
28510
- const failureSkills = {};
28511
- for (const f of failures) {
28512
- const name = f.skillName ?? f.skill_name ?? "unknown";
28513
- failureSkills[name] = (failureSkills[name] ?? 0) + 1;
28514
- }
28515
- const topFailures = Object.entries(failureSkills).sort((a, b) => b[1] - a[1]).slice(0, 5);
28516
- if (topFailures.length > 0) {
28517
- console.log(chalk55.dim(" --- Common failure points ---\n"));
28518
- for (const [name, count] of topFailures) {
29417
+ console.log(chalk55.dim(" --- Network summary ---\n"));
29418
+ console.log(` ${chalk55.dim("total insights:")} ${s.total_insights ?? 0}`);
29419
+ console.log(` ${chalk55.dim("total validations:")} ${s.total_validations ?? 0}`);
29420
+ console.log(` ${chalk55.dim("total applications:")} ${s.total_applications ?? 0}`);
29421
+ console.log(` ${chalk55.dim("unique agents:")} ${s.unique_agents ?? 0}`);
29422
+ console.log(` ${chalk55.dim("unique workspaces:")} ${s.unique_workspaces ?? 0}`);
29423
+ console.log();
29424
+ if (trendingInsights.length > 0) {
29425
+ console.log(chalk55.dim(` --- Top trending (last ${days} days) ---
29426
+ `));
29427
+ for (let i = 0; i < Math.min(trendingInsights.length, 10); i++) {
29428
+ const ins = trendingInsights[i];
29429
+ const impact = (ins.validations ?? 0) + (ins.applications ?? 0);
29430
+ const time = relativeTime(ins.created_at ?? ins._creationTime ?? Date.now());
29431
+ console.log(
29432
+ ` ${chalk55.dim(`${(i + 1).toString().padStart(2)}.`)} ${typeIcon(ins.type)} ${chalk55.bold(ins.title ?? "\u2014")} ${chalk55.dim(time)}`
29433
+ );
28519
29434
  console.log(
28520
- ` ${chalk55.red("x")} ${chalk55.bold(name)} \u2014 ${count} failure${count > 1 ? "s" : ""}`
29435
+ ` ${ins.validations ?? 0} validations, ${ins.applications ?? 0} applications, impact: ${impact}`
28521
29436
  );
28522
- const recentFail = failures.find((f) => (f.skillName ?? f.skill_name) === name);
28523
- if (recentFail?.error_message) {
28524
- const err = recentFail.error_message.length > 100 ? recentFail.error_message.slice(0, 97) + "..." : recentFail.error_message;
28525
- console.log(` ${chalk55.dim(err)}`);
29437
+ if (ins.content) {
29438
+ const content = ins.content.length > 100 ? ins.content.slice(0, 97) + "..." : ins.content;
29439
+ console.log(` ${chalk55.dim(content)}`);
28526
29440
  }
28527
29441
  }
28528
29442
  console.log();
28529
29443
  }
28530
- const improvements = learnings.filter((l) => l.improvement);
28531
- if (improvements.length > 0) {
28532
- console.log(chalk55.dim(" --- Recent improvement suggestions ---\n"));
28533
- for (const imp of improvements.slice(0, 5)) {
28534
- const skill = imp.skillName ?? imp.skill_name ?? "\u2014";
28535
- const text = imp.improvement.length > 100 ? imp.improvement.slice(0, 97) + "..." : imp.improvement;
28536
- const time = relativeTime(imp._creationTime ?? Date.now());
29444
+ const validated = [...trendingInsights].sort((a, b) => (b.validations ?? 0) - (a.validations ?? 0)).slice(0, 5);
29445
+ const hasValidated = validated.some((v) => (v.validations ?? 0) > 0);
29446
+ if (hasValidated) {
29447
+ console.log(chalk55.dim(" --- Most validated ---\n"));
29448
+ for (const v of validated) {
29449
+ if ((v.validations ?? 0) === 0) continue;
28537
29450
  console.log(
28538
- ` ${chalk55.cyan(">")} ${chalk55.bold(skill)} ${chalk55.dim(time)}`
29451
+ ` ${chalk55.green("+")} ${chalk55.bold(v.title ?? "\u2014")} \u2014 ${v.validations} validations from ${v.source_agent_id ?? "network"}`
28539
29452
  );
28540
- console.log(` ${chalk55.dim(text)}`);
28541
29453
  }
28542
29454
  console.log();
28543
29455
  }
28544
- if (feedEntries.length > 0) {
28545
- console.log(chalk55.dim(" --- Active experiments ---\n"));
28546
- for (const entry of feedEntries.slice(0, 5)) {
29456
+ const failures = trendingInsights.filter((i) => i.type === "failure_lesson");
29457
+ if (failures.length > 0) {
29458
+ console.log(chalk55.dim(" --- Recent failure lessons ---\n"));
29459
+ for (const f of failures.slice(0, 5)) {
28547
29460
  console.log(
28548
- ` ${typeIcon(entry.type ?? "learning")} ${chalk55.bold(entry.title ?? "\u2014")}`
29461
+ ` ${chalk55.red("x")} ${chalk55.bold(f.title ?? "\u2014")}`
28549
29462
  );
28550
- if (entry.details) {
28551
- console.log(` ${chalk55.dim(entry.details)}`);
29463
+ if (f.content) {
29464
+ const text = f.content.length > 100 ? f.content.slice(0, 97) + "..." : f.content;
29465
+ console.log(` ${chalk55.dim(text)}`);
28552
29466
  }
28553
29467
  }
28554
29468
  console.log();
28555
29469
  }
28556
- const totalExec = skills.reduce((sum, s) => sum + s.executions, 0);
28557
- const avgSuccess = skills.length > 0 ? skills.reduce((sum, s) => sum + s.success_rate, 0) / skills.length : 0;
28558
- const totalAgents = new Set(skills.flatMap((s) => Array.from({ length: s.unique_agents }, (_, i) => `${s.name}-${i}`))).size;
28559
- console.log(chalk55.dim(" --- Network summary ---\n"));
28560
- console.log(` ${chalk55.dim("total skills tracked:")} ${skills.length}`);
28561
- console.log(` ${chalk55.dim("total executions:")} ${totalExec}`);
28562
- console.log(` ${chalk55.dim("avg success rate:")} ${(avgSuccess * 100).toFixed(1)}%`);
28563
- console.log(` ${chalk55.dim("recent learnings:")} ${learnings.length}`);
28564
- console.log(` ${chalk55.dim("improvements pending:")} ${improvements.length}`);
28565
- console.log(` ${chalk55.dim("failures tracked:")} ${failures.length}`);
28566
- console.log();
28567
29470
  } catch (error) {
28568
29471
  spinner.fail("Failed to aggregate insights");
28569
29472
  console.error(chalk55.red(error.message));
@@ -28571,164 +29474,95 @@ function collectiveInsightsCommand() {
28571
29474
  });
28572
29475
  }
28573
29476
  function collectiveSyncCommand() {
28574
- return new Command52("sync").description("Pull latest relevant insights from network into local workspace").option("--workspace <hub_id>", "Workspace/hub ID").option("--limit <n>", "Max insights to pull", "25").option("--dir <path>", "Output directory", ".hubify/collective").option("--json", "Output as JSON").action(async (options) => {
29477
+ return new Command52("sync").description("Pull latest insights from collective into local workspace as organized markdown").option("--limit <n>", "Max insights to pull", "50").option("--dir <path>", "Output directory", ".hubify/collective").option("--json", "Output as JSON").action(async (options) => {
28575
29478
  const spinner = ora51("Syncing collective intelligence to local workspace...").start();
28576
29479
  try {
28577
29480
  const client = getClient();
28578
29481
  const limit = parseInt(options.limit);
28579
- const [feed, trending, recentLearnings] = await Promise.all([
28580
- client.query(
28581
- toFunctionName(api.singularity.getIntelligenceFeed),
28582
- { limit: 10, type: "all" }
28583
- ),
28584
- client.query(
28585
- toFunctionName(api.singularity.getTrendingSkills),
28586
- { days: 7, limit }
28587
- ),
28588
- client.query(
28589
- toFunctionName(api.learning.getRecentEnriched),
28590
- { limit }
28591
- )
28592
- ]);
29482
+ const collectiveFeed = await client.query(
29483
+ toFunctionName(api.collective.getFeed),
29484
+ { limit }
29485
+ );
28593
29486
  spinner.stop();
28594
- const feedEntries = feed;
28595
- const skills = trending;
28596
- const learnings = recentLearnings;
29487
+ const entries = collectiveFeed;
28597
29488
  if (options.json) {
28598
- console.log(JSON.stringify({ feed: feedEntries, trending: skills, learnings }, null, 2));
29489
+ console.log(JSON.stringify(entries, null, 2));
28599
29490
  return;
28600
29491
  }
28601
29492
  const outDir = path25.resolve(process.cwd(), options.dir);
28602
29493
  fs25.mkdirSync(outDir, { recursive: true });
28603
29494
  const now = (/* @__PURE__ */ new Date()).toISOString();
28604
29495
  let filesWritten = 0;
28605
- if (skills.length > 0) {
28606
- let md = `# Trending Skills
28607
-
28608
- _Synced: ${now}_
28609
-
28610
- `;
28611
- for (let i = 0; i < skills.length; i++) {
28612
- const s = skills[i];
28613
- const rate = (s.success_rate * 100).toFixed(0);
28614
- md += `${i + 1}. **${s.name}** \u2014 ${s.executions} executions, ${rate}% success, ${s.unique_agents} agents
28615
- `;
28616
- }
28617
- fs25.writeFileSync(path25.join(outDir, "trending-skills.md"), md);
28618
- filesWritten++;
28619
- }
28620
- if (learnings.length > 0) {
28621
- let md = `# Recent Learnings
28622
-
28623
- _Synced: ${now}_
28624
-
28625
- `;
28626
- for (const l of learnings) {
28627
- const skill = l.skillName ?? l.skill_name ?? "unknown";
28628
- const result = l.result ?? "unknown";
28629
- const time = new Date(l._creationTime ?? Date.now()).toISOString();
28630
- md += `## ${skill} (${result})
28631
- `;
28632
- md += `_${time}_ | agent: ${l.agent_id ?? "unknown"} | platform: ${l.platform ?? "unknown"}_
28633
-
28634
- `;
28635
- if (l.note) md += `> ${l.note}
28636
-
28637
- `;
28638
- if (l.improvement) md += `**Improvement:** ${l.improvement}
28639
-
28640
- `;
28641
- if (l.error_message) md += `**Error:** ${l.error_message}
28642
-
28643
- `;
28644
- md += `---
28645
-
28646
- `;
28647
- }
28648
- fs25.writeFileSync(path25.join(outDir, "recent-learnings.md"), md);
28649
- filesWritten++;
28650
- }
28651
- if (feedEntries.length > 0) {
28652
- let md = `# Active Experiments
28653
-
28654
- _Synced: ${now}_
28655
-
28656
- `;
28657
- for (const entry of feedEntries) {
28658
- md += `## ${entry.title ?? "Untitled"}
28659
- `;
28660
- md += `Type: ${entry.type ?? "unknown"}
28661
-
28662
- `;
28663
- if (entry.description) md += `${entry.description}
28664
-
28665
- `;
28666
- if (entry.details) md += `Progress: ${entry.details}
28667
-
28668
- `;
28669
- md += `---
28670
-
28671
- `;
28672
- }
28673
- fs25.writeFileSync(path25.join(outDir, "active-experiments.md"), md);
28674
- filesWritten++;
28675
- }
28676
- const improvements = learnings.filter((l) => l.improvement);
28677
- if (improvements.length > 0) {
28678
- let md = `# Patterns & Improvements
29496
+ const grouped = {};
29497
+ for (const entry of entries) {
29498
+ const type = entry.type ?? "learning";
29499
+ if (!grouped[type]) grouped[type] = [];
29500
+ grouped[type].push(entry);
29501
+ }
29502
+ const fileMap = {
29503
+ learning: "learnings.md",
29504
+ pattern: "patterns.md",
29505
+ finding: "findings.md",
29506
+ technique: "techniques.md",
29507
+ experiment_result: "experiment-results.md",
29508
+ failure_lesson: "failure-lessons.md"
29509
+ };
29510
+ const headerMap = {
29511
+ learning: "Learnings",
29512
+ pattern: "Patterns",
29513
+ finding: "Findings",
29514
+ technique: "Techniques",
29515
+ experiment_result: "Experiment Results",
29516
+ failure_lesson: "Failure Lessons"
29517
+ };
29518
+ for (const [type, items] of Object.entries(grouped)) {
29519
+ const filename = fileMap[type] ?? `${type}.md`;
29520
+ const header = headerMap[type] ?? type.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
29521
+ let md = `# ${header}
28679
29522
 
28680
29523
  _Synced: ${now}_
29524
+ _Source: Hubify Collective Intelligence_
28681
29525
 
28682
29526
  `;
28683
- md += `These are improvement suggestions extracted from the collective.
28684
-
28685
- `;
28686
- for (const imp of improvements) {
28687
- const skill = imp.skillName ?? imp.skill_name ?? "unknown";
28688
- md += `### ${skill}
28689
- `;
28690
- md += `${imp.improvement}
28691
-
29527
+ for (const item of items) {
29528
+ const time = new Date(item.created_at ?? item._creationTime ?? Date.now()).toISOString();
29529
+ const confidence = item.confidence ? ` | confidence: ${(item.confidence * 100).toFixed(0)}%` : "";
29530
+ const validations = item.validations ? ` | ${item.validations} validations` : "";
29531
+ const applications = item.applications ? ` | ${item.applications} applications` : "";
29532
+ md += `## ${item.title ?? "Untitled"}
28692
29533
  `;
28693
- }
28694
- fs25.writeFileSync(path25.join(outDir, "patterns.md"), md);
28695
- filesWritten++;
28696
- }
28697
- const failures = learnings.filter((l) => l.result === "fail");
28698
- if (failures.length > 0) {
28699
- let md = `# Failure Lessons
28700
-
28701
- _Synced: ${now}_
29534
+ md += `_${time}_ | agent: ${item.source_agent_id ?? "unknown"}${confidence}${validations}${applications}
28702
29535
 
28703
29536
  `;
28704
- md += `Learn from what went wrong across the network.
29537
+ if (item.content) {
29538
+ md += `${item.content}
28705
29539
 
28706
29540
  `;
28707
- for (const f of failures) {
28708
- const skill = f.skillName ?? f.skill_name ?? "unknown";
28709
- md += `### ${skill}
28710
- `;
28711
- if (f.error_message) md += `**Error:** ${f.error_message}
29541
+ }
29542
+ if (item.context) {
29543
+ md += `**Context:** ${item.context}
28712
29544
 
28713
29545
  `;
28714
- if (f.note) md += `> ${f.note}
29546
+ }
29547
+ if (item.tags && item.tags.length > 0) {
29548
+ md += `**Tags:** ${item.tags.join(", ")}
28715
29549
 
28716
29550
  `;
29551
+ }
28717
29552
  md += `---
28718
29553
 
28719
29554
  `;
28720
29555
  }
28721
- fs25.writeFileSync(path25.join(outDir, "failures.md"), md);
29556
+ fs25.writeFileSync(path25.join(outDir, filename), md);
28722
29557
  filesWritten++;
28723
29558
  }
29559
+ const totalEntries = entries.length;
29560
+ const typeBreakdown = Object.entries(grouped).map(([type, items]) => `${type}: ${items.length}`).join(", ");
28724
29561
  console.log(chalk55.bold("\n Collective intelligence synced to local workspace\n"));
28725
29562
  console.log(` ${chalk55.dim("directory:")} ${outDir}`);
28726
29563
  console.log(` ${chalk55.dim("files:")} ${filesWritten} files written`);
28727
- console.log(` ${chalk55.dim("skills:")} ${skills.length} trending`);
28728
- console.log(` ${chalk55.dim("learnings:")} ${learnings.length} recent`);
28729
- console.log(` ${chalk55.dim("experiments:")} ${feedEntries.length} active`);
28730
- console.log(` ${chalk55.dim("patterns:")} ${improvements.length} improvement suggestions`);
28731
- console.log(` ${chalk55.dim("failures:")} ${failures.length} tracked`);
29564
+ console.log(` ${chalk55.dim("insights:")} ${totalEntries} total`);
29565
+ console.log(` ${chalk55.dim("breakdown:")} ${typeBreakdown || "none"}`);
28732
29566
  console.log();
28733
29567
  console.log(chalk55.dim(" Files are markdown \u2014 ready for agent consumption."));
28734
29568
  console.log(chalk55.dim(` Add ${options.dir}/ to your agent's context for smarter decisions.`));
@@ -28745,64 +29579,1491 @@ function miniBar(ratio) {
28745
29579
  return chalk55.green("\u2588".repeat(filled)) + chalk55.dim("\u2591".repeat(empty));
28746
29580
  }
28747
29581
 
28748
- // src/index.ts
28749
- function getCliVersion() {
28750
- try {
28751
- const pkgUrl = new URL("../package.json", import.meta.url);
28752
- const pkg = JSON.parse(fs26.readFileSync(pkgUrl, "utf8"));
28753
- return pkg.version || "0.0.0";
28754
- } catch {
28755
- return "0.0.0";
28756
- }
28757
- }
28758
- var VERSION = getCliVersion();
28759
- var BANNER = `
28760
- ${chalk56.cyan(" __ __ __ _ ____ ")}
28761
- ${chalk56.cyan(" / / / /_ __/ /_ (_) __/_ __")}
28762
- ${chalk56.cyan(" / /_/ / / / / __ \\/ / /_/ / / /")}
28763
- ${chalk56.cyan(" / __ / /_/ / /_/ / / __/ /_/ / ")}
28764
- ${chalk56.cyan("/_/ /_/\\__,_/_.___/_/_/ \\__, / ")}
28765
- ${chalk56.cyan(" /____/ ")}
29582
+ // src/commands/vault.ts
29583
+ import { Command as Command53 } from "commander";
29584
+ import chalk56 from "chalk";
29585
+ import ora52 from "ora";
29586
+ import crypto7 from "crypto";
29587
+ function relativeTime2(ts) {
29588
+ const diff = Date.now() - ts;
29589
+ const mins = Math.floor(diff / 6e4);
29590
+ const hrs = Math.floor(mins / 60);
29591
+ const days = Math.floor(hrs / 24);
29592
+ if (days > 0) return `${days}d ago`;
29593
+ if (hrs > 0) return `${hrs}h ago`;
29594
+ if (mins > 0) return `${mins}m ago`;
29595
+ return "just now";
29596
+ }
29597
+ function encrypt(text, passphrase) {
29598
+ const key = crypto7.scryptSync(passphrase, "hubify-vault-salt", 32);
29599
+ const iv = crypto7.randomBytes(16);
29600
+ const cipher = crypto7.createCipheriv("aes-256-cbc", key, iv);
29601
+ let encrypted = cipher.update(text, "utf8", "hex");
29602
+ encrypted += cipher.final("hex");
29603
+ return iv.toString("hex") + ":" + encrypted;
29604
+ }
29605
+ function decrypt(encrypted, passphrase) {
29606
+ const key = crypto7.scryptSync(passphrase, "hubify-vault-salt", 32);
29607
+ const [ivHex, encHex] = encrypted.split(":");
29608
+ const iv = Buffer.from(ivHex, "hex");
29609
+ const decipher = crypto7.createDecipheriv("aes-256-cbc", key, iv);
29610
+ let decrypted = decipher.update(encHex, "hex", "utf8");
29611
+ decrypted += decipher.final("utf8");
29612
+ return decrypted;
29613
+ }
29614
+ function vaultListCommand() {
29615
+ return new Command53("list").description("List vault entries for a workspace").argument("<hub_id>", "Hub/workspace ID").option("--owner <id>", "Owner ID", "user_default").option("--json", "Output as JSON").action(async (hubId, options) => {
29616
+ const spinner = ora52("Fetching vault entries...").start();
29617
+ try {
29618
+ const client = getClient();
29619
+ const entries = await client.query(
29620
+ toFunctionName(api.vault.listVaultEntries),
29621
+ { hub_id: hubId, owner_id: options.owner }
29622
+ );
29623
+ spinner.stop();
29624
+ if (options.json) {
29625
+ console.log(JSON.stringify(entries, null, 2));
29626
+ return;
29627
+ }
29628
+ if (!entries || entries.length === 0) {
29629
+ console.log(chalk56.gray("\n No vault entries. Add one with:"));
29630
+ console.log(chalk56.cyan(" hubify vault store <hub_id> --service github --type api_key --value <key>\n"));
29631
+ return;
29632
+ }
29633
+ console.log(chalk56.cyan(`
29634
+ Vault (${entries.length} entries)
29635
+ `));
29636
+ for (const entry of entries) {
29637
+ const typeColor = entry.type === "api_key" ? chalk56.yellow : entry.type === "mcp" ? chalk56.blue : chalk56.green;
29638
+ console.log(
29639
+ ` ${typeColor(entry.type.padEnd(12))} ${chalk56.white(entry.service.padEnd(20))} ` + chalk56.gray(`agents: ${entry.granted_agents.join(", ") || "none"}`) + (entry.last_accessed ? chalk56.dim(` last used ${relativeTime2(entry.last_accessed)}`) : "")
29640
+ );
29641
+ }
29642
+ console.log();
29643
+ } catch (error) {
29644
+ spinner.fail("Failed to list vault entries");
29645
+ console.error(chalk56.red(` ${error.message}`));
29646
+ }
29647
+ });
29648
+ }
29649
+ function vaultStoreCommand() {
29650
+ return new Command53("store").description("Store a credential in the vault").argument("<hub_id>", "Hub/workspace ID").requiredOption("--service <name>", "Service name (e.g., github, openai, slack)").requiredOption("--type <type>", "Entry type: api_key, mcp, oauth_token").requiredOption("--value <value>", "The secret value to store").option("--owner <id>", "Owner ID", "user_default").option("--agents <agents>", "Comma-separated agent IDs granted access", "all").option("--passphrase <p>", "Encryption passphrase", "hubify-default-key").action(async (hubId, options) => {
29651
+ const validTypes = ["api_key", "mcp", "oauth_token"];
29652
+ if (!validTypes.includes(options.type)) {
29653
+ console.log(chalk56.red(`
29654
+ Invalid type: ${options.type}. Must be one of: ${validTypes.join(", ")}
29655
+ `));
29656
+ process.exit(1);
29657
+ }
29658
+ const spinner = ora52(`Encrypting and storing ${options.service} credential...`).start();
29659
+ try {
29660
+ const client = getClient();
29661
+ const encrypted = encrypt(options.value, options.passphrase);
29662
+ const agents = options.agents.split(",").map((a) => a.trim());
29663
+ await client.mutation(
29664
+ toFunctionName(api.vault.addVaultEntry),
29665
+ {
29666
+ hub_id: hubId,
29667
+ owner_id: options.owner,
29668
+ entry: {
29669
+ id: `${options.service}-${options.type}-${Date.now()}`,
29670
+ type: options.type,
29671
+ service: options.service,
29672
+ encrypted_config: encrypted,
29673
+ granted_agents: agents
29674
+ }
29675
+ }
29676
+ );
29677
+ spinner.succeed(`Stored ${options.service} credential`);
29678
+ console.log(chalk56.gray(` Type: ${options.type}`));
29679
+ console.log(chalk56.gray(` Agents: ${agents.join(", ")}`));
29680
+ console.log(chalk56.gray(` Hub: ${hubId}`));
29681
+ console.log();
29682
+ } catch (error) {
29683
+ spinner.fail("Failed to store credential");
29684
+ console.error(chalk56.red(` ${error.message}`));
29685
+ }
29686
+ });
29687
+ }
29688
+ function vaultGetCommand() {
29689
+ return new Command53("get").description("Retrieve a credential from the vault (requires agent access)").argument("<hub_id>", "Hub/workspace ID").requiredOption("--service <name>", "Service name").option("--agent <id>", "Requesting agent ID", "cli-user").option("--passphrase <p>", "Decryption passphrase", "hubify-default-key").option("--json", "Output as JSON").action(async (hubId, options) => {
29690
+ const spinner = ora52(`Retrieving ${options.service} credential...`).start();
29691
+ try {
29692
+ const client = getClient();
29693
+ const result = await client.mutation(
29694
+ toFunctionName(api.vault.getVaultEntry),
29695
+ {
29696
+ hub_id: hubId,
29697
+ service: options.service,
29698
+ requesting_agent: options.agent
29699
+ }
29700
+ );
29701
+ spinner.stop();
29702
+ if (!result) {
29703
+ console.log(chalk56.yellow(`
29704
+ No credential found for service: ${options.service}
29705
+ `));
29706
+ return;
29707
+ }
29708
+ if (result.error) {
29709
+ console.log(chalk56.red(`
29710
+ Access denied: ${result.error}
29711
+ `));
29712
+ process.exit(1);
29713
+ }
29714
+ const decrypted = decrypt(result.encrypted_config, options.passphrase);
29715
+ if (options.json) {
29716
+ console.log(JSON.stringify({ service: result.service, type: result.type, value: decrypted }, null, 2));
29717
+ return;
29718
+ }
29719
+ console.log(chalk56.cyan(`
29720
+ ${result.service} (${result.type})
29721
+ `));
29722
+ console.log(chalk56.white(` ${decrypted}`));
29723
+ console.log();
29724
+ } catch (error) {
29725
+ spinner.fail("Failed to retrieve credential");
29726
+ console.error(chalk56.red(` ${error.message}`));
29727
+ }
29728
+ });
29729
+ }
29730
+ function vaultRevokeCommand() {
29731
+ return new Command53("revoke").description("Delete a vault entry").argument("<hub_id>", "Hub/workspace ID").requiredOption("--entry-id <id>", "Entry ID to revoke").action(async (hubId, options) => {
29732
+ const spinner = ora52("Revoking vault entry...").start();
29733
+ try {
29734
+ const client = getClient();
29735
+ await client.mutation(
29736
+ toFunctionName(api.vault.deleteVaultEntry),
29737
+ { hub_id: hubId, entry_id: options.entryId }
29738
+ );
29739
+ spinner.succeed("Vault entry revoked");
29740
+ console.log(chalk56.gray(` Entry ${options.entryId} has been removed.
29741
+ `));
29742
+ } catch (error) {
29743
+ spinner.fail("Failed to revoke entry");
29744
+ console.error(chalk56.red(` ${error.message}`));
29745
+ }
29746
+ });
29747
+ }
29748
+ function vaultGrantCommand() {
29749
+ return new Command53("grant").description("Update which agents can access a vault entry").argument("<hub_id>", "Hub/workspace ID").requiredOption("--entry-id <id>", "Entry ID").requiredOption("--agents <agents>", "Comma-separated agent IDs (or 'all')").action(async (hubId, options) => {
29750
+ const spinner = ora52("Updating access grants...").start();
29751
+ try {
29752
+ const client = getClient();
29753
+ const agents = options.agents.split(",").map((a) => a.trim());
29754
+ await client.mutation(
29755
+ toFunctionName(api.vault.updateVaultEntryGrants),
29756
+ { hub_id: hubId, entry_id: options.entryId, granted_agents: agents }
29757
+ );
29758
+ spinner.succeed("Access grants updated");
29759
+ console.log(chalk56.gray(` Agents: ${agents.join(", ")}
29760
+ `));
29761
+ } catch (error) {
29762
+ spinner.fail("Failed to update grants");
29763
+ console.error(chalk56.red(` ${error.message}`));
29764
+ }
29765
+ });
29766
+ }
29767
+ function vaultAuditCommand() {
29768
+ return new Command53("audit").description("View access log for a vault service").argument("<hub_id>", "Hub/workspace ID").requiredOption("--service <name>", "Service name").option("--limit <n>", "Max entries", "20").option("--json", "Output as JSON").action(async (hubId, options) => {
29769
+ const spinner = ora52("Fetching access log...").start();
29770
+ try {
29771
+ const client = getClient();
29772
+ const logs = await client.query(
29773
+ toFunctionName(api.vault.getVaultAccessLog),
29774
+ { hub_id: hubId, service: options.service, limit: parseInt(options.limit) }
29775
+ );
29776
+ spinner.stop();
29777
+ if (options.json) {
29778
+ console.log(JSON.stringify(logs, null, 2));
29779
+ return;
29780
+ }
29781
+ if (!logs || logs.length === 0) {
29782
+ console.log(chalk56.gray(`
29783
+ No access logs for ${options.service}
29784
+ `));
29785
+ return;
29786
+ }
29787
+ console.log(chalk56.cyan(`
29788
+ Access Log: ${options.service} (${logs.length} entries)
29789
+ `));
29790
+ for (const log of logs) {
29791
+ console.log(
29792
+ ` ${chalk56.gray(relativeTime2(log.timestamp).padEnd(12))} ${chalk56.white(log.agent_id.padEnd(20))} ` + chalk56.dim(log.operation)
29793
+ );
29794
+ }
29795
+ console.log();
29796
+ } catch (error) {
29797
+ spinner.fail("Failed to fetch access log");
29798
+ console.error(chalk56.red(` ${error.message}`));
29799
+ }
29800
+ });
29801
+ }
29802
+ var vaultCommand = new Command53("vault").description("Manage tool credentials and API keys for workspace agents").addCommand(vaultListCommand()).addCommand(vaultStoreCommand()).addCommand(vaultGetCommand()).addCommand(vaultRevokeCommand()).addCommand(vaultGrantCommand()).addCommand(vaultAuditCommand());
29803
+
29804
+ // src/commands/reports.ts
29805
+ import { Command as Command54 } from "commander";
29806
+ import chalk57 from "chalk";
29807
+ import ora53 from "ora";
29808
+ var reportsCommand = new Command54("reports").description("Weekly intelligence reports \u2014 network activity, skills, experiments").addCommand(reportsLatestCommand()).addCommand(reportsListCommand()).addCommand(reportsViewCommand());
29809
+ function reportsLatestCommand() {
29810
+ return new Command54("latest").description("Show the most recent weekly intelligence report").option("--json", "Output as raw JSON").action(async (options) => {
29811
+ const spinner = ora53("Fetching latest report...").start();
29812
+ try {
29813
+ const client = getClient();
29814
+ const report = await client.query(
29815
+ toFunctionName("weeklyReport:getLatestReport"),
29816
+ {}
29817
+ );
29818
+ spinner.stop();
29819
+ if (!report) {
29820
+ console.log(chalk57.dim(" No weekly reports available yet."));
29821
+ return;
29822
+ }
29823
+ if (options.json) {
29824
+ console.log(JSON.stringify(report, null, 2));
29825
+ return;
29826
+ }
29827
+ printFullReport(report);
29828
+ } catch (error) {
29829
+ spinner.fail("Failed to fetch latest report");
29830
+ console.error(chalk57.red(error.message));
29831
+ }
29832
+ });
29833
+ }
29834
+ function reportsListCommand() {
29835
+ return new Command54("list").description("List available weekly reports").option("--limit <n>", "Number of reports to show", "10").option("--json", "Output as raw JSON").action(async (options) => {
29836
+ const spinner = ora53("Fetching report list...").start();
29837
+ try {
29838
+ const client = getClient();
29839
+ const reports = await client.query(
29840
+ toFunctionName("weeklyReport:listReports"),
29841
+ { limit: parseInt(options.limit) }
29842
+ );
29843
+ spinner.stop();
29844
+ if (options.json) {
29845
+ console.log(JSON.stringify(reports, null, 2));
29846
+ return;
29847
+ }
29848
+ const list = reports;
29849
+ if (list.length === 0) {
29850
+ console.log(chalk57.dim(" No weekly reports available yet."));
29851
+ return;
29852
+ }
29853
+ console.log(chalk57.bold(`
29854
+ Weekly Intelligence Reports (${list.length})
29855
+ `));
29856
+ console.log(
29857
+ chalk57.dim(" ") + chalk57.white("Week Start".padEnd(14)) + chalk57.white("Week End".padEnd(14)) + chalk57.white("Generated".padEnd(24)) + chalk57.white("Executions".padEnd(12)) + chalk57.white("New Skills".padEnd(12)) + chalk57.white("Experiments")
29858
+ );
29859
+ console.log(chalk57.dim(" " + "\u2500".repeat(88)));
29860
+ for (const r of list) {
29861
+ const weekStart = formatDate3(r.week_start).padEnd(14);
29862
+ const weekEnd = formatDate3(r.week_end).padEnd(14);
29863
+ const generated = new Date(r.generated_at).toLocaleString().padEnd(24);
29864
+ const executions = String(r.stats?.total_executions ?? "\u2014").padEnd(12);
29865
+ const newSkills = String(r.stats?.new_skills ?? "\u2014").padEnd(12);
29866
+ const experiments = String(r.stats?.active_experiments ?? "\u2014");
29867
+ console.log(
29868
+ chalk57.dim(" ") + chalk57.cyan(weekStart) + chalk57.dim(weekEnd) + chalk57.dim(generated) + chalk57.yellow(executions) + chalk57.green(newSkills) + chalk57.dim(experiments)
29869
+ );
29870
+ }
29871
+ console.log();
29872
+ console.log(chalk57.dim(" Use `hubify reports view --date <YYYY-MM-DD>` to view a specific week."));
29873
+ console.log();
29874
+ } catch (error) {
29875
+ spinner.fail("Failed to fetch report list");
29876
+ console.error(chalk57.red(error.message));
29877
+ }
29878
+ });
29879
+ }
29880
+ function reportsViewCommand() {
29881
+ return new Command54("view").description("View report for a specific week").requiredOption("--date <date>", "ISO date string within the week (e.g. 2026-03-10)").option("--json", "Output as raw JSON").action(async (options) => {
29882
+ const spinner = ora53(`Fetching report for ${options.date}...`).start();
29883
+ try {
29884
+ const parsed = Date.parse(options.date);
29885
+ if (isNaN(parsed)) {
29886
+ spinner.fail("Invalid date");
29887
+ console.error(chalk57.red(` Could not parse date: ${options.date}`));
29888
+ console.error(chalk57.dim(" Expected ISO format, e.g. 2026-03-10"));
29889
+ process.exit(1);
29890
+ }
29891
+ const client = getClient();
29892
+ const report = await client.query(
29893
+ toFunctionName("weeklyReport:getReportByWeek"),
29894
+ { date: parsed }
29895
+ );
29896
+ spinner.stop();
29897
+ if (!report) {
29898
+ console.log(chalk57.dim(` No report found for the week containing ${options.date}.`));
29899
+ return;
29900
+ }
29901
+ if (options.json) {
29902
+ console.log(JSON.stringify(report, null, 2));
29903
+ return;
29904
+ }
29905
+ printFullReport(report);
29906
+ } catch (error) {
29907
+ spinner.fail("Failed to fetch report");
29908
+ console.error(chalk57.red(error.message));
29909
+ }
29910
+ });
29911
+ }
29912
+ function printFullReport(r) {
29913
+ const weekStart = formatDate3(r.week_start);
29914
+ const weekEnd = formatDate3(r.week_end);
29915
+ const generated = new Date(r.generated_at).toLocaleString();
29916
+ console.log();
29917
+ console.log(chalk57.bold(` Weekly Intelligence Report`));
29918
+ console.log(chalk57.dim(` ${weekStart} \u2192 ${weekEnd} \xB7 generated ${generated}`));
29919
+ console.log(chalk57.dim(" " + "\u2500".repeat(60)));
29920
+ const s = r.stats ?? {};
29921
+ console.log();
29922
+ console.log(chalk57.bold(" Overview"));
29923
+ console.log();
29924
+ const delta = s.execution_delta_pct ?? 0;
29925
+ const deltaStr = delta >= 0 ? chalk57.green(`+${delta.toFixed(1)}%`) : chalk57.red(`${delta.toFixed(1)}%`);
29926
+ console.log(` ${chalk57.dim("Executions: ")} ${chalk57.yellow(s.total_executions ?? 0)} ${deltaStr} vs last week`);
29927
+ console.log(` ${chalk57.dim("New skills: ")} ${chalk57.cyan(s.new_skills ?? 0)}`);
29928
+ console.log(` ${chalk57.dim("Skills evolved: ")} ${chalk57.cyan(s.skills_evolved ?? 0)}`);
29929
+ console.log(` ${chalk57.dim("New learnings: ")} ${s.new_learnings ?? 0}`);
29930
+ console.log(` ${chalk57.dim("New agents: ")} ${s.new_agents ?? 0}`);
29931
+ console.log(` ${chalk57.dim("Security scans: ")} ${s.security_scans ?? 0}`);
29932
+ console.log(` ${chalk57.dim("Collective insights: ")} ${s.collective_insights_shared ?? 0}`);
29933
+ console.log(` ${chalk57.dim("Active experiments: ")} ${s.active_experiments ?? 0}`);
29934
+ if (r.top_used_skills?.length) {
29935
+ console.log();
29936
+ console.log(chalk57.bold(" Top Used Skills"));
29937
+ console.log();
29938
+ console.log(
29939
+ chalk57.dim(" ") + chalk57.dim("Skill".padEnd(36)) + chalk57.dim("Executions".padEnd(12)) + chalk57.dim("Success Rate")
29940
+ );
29941
+ console.log(chalk57.dim(" " + "\u2500".repeat(62)));
29942
+ for (let i = 0; i < r.top_used_skills.length; i++) {
29943
+ const sk = r.top_used_skills[i];
29944
+ const rank = chalk57.dim(`${i + 1}.`.padEnd(4));
29945
+ const name = chalk57.cyan(sk.name.padEnd(32));
29946
+ const execs = chalk57.yellow(String(sk.executions).padEnd(12));
29947
+ const rate = formatSuccessRate(sk.success_rate);
29948
+ console.log(` ${rank}${name}${execs}${rate}`);
29949
+ }
29950
+ }
29951
+ if (r.top_improving_skills?.length) {
29952
+ console.log();
29953
+ console.log(chalk57.bold(" Top Improving Skills"));
29954
+ console.log();
29955
+ console.log(
29956
+ chalk57.dim(" ") + chalk57.dim("Skill".padEnd(36)) + chalk57.dim("Confidence".padEnd(12)) + chalk57.dim("Delta")
29957
+ );
29958
+ console.log(chalk57.dim(" " + "\u2500".repeat(62)));
29959
+ for (let i = 0; i < r.top_improving_skills.length; i++) {
29960
+ const sk = r.top_improving_skills[i];
29961
+ const rank = chalk57.dim(`${i + 1}.`.padEnd(4));
29962
+ const name = chalk57.cyan(sk.name.padEnd(32));
29963
+ const conf = `${(sk.confidence * 100).toFixed(1)}%`.padEnd(12);
29964
+ const delta2 = sk.confidence_delta >= 0 ? chalk57.green(`+${(sk.confidence_delta * 100).toFixed(1)}%`) : chalk57.red(`${(sk.confidence_delta * 100).toFixed(1)}%`);
29965
+ console.log(` ${rank}${name}${conf}${delta2}`);
29966
+ }
29967
+ }
29968
+ if (r.new_skills_list?.length) {
29969
+ console.log();
29970
+ console.log(chalk57.bold(" New Skills This Week"));
29971
+ console.log();
29972
+ for (const sk of r.new_skills_list) {
29973
+ const conf = `${(sk.confidence * 100).toFixed(0)}%`;
29974
+ console.log(
29975
+ ` ${chalk57.green("+")} ${chalk57.cyan(sk.name)} ` + chalk57.dim(`conf ${conf} executions ${sk.executions}`)
29976
+ );
29977
+ }
29978
+ }
29979
+ if (r.evolution_events?.length) {
29980
+ console.log();
29981
+ console.log(chalk57.bold(" Evolution Events"));
29982
+ console.log();
29983
+ for (const ev of r.evolution_events) {
29984
+ const time = new Date(ev.timestamp).toLocaleString();
29985
+ const typeLabel = formatEvolutionType(ev.event_type);
29986
+ console.log(` ${typeLabel} ${chalk57.cyan(ev.skill_name)} ${chalk57.dim(time)}`);
29987
+ }
29988
+ }
29989
+ if (r.top_platforms?.length) {
29990
+ console.log();
29991
+ console.log(chalk57.bold(" Top Platforms"));
29992
+ console.log();
29993
+ for (const p of r.top_platforms) {
29994
+ console.log(` ${chalk57.dim("\xB7")} ${p.platform.padEnd(20)} ${chalk57.yellow(p.executions)} executions`);
29995
+ }
29996
+ }
29997
+ if (r.failure_patterns?.length) {
29998
+ console.log();
29999
+ console.log(chalk57.bold(" Failure Patterns"));
30000
+ console.log();
30001
+ for (const fp of r.failure_patterns) {
30002
+ console.log(` ${chalk57.red("!")} ${fp.pattern} ${chalk57.dim(`(${fp.count} occurrences)`)}`);
30003
+ if (fp.affected_skills?.length) {
30004
+ console.log(` ${chalk57.dim("affected:")} ${fp.affected_skills.join(", ")}`);
30005
+ }
30006
+ }
30007
+ }
30008
+ if (r.experiment_missions?.length) {
30009
+ console.log();
30010
+ console.log(chalk57.bold(" Experiment Missions"));
30011
+ console.log();
30012
+ for (const m of r.experiment_missions) {
30013
+ const statusColor = m.status === "completed" ? chalk57.green : m.status === "active" ? chalk57.cyan : chalk57.dim;
30014
+ console.log(` ${statusColor(`[${m.status}]`)} ${chalk57.bold(m.title)}`);
30015
+ console.log(` ${chalk57.dim("experiments completed:")} ${m.experiments_completed}`);
30016
+ if (m.best_metric != null) {
30017
+ console.log(` ${chalk57.dim("best metric:")} ${m.best_metric}`);
30018
+ }
30019
+ }
30020
+ }
30021
+ if (r.highlights?.length) {
30022
+ console.log();
30023
+ console.log(chalk57.bold(" Highlights"));
30024
+ console.log();
30025
+ for (const h of r.highlights) {
30026
+ console.log(` ${chalk57.yellow("\u203A")} ${h}`);
30027
+ }
30028
+ }
30029
+ console.log();
30030
+ }
30031
+ function formatDate3(ts) {
30032
+ return new Date(ts).toISOString().slice(0, 10);
30033
+ }
30034
+ function formatSuccessRate(rate) {
30035
+ const pct = `${(rate * 100).toFixed(1)}%`;
30036
+ if (rate >= 0.8) return chalk57.green(pct);
30037
+ if (rate >= 0.5) return chalk57.yellow(pct);
30038
+ return chalk57.red(pct);
30039
+ }
30040
+ function formatEvolutionType(eventType) {
30041
+ switch (eventType) {
30042
+ case "promoted":
30043
+ return chalk57.green("[promoted]");
30044
+ case "canary":
30045
+ return chalk57.yellow("[canary] ");
30046
+ case "merged":
30047
+ return chalk57.cyan("[merged] ");
30048
+ case "rejected":
30049
+ return chalk57.red("[rejected]");
30050
+ default:
30051
+ return chalk57.dim(`[${eventType}]`);
30052
+ }
30053
+ }
30054
+
30055
+ // src/commands/mission.ts
30056
+ import { Command as Command55 } from "commander";
30057
+ import chalk58 from "chalk";
30058
+ import ora54 from "ora";
30059
+ var missionCommand = new Command55("mission").description("Autonomous Mission Runner \u2014 Ralph Loop").addCommand(missionListCommand()).addCommand(missionCreateCommand()).addCommand(missionRunCommand()).addCommand(missionStatusCommand()).addCommand(missionStopCommand()).addCommand(missionAgentsCommand());
30060
+ function missionListCommand() {
30061
+ return new Command55("list").description("List missions").option("--status <status>", "Filter by status (proposed|approved|active|completed)").option("--limit <n>", "Max results", "20").option("--json", "Output as JSON").action(async (options) => {
30062
+ const client = getClient();
30063
+ const spinner = ora54("Fetching missions...").start();
30064
+ try {
30065
+ const missions = await client.query(toFunctionName(api.research.listMissions), {
30066
+ status: options.status,
30067
+ limit: parseInt(options.limit)
30068
+ });
30069
+ spinner.stop();
30070
+ if (options.json) {
30071
+ console.log(JSON.stringify(missions, null, 2));
30072
+ return;
30073
+ }
30074
+ if (!missions || missions.length === 0) {
30075
+ console.log(chalk58.dim("No missions found."));
30076
+ return;
30077
+ }
30078
+ console.log(chalk58.bold(`
30079
+ Missions (${missions.length})
30080
+ `));
30081
+ for (const m of missions) {
30082
+ const statusColor = m.status === "active" ? chalk58.green : m.status === "completed" ? chalk58.blue : m.status === "proposed" ? chalk58.yellow : chalk58.dim;
30083
+ console.log(` ${statusColor("\u25CF")} ${chalk58.bold(m.title)}`);
30084
+ console.log(` ${chalk58.dim("ID:")} ${m._id}`);
30085
+ console.log(` ${chalk58.dim("Type:")} ${m.mission_type} ${chalk58.dim("Status:")} ${statusColor(m.status)}`);
30086
+ if (m.experiment_config?.experiments_completed !== void 0) {
30087
+ console.log(` ${chalk58.dim("Experiments:")} ${m.experiment_config.experiments_completed}/${m.experiment_config.max_experiments}`);
30088
+ }
30089
+ console.log();
30090
+ }
30091
+ } catch (e) {
30092
+ spinner.fail(e.message);
30093
+ }
30094
+ });
30095
+ }
30096
+ function missionCreateCommand() {
30097
+ return new Command55("create").description("Create a new research mission").argument("<hub_id>", "Hub ID to create mission in").requiredOption("--title <title>", "Mission title").requiredOption("--question <question>", "Research question").option("--type <type>", "Mission type", "technical").option("--methodology <method>", "Research methodology").option("--description <desc>", "Detailed description").option("--max-experiments <n>", "Max experiments", "50").option("--time-hours <n>", "Time budget in hours", "24").option("--max-cost <n>", "Max cost in USD", "5.00").option("--metric <name>", "Primary metric name", "quality_score").option("--direction <dir>", "Metric direction (maximize|minimize)", "maximize").option("--json", "Output as JSON").action(async (hubId, options) => {
30098
+ const client = getClient();
30099
+ const spinner = ora54("Creating mission...").start();
30100
+ try {
30101
+ const result = await client.mutation(toFunctionName(api.research.proposeMission), {
30102
+ hub_id: hubId,
30103
+ title: options.title,
30104
+ description: options.description || options.title,
30105
+ research_question: options.question,
30106
+ methodology: options.methodology,
30107
+ mission_type: options.type,
30108
+ proposed_by: "cli-user",
30109
+ experiment_config: {
30110
+ enabled: true,
30111
+ primary_metric: options.metric,
30112
+ metric_direction: options.direction,
30113
+ budget_minutes_per_experiment: 15,
30114
+ max_experiments: parseInt(options.maxExperiments),
30115
+ time_budget_hours: parseInt(options.timeHours),
30116
+ max_cost_usd: parseFloat(options.maxCost),
30117
+ minimum_improvement_threshold: 0.01
30118
+ }
30119
+ });
30120
+ spinner.succeed("Mission created");
30121
+ if (options.json) {
30122
+ console.log(JSON.stringify(result, null, 2));
30123
+ } else {
30124
+ console.log(`
30125
+ ${chalk58.bold("Mission ID:")} ${result}`);
30126
+ console.log(` ${chalk58.dim("Next:")} hubify mission run ${result}`);
30127
+ }
30128
+ } catch (e) {
30129
+ spinner.fail(e.message);
30130
+ }
30131
+ });
30132
+ }
30133
+ function missionRunCommand() {
30134
+ return new Command55("run").description("Run autonomous mission loop (Ralph Loop)").argument("<mission_id>", "Mission ID to run").option("--cycles <n>", "Max cycles before stopping (0 = until budget exhausted)", "0").option("--interval <ms>", "Delay between cycles in ms", "2000").option("--dry-run", "Show what would happen without executing").action(async (missionId, options) => {
30135
+ const client = getClient();
30136
+ const maxCycles = parseInt(options.cycles);
30137
+ const interval = parseInt(options.interval);
30138
+ console.log(chalk58.bold("\n Ralph Loop \u2014 Autonomous Mission Runner\n"));
30139
+ console.log(` ${chalk58.dim("Mission:")} ${missionId}`);
30140
+ console.log(` ${chalk58.dim("Max cycles:")} ${maxCycles || "unlimited (budget-limited)"}`);
30141
+ console.log(` ${chalk58.dim("Interval:")} ${interval}ms`);
30142
+ console.log();
30143
+ const spinner = ora54("Loading mission...").start();
30144
+ let mission;
30145
+ try {
30146
+ mission = await client.query(toFunctionName(api.research.getMission), {
30147
+ id: missionId
30148
+ });
30149
+ if (!mission) {
30150
+ spinner.fail("Mission not found");
30151
+ return;
30152
+ }
30153
+ spinner.succeed(`${mission.title} (${mission.status})`);
30154
+ } catch (e) {
30155
+ spinner.fail(e.message);
30156
+ return;
30157
+ }
30158
+ if (mission.status === "proposed") {
30159
+ const approveSpinner = ora54("Auto-approving mission...").start();
30160
+ try {
30161
+ await client.mutation(toFunctionName(api.research.approveMission), {
30162
+ mission_id: missionId,
30163
+ approved_by: "ralph-loop"
30164
+ });
30165
+ approveSpinner.succeed("Mission approved");
30166
+ } catch (e) {
30167
+ approveSpinner.fail(e.message);
30168
+ }
30169
+ }
30170
+ if (mission.status === "proposed" || mission.status === "approved") {
30171
+ const startSpinner = ora54("Starting mission...").start();
30172
+ try {
30173
+ await client.mutation(toFunctionName(api.research.startMission), {
30174
+ mission_id: missionId
30175
+ });
30176
+ startSpinner.succeed("Mission started");
30177
+ } catch (e) {
30178
+ startSpinner.fail(e.message);
30179
+ return;
30180
+ }
30181
+ }
30182
+ const config = mission.experiment_config;
30183
+ if (config) {
30184
+ console.log(chalk58.dim("\n Budget:"));
30185
+ console.log(` Experiments: ${config.experiments_completed || 0}/${config.max_experiments}`);
30186
+ console.log(` Time: ${config.time_budget_hours}h`);
30187
+ console.log(` Cost: $${(config.cost_spent_usd || 0).toFixed(2)}/$${config.max_cost_usd}`);
30188
+ console.log(` Metric: ${config.primary_metric} (${config.metric_direction})`);
30189
+ if (config.best_metric_value !== void 0) {
30190
+ console.log(` Best: ${config.best_metric_value}`);
30191
+ }
30192
+ }
30193
+ if (options.dryRun) {
30194
+ console.log(chalk58.yellow("\n Dry run \u2014 no experiments will be executed."));
30195
+ return;
30196
+ }
30197
+ console.log(chalk58.green("\n \u26A1 Entering Ralph Loop...\n"));
30198
+ let cycle = 0;
30199
+ let consecutiveFailures = 0;
30200
+ const maxConsecutiveFailures = 5;
30201
+ while (true) {
30202
+ cycle++;
30203
+ if (maxCycles > 0 && cycle > maxCycles) {
30204
+ console.log(chalk58.yellow(`
30205
+ Reached max cycles (${maxCycles}). Stopping.`));
30206
+ break;
30207
+ }
30208
+ const cycleSpinner = ora54(`Cycle ${cycle}: Checking frontier...`).start();
30209
+ try {
30210
+ const summary = await client.query(toFunctionName(api.research.getExperimentSummary), {
30211
+ mission_id: missionId
30212
+ });
30213
+ if (!summary) {
30214
+ cycleSpinner.fail("Could not fetch experiment summary");
30215
+ break;
30216
+ }
30217
+ const expConfig = summary.config;
30218
+ if (expConfig) {
30219
+ if (expConfig.experiments_completed >= expConfig.max_experiments) {
30220
+ cycleSpinner.info(`Budget exhausted: ${expConfig.experiments_completed}/${expConfig.max_experiments} experiments`);
30221
+ break;
30222
+ }
30223
+ if (expConfig.cost_spent_usd >= expConfig.max_cost_usd) {
30224
+ cycleSpinner.info(`Cost budget exhausted: $${expConfig.cost_spent_usd.toFixed(2)}/$${expConfig.max_cost_usd}`);
30225
+ break;
30226
+ }
30227
+ }
30228
+ const frontier = await client.query(toFunctionName(api.experimentDag.getLeaves), {
30229
+ mission_id: missionId,
30230
+ limit: 5
30231
+ });
30232
+ if (!frontier || frontier.length === 0) {
30233
+ cycleSpinner.warn("No frontier nodes available \u2014 waiting...");
30234
+ consecutiveFailures++;
30235
+ if (consecutiveFailures >= maxConsecutiveFailures) {
30236
+ console.log(chalk58.yellow(`
30237
+ ${maxConsecutiveFailures} consecutive failures. Stopping.`));
30238
+ break;
30239
+ }
30240
+ await sleep2(interval * 2);
30241
+ continue;
30242
+ }
30243
+ cycleSpinner.text = `Cycle ${cycle}: Triggering experiment (frontier: ${frontier.length} nodes)...`;
30244
+ const triggerResult = await client.mutation(toFunctionName(api.experimentRunner.triggerCycle), {
30245
+ mission_id: missionId
30246
+ });
30247
+ if (!triggerResult.triggered) {
30248
+ cycleSpinner.info(`Cycle ${cycle}: Budget exhausted (${triggerResult.reason})`);
30249
+ break;
30250
+ }
30251
+ consecutiveFailures = 0;
30252
+ const completed = triggerResult.experiments_completed || 0;
30253
+ const max = triggerResult.max_experiments || 0;
30254
+ const cost = triggerResult.cost_spent_usd || 0;
30255
+ const maxCost = triggerResult.max_cost_usd || 0;
30256
+ const best = expConfig?.best_metric_value;
30257
+ const pct = max > 0 ? Math.round(completed / max * 100) : 0;
30258
+ const bar = progressBar3(pct, 20);
30259
+ cycleSpinner.succeed(
30260
+ `Cycle ${cycle}: ${bar} ${completed}/${max} experiments \xB7 $${cost.toFixed(2)}/$${maxCost.toFixed(2)} \xB7 best: ${best ?? "\u2014"}`
30261
+ );
30262
+ } catch (e) {
30263
+ cycleSpinner.fail(`Cycle ${cycle}: ${e.message}`);
30264
+ consecutiveFailures++;
30265
+ if (consecutiveFailures >= maxConsecutiveFailures) {
30266
+ console.log(chalk58.red(`
30267
+ ${maxConsecutiveFailures} consecutive failures. Stopping.`));
30268
+ break;
30269
+ }
30270
+ }
30271
+ await sleep2(interval);
30272
+ }
30273
+ console.log(chalk58.bold("\n Ralph Loop completed.\n"));
30274
+ try {
30275
+ const finalSummary = await client.query(toFunctionName(api.research.getExperimentSummary), {
30276
+ mission_id: missionId
30277
+ });
30278
+ if (finalSummary?.config) {
30279
+ const c = finalSummary.config;
30280
+ console.log(` Experiments: ${c.experiments_completed}/${c.max_experiments}`);
30281
+ console.log(` Cost: $${(c.cost_spent_usd || 0).toFixed(2)}/$${c.max_cost_usd}`);
30282
+ console.log(` Best metric: ${c.best_metric_value ?? "none"}`);
30283
+ if (c.best_node_id) {
30284
+ console.log(` Best node: ${c.best_node_id}`);
30285
+ }
30286
+ }
30287
+ if (finalSummary?.stats) {
30288
+ console.log(` DAG: ${finalSummary.stats.total_nodes} nodes, depth ${finalSummary.stats.max_depth}`);
30289
+ console.log(` Success rate: ${Math.round(finalSummary.stats.completed_nodes / Math.max(finalSummary.stats.total_nodes, 1) * 100)}%`);
30290
+ }
30291
+ } catch {
30292
+ }
30293
+ console.log(`
30294
+ ${chalk58.dim("View results:")} hubify mission status ${missionId}`);
30295
+ console.log(` ${chalk58.dim("Best path:")} hubify labs best-path ${missionId}
30296
+ `);
30297
+ });
30298
+ }
30299
+ function missionStatusCommand() {
30300
+ return new Command55("status").description("Show mission progress and DAG stats").argument("<mission_id>", "Mission ID").option("--json", "Output as JSON").action(async (missionId, options) => {
30301
+ const client = getClient();
30302
+ const spinner = ora54("Fetching mission status...").start();
30303
+ try {
30304
+ const [mission, summary, dagStats] = await Promise.all([
30305
+ client.query(toFunctionName(api.research.getMission), { id: missionId }),
30306
+ client.query(toFunctionName(api.research.getExperimentSummary), { mission_id: missionId }),
30307
+ client.query(toFunctionName(api.experimentDag.getDAGStats), { mission_id: missionId })
30308
+ ]);
30309
+ spinner.stop();
30310
+ if (!mission) {
30311
+ console.log(chalk58.red("Mission not found."));
30312
+ return;
30313
+ }
30314
+ if (options.json) {
30315
+ console.log(JSON.stringify({ mission, summary, dagStats }, null, 2));
30316
+ return;
30317
+ }
30318
+ const statusColor = mission.status === "active" ? chalk58.green : mission.status === "completed" ? chalk58.blue : chalk58.yellow;
30319
+ console.log(chalk58.bold(`
30320
+ ${mission.title}`));
30321
+ console.log(` ${chalk58.dim("Status:")} ${statusColor(mission.status)} ${chalk58.dim("Type:")} ${mission.mission_type}`);
30322
+ console.log(` ${chalk58.dim("Question:")} ${mission.research_question}`);
30323
+ if (summary?.config) {
30324
+ const c = summary.config;
30325
+ const pct = c.max_experiments > 0 ? Math.round(c.experiments_completed / c.max_experiments * 100) : 0;
30326
+ console.log(chalk58.bold("\n Experiment Budget"));
30327
+ console.log(` ${progressBar3(pct, 30)} ${c.experiments_completed}/${c.max_experiments} experiments (${pct}%)`);
30328
+ console.log(` Cost: $${(c.cost_spent_usd || 0).toFixed(2)} / $${c.max_cost_usd}`);
30329
+ console.log(` Metric: ${c.primary_metric} (${c.metric_direction})`);
30330
+ if (c.best_metric_value !== void 0) {
30331
+ console.log(` ${chalk58.green("Best:")} ${c.best_metric_value}`);
30332
+ }
30333
+ }
30334
+ if (dagStats) {
30335
+ console.log(chalk58.bold("\n DAG Stats"));
30336
+ console.log(` Total nodes: ${dagStats.total_nodes}`);
30337
+ console.log(` Completed: ${dagStats.completed_nodes} / Running: ${dagStats.running_nodes} / Reverted: ${dagStats.reverted_nodes}`);
30338
+ console.log(` Max depth: ${dagStats.max_depth}`);
30339
+ console.log(` Frontier: ${dagStats.frontier_size} nodes`);
30340
+ console.log(` Agents: ${dagStats.unique_agents}`);
30341
+ }
30342
+ console.log();
30343
+ } catch (e) {
30344
+ spinner.fail(e.message);
30345
+ }
30346
+ });
30347
+ }
30348
+ function missionStopCommand() {
30349
+ return new Command55("stop").description("Complete a mission").argument("<mission_id>", "Mission ID").option("--conclusion <text>", "Conclusion summary").action(async (missionId, options) => {
30350
+ const client = getClient();
30351
+ const spinner = ora54("Completing mission...").start();
30352
+ try {
30353
+ await client.mutation(toFunctionName(api.research.completeMission), {
30354
+ mission_id: missionId,
30355
+ conclusion: options.conclusion || "Mission completed via Ralph Loop CLI."
30356
+ });
30357
+ spinner.succeed("Mission completed");
30358
+ } catch (e) {
30359
+ spinner.fail(e.message);
30360
+ }
30361
+ });
30362
+ }
30363
+ function missionAgentsCommand() {
30364
+ return new Command55("agents").description("Show best-fit agents for a mission (uses agent dispatch scoring)").argument("<mission_id>", "Mission ID").option("--limit <n>", "Max agents", "10").option("--json", "Output as JSON").action(async (missionId, options) => {
30365
+ const client = getClient();
30366
+ const spinner = ora54("Scoring agents for mission...").start();
30367
+ try {
30368
+ const [candidates, available] = await Promise.all([
30369
+ client.query(toFunctionName(api.agentDispatch.pickBestAgent), {
30370
+ mission_id: missionId
30371
+ }).catch(() => null),
30372
+ client.query(toFunctionName(api.agentDispatch.listAvailableAgents), {
30373
+ limit: parseInt(options.limit)
30374
+ })
30375
+ ]);
30376
+ spinner.stop();
30377
+ if (options.json) {
30378
+ console.log(JSON.stringify({ candidates, available }, null, 2));
30379
+ return;
30380
+ }
30381
+ if (candidates && candidates.length > 0) {
30382
+ console.log(chalk58.bold("\n Best-fit agents for this mission\n"));
30383
+ for (let i = 0; i < candidates.length; i++) {
30384
+ const c = candidates[i];
30385
+ const score = ((c.score ?? 0) * 100).toFixed(0);
30386
+ console.log(
30387
+ ` ${chalk58.dim(`${(i + 1).toString().padStart(2)}.`)} ${chalk58.bold(c.agent_id || c.username || "unknown")} ${chalk58.green(`${score}%`)} match ${chalk58.dim(`rep: ${((c.reputation ?? 0) * 100).toFixed(0)}%`)}`
30388
+ );
30389
+ }
30390
+ console.log();
30391
+ }
30392
+ const agents = available;
30393
+ if (agents && agents.length > 0) {
30394
+ console.log(chalk58.bold(` Available agents (${agents.length})
30395
+ `));
30396
+ for (const a of agents) {
30397
+ const rep = ((a.reputation ?? 0) * 100).toFixed(0);
30398
+ const load = a.running_tasks ?? 0;
30399
+ console.log(
30400
+ ` ${chalk58.white((a.agent_id || a.username || "\u2014").padEnd(24))} rep: ${chalk58.green(`${rep}%`.padEnd(6))} load: ${load === 0 ? chalk58.green("idle") : chalk58.yellow(`${load} tasks`)} ${chalk58.dim(a.platform || "")}`
30401
+ );
30402
+ }
30403
+ console.log();
30404
+ } else {
30405
+ console.log(chalk58.dim("\n No available agents found.\n"));
30406
+ }
30407
+ } catch (e) {
30408
+ spinner.fail(e.message);
30409
+ }
30410
+ });
30411
+ }
30412
+ function sleep2(ms) {
30413
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
30414
+ }
30415
+ function progressBar3(pct, width) {
30416
+ const filled = Math.round(pct / 100 * width);
30417
+ const empty = width - filled;
30418
+ return chalk58.green("\u2588".repeat(filled)) + chalk58.dim("\u2591".repeat(empty));
30419
+ }
30420
+
30421
+ // src/commands/meta.ts
30422
+ import { Command as Command56 } from "commander";
30423
+ import chalk59 from "chalk";
30424
+ import ora55 from "ora";
30425
+ import * as fs26 from "fs";
30426
+ import * as path26 from "path";
30427
+ import { parse as parseYaml10 } from "yaml";
30428
+ function getMetaSkillsDir() {
30429
+ const thisDir = path26.dirname(new URL(import.meta.url).pathname);
30430
+ const pkgRoot = path26.resolve(thisDir, "..", "..");
30431
+ return path26.join(pkgRoot, "meta-skills");
30432
+ }
30433
+ function getProjectSkillsDir() {
30434
+ return path26.join(process.cwd(), ".hubify", "skills");
30435
+ }
30436
+ function parseFrontmatter3(content) {
30437
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
30438
+ if (!match) return {};
30439
+ try {
30440
+ return parseYaml10(match[1]);
30441
+ } catch {
30442
+ return {};
30443
+ }
30444
+ }
30445
+ function loadMetaSkills() {
30446
+ const metaDir = getMetaSkillsDir();
30447
+ if (!fs26.existsSync(metaDir)) {
30448
+ return [];
30449
+ }
30450
+ const skills = [];
30451
+ const entries = fs26.readdirSync(metaDir, { withFileTypes: true });
30452
+ for (const entry of entries) {
30453
+ if (!entry.isDirectory()) continue;
30454
+ const skillMdPath = path26.join(metaDir, entry.name, "SKILL.md");
30455
+ if (!fs26.existsSync(skillMdPath)) continue;
30456
+ const content = fs26.readFileSync(skillMdPath, "utf-8");
30457
+ const fm = parseFrontmatter3(content);
30458
+ skills.push({
30459
+ name: fm.name || `hubify/${entry.name}`,
30460
+ dir: entry.name,
30461
+ version: typeof fm.version === "string" ? fm.version : String(fm.version || "1.0.0"),
30462
+ description: fm.description || "",
30463
+ category: fm.category || "meta",
30464
+ triggers: Array.isArray(fm.triggers) ? fm.triggers : [],
30465
+ outputs: Array.isArray(fm.outputs) ? fm.outputs : []
30466
+ });
30467
+ }
30468
+ return skills;
30469
+ }
30470
+ function metaListCommand() {
30471
+ return new Command56("list").description("List available meta-skills").option("--json", "Output as JSON").action(async (options) => {
30472
+ const skills = loadMetaSkills();
30473
+ if (skills.length === 0) {
30474
+ console.log(chalk59.dim("\n No meta-skills found.\n"));
30475
+ return;
30476
+ }
30477
+ if (options.json) {
30478
+ console.log(JSON.stringify(skills, null, 2));
30479
+ return;
30480
+ }
30481
+ console.log(chalk59.bold("\n Hubify Meta-Skills\n"));
30482
+ console.log(chalk59.gray(" System skills that help agents interact with the Hubify platform.\n"));
30483
+ for (const skill of skills) {
30484
+ console.log(
30485
+ ` ${chalk59.cyan(skill.name.padEnd(26))} ${chalk59.white(`v${skill.version}`)} ${chalk59.gray(skill.description)}`
30486
+ );
30487
+ if (skill.triggers.length > 0) {
30488
+ console.log(
30489
+ ` ${" ".repeat(26)} ${chalk59.dim("triggers:")} ${chalk59.dim(skill.triggers.slice(0, 3).join(", "))}`
30490
+ );
30491
+ }
30492
+ console.log();
30493
+ }
30494
+ const projectDir = getProjectSkillsDir();
30495
+ if (fs26.existsSync(projectDir)) {
30496
+ const installed = skills.filter(
30497
+ (s) => fs26.existsSync(path26.join(projectDir, s.dir, "SKILL.md"))
30498
+ );
30499
+ if (installed.length > 0) {
30500
+ console.log(
30501
+ chalk59.green(` ${installed.length}/${skills.length} installed in this project`)
30502
+ );
30503
+ } else {
30504
+ console.log(chalk59.dim(" None installed in this project."));
30505
+ console.log(chalk59.dim(" Run: hubify meta install"));
30506
+ }
30507
+ } else {
30508
+ console.log(chalk59.dim(" Not a Hubify project. Run: hubify init"));
30509
+ }
30510
+ console.log();
30511
+ });
30512
+ }
30513
+ function metaInstallCommand() {
30514
+ return new Command56("install").description("Install meta-skills into the current project").argument("[name]", "Specific meta-skill to install (e.g., find-skills). Installs all if omitted.").option("--force", "Overwrite existing meta-skills").action(async (name, options) => {
30515
+ const spinner = ora55();
30516
+ const skills = loadMetaSkills();
30517
+ if (skills.length === 0) {
30518
+ console.log(chalk59.red("\n No meta-skills found in package.\n"));
30519
+ process.exit(1);
30520
+ }
30521
+ const toInstall = name ? skills.filter((s) => s.dir === name || s.name === name || s.name === `hubify/${name}`) : skills;
30522
+ if (toInstall.length === 0) {
30523
+ console.log(chalk59.red(`
30524
+ Meta-skill "${name}" not found.`));
30525
+ console.log(chalk59.gray(" Available: " + skills.map((s) => s.dir).join(", ")));
30526
+ console.log();
30527
+ process.exit(1);
30528
+ }
30529
+ const projectDir = getProjectSkillsDir();
30530
+ const metaDir = getMetaSkillsDir();
30531
+ if (!fs26.existsSync(projectDir)) {
30532
+ fs26.mkdirSync(projectDir, { recursive: true });
30533
+ }
30534
+ spinner.start(`Installing ${toInstall.length} meta-skill(s)...`);
30535
+ let installed = 0;
30536
+ let skipped = 0;
30537
+ for (const skill of toInstall) {
30538
+ const srcDir = path26.join(metaDir, skill.dir);
30539
+ const destDir = path26.join(projectDir, skill.dir);
30540
+ if (fs26.existsSync(destDir) && !options.force) {
30541
+ skipped++;
30542
+ continue;
30543
+ }
30544
+ fs26.mkdirSync(destDir, { recursive: true });
30545
+ const srcFile = path26.join(srcDir, "SKILL.md");
30546
+ const destFile = path26.join(destDir, "SKILL.md");
30547
+ fs26.copyFileSync(srcFile, destFile);
30548
+ installed++;
30549
+ }
30550
+ if (installed > 0 && skipped > 0) {
30551
+ spinner.succeed(
30552
+ `Installed ${installed} meta-skill(s), skipped ${skipped} (already installed)`
30553
+ );
30554
+ } else if (installed > 0) {
30555
+ spinner.succeed(`Installed ${installed} meta-skill(s)`);
30556
+ } else {
30557
+ spinner.info(`All ${skipped} meta-skill(s) already installed (use --force to overwrite)`);
30558
+ }
30559
+ console.log(chalk59.gray(`
30560
+ Location: ${projectDir}`));
30561
+ if (installed > 0) {
30562
+ console.log(chalk59.gray(" Installed:"));
30563
+ for (const skill of toInstall) {
30564
+ const destDir = path26.join(projectDir, skill.dir);
30565
+ if (fs26.existsSync(path26.join(destDir, "SKILL.md"))) {
30566
+ console.log(` ${chalk59.cyan(skill.name)}`);
30567
+ }
30568
+ }
30569
+ }
30570
+ console.log();
30571
+ });
30572
+ }
30573
+ function metaRunCommand() {
30574
+ return new Command56("run").description("Execute a meta-skill").argument("<name>", "Meta-skill name (e.g., find-skills, create-skill)").argument("[args...]", "Arguments to pass to the meta-skill").option("--json", "Output as JSON").action(async (name, args, options) => {
30575
+ const spinner = ora55();
30576
+ const skills = loadMetaSkills();
30577
+ const skill = skills.find(
30578
+ (s) => s.dir === name || s.name === name || s.name === `hubify/${name}`
30579
+ );
30580
+ if (!skill) {
30581
+ console.log(chalk59.red(`
30582
+ Meta-skill "${name}" not found.`));
30583
+ console.log(chalk59.gray(" Available: " + skills.map((s) => s.dir).join(", ")));
30584
+ console.log();
30585
+ process.exit(1);
30586
+ }
30587
+ const query = args.join(" ");
30588
+ switch (skill.dir) {
30589
+ case "find-skills":
30590
+ await runFindSkills(query, options, spinner);
30591
+ break;
30592
+ case "create-skill":
30593
+ await runCreateSkill(query, options, spinner);
30594
+ break;
30595
+ case "update-skills":
30596
+ await runUpdateSkills(query, options, spinner);
30597
+ break;
30598
+ case "chain-skills":
30599
+ await runChainSkills(query, options, spinner);
30600
+ break;
30601
+ default:
30602
+ console.log(chalk59.yellow(`
30603
+ Meta-skill "${skill.name}" does not have a run handler yet.`));
30604
+ console.log(chalk59.gray(" You can read its instructions:"));
30605
+ console.log(chalk59.cyan(` cat ${path26.join(getMetaSkillsDir(), skill.dir, "SKILL.md")}`));
30606
+ console.log();
30607
+ }
30608
+ });
30609
+ }
30610
+ async function runFindSkills(query, options, spinner) {
30611
+ if (!query) {
30612
+ console.log(chalk59.red("\n Usage: hubify meta run find-skills <search query>"));
30613
+ console.log(chalk59.gray(" Example: hubify meta run find-skills web scraping\n"));
30614
+ process.exit(1);
30615
+ }
30616
+ spinner.start(`Searching registry for "${query}"...`);
30617
+ try {
30618
+ const client = getClient();
30619
+ const results = await client.query(toFunctionName(api.skills.search), {
30620
+ query,
30621
+ limit: 10
30622
+ });
30623
+ spinner.stop();
30624
+ const skills = results;
30625
+ if (options.json) {
30626
+ console.log(JSON.stringify(skills, null, 2));
30627
+ return;
30628
+ }
30629
+ if (!skills || skills.length === 0) {
30630
+ console.log(chalk59.dim(`
30631
+ No skills found for "${query}".`));
30632
+ console.log(chalk59.dim(" Try broader search terms or different keywords.\n"));
30633
+ return;
30634
+ }
30635
+ console.log(chalk59.bold(`
30636
+ Results for "${query}" (${skills.length} found)
30637
+ `));
30638
+ for (let i = 0; i < skills.length; i++) {
30639
+ const s = skills[i];
30640
+ const confidence = typeof s.confidence === "number" ? s.confidence.toFixed(2) : "0.00";
30641
+ const executions = s.executions || 0;
30642
+ const verified = s.verification_level ? `L${s.verification_level}` : "L0";
30643
+ console.log(
30644
+ ` ${chalk59.dim(`${i + 1}.`)} ${chalk59.bold(s.name)}`
30645
+ );
30646
+ console.log(
30647
+ ` ${chalk59.dim("Confidence:")} ${chalk59.white(confidence)} ${chalk59.dim("|")} ${chalk59.dim("Verified:")} ${chalk59.white(verified)} ${chalk59.dim("|")} ${chalk59.dim("Executions:")} ${chalk59.white(String(executions))}`
30648
+ );
30649
+ if (s.description) {
30650
+ console.log(` ${chalk59.gray(s.description)}`);
30651
+ }
30652
+ console.log();
30653
+ }
30654
+ console.log(chalk59.dim(" Install a skill: hubify install <skill-name>"));
30655
+ console.log(chalk59.dim(" More details: hubify info <skill-name>\n"));
30656
+ } catch (error) {
30657
+ spinner.fail("Search failed");
30658
+ console.error(chalk59.red(` ${error.message}
30659
+ `));
30660
+ }
30661
+ }
30662
+ async function runCreateSkill(description, options, spinner) {
30663
+ if (!description) {
30664
+ console.log(chalk59.red("\n Usage: hubify meta run create-skill <description>"));
30665
+ console.log(chalk59.gray(' Example: hubify meta run create-skill "skill for parsing CSV files"\n'));
30666
+ process.exit(1);
30667
+ }
30668
+ console.log(chalk59.bold("\n Create Skill\n"));
30669
+ console.log(chalk59.gray(" Delegating to the skill generator...\n"));
30670
+ console.log(chalk59.white(" Run this command directly:"));
30671
+ console.log(chalk59.cyan(` hubify generate "${description}"
30672
+ `));
30673
+ console.log(chalk59.gray(" Options:"));
30674
+ console.log(chalk59.gray(" --category <cat> Skill category"));
30675
+ console.log(chalk59.gray(" --name <name> Override auto-generated name"));
30676
+ console.log(chalk59.gray(" --publish Auto-publish after generation"));
30677
+ console.log(chalk59.gray(" --template Use template-based generation (no AI)"));
30678
+ console.log(chalk59.gray(" --dry-run Preview without saving"));
30679
+ try {
30680
+ spinner.start("Queuing generation in registry...");
30681
+ const client = getClient();
30682
+ const result = await client.mutation(
30683
+ toFunctionName(api.skillGeneration.queueGeneration),
30684
+ {
30685
+ prompt: description,
30686
+ requested_by: process.env.USER || "cli",
30687
+ category: "coding"
30688
+ }
30689
+ );
30690
+ spinner.succeed("Generation queued in registry");
30691
+ const r = result;
30692
+ if (r && r._id) {
30693
+ console.log(chalk59.gray(`
30694
+ Generation ID: ${r._id}`));
30695
+ console.log(chalk59.gray(" Check status: hubify skill-gen list\n"));
30696
+ }
30697
+ } catch {
30698
+ spinner.info("Remote generation not available. Use hubify generate locally.");
30699
+ console.log();
30700
+ }
30701
+ }
30702
+ async function runUpdateSkills(skillName, options, spinner) {
30703
+ const projectDir = getProjectSkillsDir();
30704
+ if (!fs26.existsSync(projectDir)) {
30705
+ console.log(chalk59.red("\n No .hubify/skills directory found."));
30706
+ console.log(chalk59.gray(" Run: hubify init\n"));
30707
+ process.exit(1);
30708
+ }
30709
+ spinner.start("Scanning installed skills...");
30710
+ const entries = fs26.readdirSync(projectDir, { withFileTypes: true });
30711
+ const installed = [];
30712
+ for (const entry of entries) {
30713
+ if (!entry.isDirectory()) continue;
30714
+ const skillMdPath = path26.join(projectDir, entry.name, "SKILL.md");
30715
+ if (!fs26.existsSync(skillMdPath)) continue;
30716
+ const content = fs26.readFileSync(skillMdPath, "utf-8");
30717
+ const fm = parseFrontmatter3(content);
30718
+ const name = fm.name || entry.name;
30719
+ const version = typeof fm.version === "string" ? fm.version : String(fm.version || "0.0.0");
30720
+ if (skillName && name !== skillName && entry.name !== skillName) continue;
30721
+ installed.push({ name, localVersion: version, dir: entry.name });
30722
+ }
30723
+ if (installed.length === 0) {
30724
+ spinner.info(skillName ? `Skill "${skillName}" not found locally.` : "No installed skills found.");
30725
+ console.log();
30726
+ return;
30727
+ }
30728
+ spinner.text = `Checking updates for ${installed.length} skill(s)...`;
30729
+ const client = getClient();
30730
+ const updates = [];
30731
+ const upToDate = [];
30732
+ const notInRegistry = [];
30733
+ for (const skill of installed) {
30734
+ try {
30735
+ const lookupName = skill.name.replace(/^hubify\//, "");
30736
+ const remote = await client.query(toFunctionName(api.skills.getByName), {
30737
+ name: lookupName
30738
+ });
30739
+ if (!remote) {
30740
+ notInRegistry.push(skill.name);
30741
+ continue;
30742
+ }
30743
+ const r = remote;
30744
+ const remoteVersion = r.version || "0.0.0";
30745
+ const confidence = r.confidence || 0;
30746
+ if (remoteVersion !== skill.localVersion) {
30747
+ updates.push({
30748
+ name: skill.name,
30749
+ local: skill.localVersion,
30750
+ remote: remoteVersion,
30751
+ confidence
30752
+ });
30753
+ } else {
30754
+ upToDate.push(skill.name);
30755
+ }
30756
+ } catch {
30757
+ notInRegistry.push(skill.name);
30758
+ }
30759
+ }
30760
+ spinner.stop();
30761
+ if (options.json) {
30762
+ console.log(JSON.stringify({ updates, upToDate, notInRegistry }, null, 2));
30763
+ return;
30764
+ }
30765
+ console.log(chalk59.bold(`
30766
+ Skill Update Check (${installed.length} installed)
30767
+ `));
30768
+ if (updates.length > 0) {
30769
+ console.log(chalk59.yellow(` Updates available (${updates.length}):
30770
+ `));
30771
+ for (const u of updates) {
30772
+ console.log(` ${chalk59.bold(u.name)}`);
30773
+ console.log(
30774
+ ` ${chalk59.dim("Local:")} ${u.local} ${chalk59.dim("->")} ${chalk59.green(u.remote)} ${chalk59.dim("Confidence:")} ${u.confidence.toFixed(2)}`
30775
+ );
30776
+ }
30777
+ console.log();
30778
+ console.log(chalk59.dim(" Update a skill: hubify install <skill-name>"));
30779
+ } else {
30780
+ console.log(chalk59.green(" All skills are up to date."));
30781
+ }
30782
+ if (upToDate.length > 0) {
30783
+ console.log(chalk59.dim(`
30784
+ Up to date (${upToDate.length}): ${upToDate.join(", ")}`));
30785
+ }
30786
+ if (notInRegistry.length > 0) {
30787
+ console.log(chalk59.dim(`
30788
+ Not in registry (${notInRegistry.length}): ${notInRegistry.join(", ")}`));
30789
+ }
30790
+ console.log();
30791
+ }
30792
+ async function runChainSkills(skillList, options, spinner) {
30793
+ if (!skillList) {
30794
+ console.log(chalk59.red("\n Usage: hubify meta run chain-skills <skill1,skill2,skill3>"));
30795
+ console.log(chalk59.gray(" Example: hubify meta run chain-skills web-research,data-analysis,email-draft\n"));
30796
+ process.exit(1);
30797
+ }
30798
+ const skillNames = skillList.split(",").map((s) => s.trim()).filter(Boolean);
30799
+ if (skillNames.length < 2) {
30800
+ console.log(chalk59.red("\n A chain requires at least 2 skills."));
30801
+ console.log(chalk59.gray(" Separate skill names with commas.\n"));
30802
+ process.exit(1);
30803
+ }
30804
+ spinner.start(`Validating ${skillNames.length} skills...`);
30805
+ const client = getClient();
30806
+ const validSkills = [];
30807
+ const missing = [];
30808
+ for (const name of skillNames) {
30809
+ try {
30810
+ const result = await client.query(toFunctionName(api.skills.getByName), { name });
30811
+ if (result) {
30812
+ const r = result;
30813
+ validSkills.push({
30814
+ name: r.name,
30815
+ description: r.description || "",
30816
+ confidence: r.confidence || 0
30817
+ });
30818
+ } else {
30819
+ missing.push(name);
30820
+ }
30821
+ } catch {
30822
+ missing.push(name);
30823
+ }
30824
+ }
30825
+ spinner.stop();
30826
+ if (missing.length > 0) {
30827
+ console.log(chalk59.yellow(`
30828
+ Warning: ${missing.length} skill(s) not found in registry:`));
30829
+ for (const m of missing) {
30830
+ console.log(chalk59.dim(` - ${m}`));
30831
+ }
30832
+ console.log(chalk59.dim(" These steps will still be included in the chain definition.\n"));
30833
+ }
30834
+ const chainName = skillNames.slice(0, 3).join("-then-");
30835
+ const steps = skillNames.map((name, i) => ({
30836
+ id: `step_${i + 1}`,
30837
+ skill_name: name,
30838
+ depends_on: i === 0 ? [] : [`step_${i}`],
30839
+ on_fail: i === skillNames.length - 1 ? "abort" : "retry"
30840
+ }));
30841
+ const chainDef = {
30842
+ name: chainName,
30843
+ description: `Chain: ${skillNames.join(" -> ")}`,
30844
+ steps
30845
+ };
30846
+ if (options.json) {
30847
+ console.log(JSON.stringify(chainDef, null, 2));
30848
+ return;
30849
+ }
30850
+ console.log(chalk59.bold(`
30851
+ Skill Chain: ${chainName}
30852
+ `));
30853
+ console.log(chalk59.gray(` Flow: ${skillNames.join(chalk59.dim(" -> "))}
30854
+ `));
30855
+ for (let i = 0; i < steps.length; i++) {
30856
+ const step = steps[i];
30857
+ const valid = validSkills.find((s) => s.name === step.skill_name);
30858
+ const statusIcon = valid ? chalk59.green("[OK]") : chalk59.yellow("[??]");
30859
+ const conf = valid ? chalk59.dim(`(${valid.confidence.toFixed(2)})`) : "";
30860
+ console.log(
30861
+ ` ${chalk59.dim(`${i + 1}.`)} ${statusIcon} ${chalk59.bold(step.skill_name)} ${conf}`
30862
+ );
30863
+ if (valid?.description) {
30864
+ console.log(` ${chalk59.gray(valid.description)}`);
30865
+ }
30866
+ console.log(
30867
+ ` ${chalk59.dim("on_fail:")} ${step.on_fail} ${chalk59.dim("| depends:")} ${step.depends_on.length === 0 ? "none" : step.depends_on.join(", ")}`
30868
+ );
30869
+ }
30870
+ console.log(chalk59.gray("\n To create this workflow:"));
30871
+ console.log(chalk59.cyan(` hubify workflow create --name "${chainName}" --steps '${JSON.stringify(steps)}'`));
30872
+ console.log(chalk59.gray("\n To run an existing workflow:"));
30873
+ console.log(chalk59.cyan(` hubify workflow run ${chainName}
30874
+ `));
30875
+ }
30876
+ var metaCommand = new Command56("meta").description("Meta-skills \u2014 system skills for interacting with the Hubify platform").addCommand(metaListCommand()).addCommand(metaInstallCommand()).addCommand(metaRunCommand());
30877
+
30878
+ // src/commands/self-update.ts
30879
+ import { Command as Command57 } from "commander";
30880
+ import chalk60 from "chalk";
30881
+ import ora56 from "ora";
30882
+ import { execSync as execSync2 } from "child_process";
30883
+ import fs27 from "fs";
30884
+ function getCliVersion() {
30885
+ try {
30886
+ const pkgUrl = new URL("../../package.json", import.meta.url);
30887
+ const pkg = JSON.parse(fs27.readFileSync(pkgUrl, "utf8"));
30888
+ return pkg.version || "0.0.0";
30889
+ } catch {
30890
+ return "0.0.0";
30891
+ }
30892
+ }
30893
+ function getLatestNpmVersion(packageName) {
30894
+ try {
30895
+ const output = execSync2(`npm view ${packageName} version`, {
30896
+ encoding: "utf-8",
30897
+ timeout: 15e3,
30898
+ stdio: ["pipe", "pipe", "pipe"]
30899
+ });
30900
+ return output.trim();
30901
+ } catch {
30902
+ return null;
30903
+ }
30904
+ }
30905
+ function isNewerVersion(current, latest) {
30906
+ const c = current.split(".").map(Number);
30907
+ const l = latest.split(".").map(Number);
30908
+ for (let i = 0; i < 3; i++) {
30909
+ if ((l[i] ?? 0) > (c[i] ?? 0)) return true;
30910
+ if ((l[i] ?? 0) < (c[i] ?? 0)) return false;
30911
+ }
30912
+ return false;
30913
+ }
30914
+ var selfUpdateCommand = new Command57("self-update").description("Check for and install CLI updates").option("--check", "Only check for updates, do not install").option("--force", "Force reinstall even if already up to date").action(async (options) => {
30915
+ const currentVersion = getCliVersion();
30916
+ console.log();
30917
+ console.log(
30918
+ chalk60.cyan.bold(" Hubify Self-Update")
30919
+ );
30920
+ console.log(
30921
+ chalk60.gray(` Current version: ${currentVersion}`)
30922
+ );
30923
+ console.log();
30924
+ const spinner = ora56("Checking for updates...").start();
30925
+ const latestVersion = getLatestNpmVersion("hubify");
30926
+ if (!latestVersion) {
30927
+ spinner.fail("Could not reach npm registry.");
30928
+ console.log(
30929
+ chalk60.gray(
30930
+ "\n Check your internet connection and try again.\n"
30931
+ )
30932
+ );
30933
+ return;
30934
+ }
30935
+ spinner.stop();
30936
+ const hasUpdate = isNewerVersion(currentVersion, latestVersion);
30937
+ if (!hasUpdate && !options.force) {
30938
+ console.log(
30939
+ chalk60.green(` Already up to date (v${currentVersion}).`)
30940
+ );
30941
+ console.log();
30942
+ return;
30943
+ }
30944
+ if (hasUpdate) {
30945
+ console.log(
30946
+ chalk60.white(
30947
+ ` Update available: ${chalk60.gray(currentVersion)} -> ${chalk60.green(latestVersion)}`
30948
+ )
30949
+ );
30950
+ console.log();
30951
+ } else if (options.force) {
30952
+ console.log(
30953
+ chalk60.yellow(` Forcing reinstall of v${latestVersion}...`)
30954
+ );
30955
+ console.log();
30956
+ }
30957
+ if (options.check) {
30958
+ if (hasUpdate) {
30959
+ console.log(
30960
+ chalk60.gray(
30961
+ " Run " + chalk60.cyan("hubify self-update") + " to install the update."
30962
+ )
30963
+ );
30964
+ }
30965
+ console.log();
30966
+ return;
30967
+ }
30968
+ const updateSpinner = ora56(
30969
+ `Installing hubify@${latestVersion}...`
30970
+ ).start();
30971
+ try {
30972
+ execSync2(`npm install -g hubify@${latestVersion}`, {
30973
+ encoding: "utf-8",
30974
+ timeout: 12e4,
30975
+ stdio: ["pipe", "pipe", "pipe"]
30976
+ });
30977
+ updateSpinner.succeed(
30978
+ `Updated to hubify@${latestVersion}`
30979
+ );
30980
+ console.log();
30981
+ console.log(
30982
+ chalk60.green(" Update complete!") + chalk60.gray(
30983
+ " Run " + chalk60.cyan("hubify --version") + " to confirm."
30984
+ )
30985
+ );
30986
+ console.log();
30987
+ } catch (err) {
30988
+ updateSpinner.fail("Update failed.");
30989
+ console.log();
30990
+ const errMsg = err instanceof Error ? err.message : String(err);
30991
+ if (errMsg.includes("EACCES") || errMsg.includes("permission")) {
30992
+ console.log(
30993
+ chalk60.yellow(
30994
+ " Permission denied. Try running with sudo:"
30995
+ )
30996
+ );
30997
+ console.log(
30998
+ chalk60.cyan(
30999
+ ` sudo npm install -g hubify@${latestVersion}`
31000
+ )
31001
+ );
31002
+ } else {
31003
+ console.log(chalk60.red(` ${errMsg}`));
31004
+ }
31005
+ console.log();
31006
+ }
31007
+ });
31008
+
31009
+ // src/index.ts
31010
+ function getCliVersion2() {
31011
+ try {
31012
+ const pkgUrl = new URL("../package.json", import.meta.url);
31013
+ const pkg = JSON.parse(fs28.readFileSync(pkgUrl, "utf8"));
31014
+ return pkg.version || "0.0.0";
31015
+ } catch {
31016
+ return "0.0.0";
31017
+ }
31018
+ }
31019
+ var VERSION = getCliVersion2();
31020
+ var BANNER = `
31021
+ ${chalk61.cyan(" __ __ __ _ ____ ")}
31022
+ ${chalk61.cyan(" / / / /_ __/ /_ (_) __/_ __")}
31023
+ ${chalk61.cyan(" / /_/ / / / / __ \\/ / /_/ / / /")}
31024
+ ${chalk61.cyan(" / __ / /_/ / /_/ / / __/ /_/ / ")}
31025
+ ${chalk61.cyan("/_/ /_/\\__,_/_.___/_/_/ \\__, / ")}
31026
+ ${chalk61.cyan(" /____/ ")}
28766
31027
  `;
28767
- var TAGLINE = chalk56.gray(" The living intelligence layer for Agent Skills");
31028
+ var TAGLINE = chalk61.gray(" The living intelligence layer for Agent Skills");
28768
31029
  function showWelcome() {
28769
31030
  console.log(BANNER);
28770
31031
  console.log(TAGLINE);
28771
31032
  console.log();
28772
- console.log(chalk56.white.bold(" Welcome to Hubify!"));
31033
+ console.log(chalk61.white.bold(" Welcome to Hubify!"));
28773
31034
  console.log();
28774
- console.log(chalk56.gray(" Hubify is the universal skill registry for AI coding agents."));
28775
- console.log(chalk56.gray(" Discover, install, and share agent skills with trust metrics."));
31035
+ console.log(chalk61.gray(" Hubify is the universal skill registry for AI coding agents."));
31036
+ console.log(chalk61.gray(" Discover, install, and share agent skills with trust metrics."));
28776
31037
  console.log();
28777
- console.log(chalk56.cyan.bold(" Quick Start"));
28778
- console.log(chalk56.gray(" -----------"));
31038
+ console.log(chalk61.cyan.bold(" Quick Start"));
31039
+ console.log(chalk61.gray(" -----------"));
28779
31040
  console.log();
28780
- console.log(chalk56.white(" 1. Initialize Hubify in your project:"));
28781
- console.log(chalk56.cyan(" $ hubify init"));
31041
+ console.log(chalk61.white(" 1. Initialize Hubify in your project:"));
31042
+ console.log(chalk61.cyan(" $ hubify init"));
28782
31043
  console.log();
28783
- console.log(chalk56.white(" 2. Search for skills:"));
28784
- console.log(chalk56.cyan(' $ hubify search "react best practices"'));
31044
+ console.log(chalk61.white(" 2. Search for skills:"));
31045
+ console.log(chalk61.cyan(' $ hubify search "react best practices"'));
28785
31046
  console.log();
28786
- console.log(chalk56.white(" 3. Install a skill:"));
28787
- console.log(chalk56.cyan(" $ hubify install vercel-react-best-practices"));
31047
+ console.log(chalk61.white(" 3. Install a skill:"));
31048
+ console.log(chalk61.cyan(" $ hubify install vercel-react-best-practices"));
28788
31049
  console.log();
28789
- console.log(chalk56.white(" 4. Report your execution results:"));
28790
- console.log(chalk56.cyan(" $ hubify report vercel-react-best-practices --success"));
31050
+ console.log(chalk61.white(" 4. Report your execution results:"));
31051
+ console.log(chalk61.cyan(" $ hubify report vercel-react-best-practices --success"));
28791
31052
  console.log();
28792
- console.log(chalk56.cyan.bold(" Common Commands"));
28793
- console.log(chalk56.gray(" ---------------"));
31053
+ console.log(chalk61.cyan.bold(" Common Commands"));
31054
+ console.log(chalk61.gray(" ---------------"));
28794
31055
  console.log();
28795
- console.log(chalk56.white(" hubify search <query> ") + chalk56.gray("Search for skills"));
28796
- console.log(chalk56.white(" hubify install <skill> ") + chalk56.gray("Install a skill locally"));
28797
- console.log(chalk56.white(" hubify info <skill> ") + chalk56.gray("View skill details"));
28798
- console.log(chalk56.white(" hubify list ") + chalk56.gray("List installed skills"));
28799
- console.log(chalk56.white(" hubify publish <path> ") + chalk56.gray("Publish your skill"));
28800
- console.log(chalk56.white(" hubify stats ") + chalk56.gray("View registry statistics"));
31056
+ console.log(chalk61.white(" hubify search <query> ") + chalk61.gray("Search for skills"));
31057
+ console.log(chalk61.white(" hubify install <skill> ") + chalk61.gray("Install a skill locally"));
31058
+ console.log(chalk61.white(" hubify info <skill> ") + chalk61.gray("View skill details"));
31059
+ console.log(chalk61.white(" hubify list ") + chalk61.gray("List installed skills"));
31060
+ console.log(chalk61.white(" hubify publish <path> ") + chalk61.gray("Publish your skill"));
31061
+ console.log(chalk61.white(" hubify stats ") + chalk61.gray("View registry statistics"));
28801
31062
  console.log();
28802
- console.log(chalk56.gray(" Run ") + chalk56.cyan("hubify --help") + chalk56.gray(" for all commands."));
28803
- console.log(chalk56.gray(" Run ") + chalk56.cyan("hubify <command> --help") + chalk56.gray(" for command details."));
31063
+ console.log(chalk61.gray(" Run ") + chalk61.cyan("hubify --help") + chalk61.gray(" for all commands."));
31064
+ console.log(chalk61.gray(" Run ") + chalk61.cyan("hubify <command> --help") + chalk61.gray(" for command details."));
28804
31065
  console.log();
28805
- console.log(chalk56.gray(" ") + chalk56.dim(`v${VERSION}`) + chalk56.gray(" | ") + chalk56.dim(REGISTRY_URL));
31066
+ console.log(chalk61.gray(" ") + chalk61.dim(`v${VERSION}`) + chalk61.gray(" | ") + chalk61.dim(REGISTRY_URL));
28806
31067
  console.log();
28807
31068
  }
28808
31069
  function formatGroupedHelp() {
@@ -28810,10 +31071,10 @@ function formatGroupedHelp() {
28810
31071
  sections.push(BANNER);
28811
31072
  sections.push(TAGLINE);
28812
31073
  sections.push("");
28813
- sections.push(chalk56.white.bold("Usage:") + chalk56.gray(" hubify [command] [options]"));
31074
+ sections.push(chalk61.white.bold("Usage:") + chalk61.gray(" hubify [command] [options]"));
28814
31075
  sections.push("");
28815
- sections.push(chalk56.cyan.bold("Souls"));
28816
- sections.push(chalk56.gray(" AI personality and behavior templates"));
31076
+ sections.push(chalk61.cyan.bold("Souls"));
31077
+ sections.push(chalk61.gray(" AI personality and behavior templates"));
28817
31078
  sections.push("");
28818
31079
  sections.push(formatCommand("soul list", "List all available souls"));
28819
31080
  sections.push(formatCommand("soul info <name>", "View detailed information about a soul"));
@@ -28822,8 +31083,8 @@ function formatGroupedHelp() {
28822
31083
  sections.push(formatCommand("soul publish <path>", "Publish a soul to the registry"));
28823
31084
  sections.push(formatCommand("soul search <query>", "Search for souls by description"));
28824
31085
  sections.push("");
28825
- sections.push(chalk56.cyan.bold("Tools"));
28826
- sections.push(chalk56.gray(" Standardized tool definitions and integrations"));
31086
+ sections.push(chalk61.cyan.bold("Tools"));
31087
+ sections.push(chalk61.gray(" Standardized tool definitions and integrations"));
28827
31088
  sections.push("");
28828
31089
  sections.push(formatCommand("tool list", "List all tools in the registry"));
28829
31090
  sections.push(formatCommand("tool info <name>", "View detailed information about a tool"));
@@ -28831,8 +31092,8 @@ function formatGroupedHelp() {
28831
31092
  sections.push(formatCommand("tool search <query>", "Search for tools by description"));
28832
31093
  sections.push(formatCommand("tool stats", "Show tool registry statistics"));
28833
31094
  sections.push("");
28834
- sections.push(chalk56.cyan.bold("Skills"));
28835
- sections.push(chalk56.gray(" Discovery and management of agent skills"));
31095
+ sections.push(chalk61.cyan.bold("Skills"));
31096
+ sections.push(chalk61.gray(" Discovery and management of agent skills"));
28836
31097
  sections.push("");
28837
31098
  sections.push(formatCommand("search <query>", "Search for skills by name, description, or tags"));
28838
31099
  sections.push(formatCommand("info <skill>", "View detailed information about a skill"));
@@ -28841,8 +31102,8 @@ function formatGroupedHelp() {
28841
31102
  sections.push(formatCommand("list", "List installed skills in project or globally"));
28842
31103
  sections.push(formatCommand("update [skill]", "Update installed skills to latest versions"));
28843
31104
  sections.push("");
28844
- sections.push(chalk56.cyan.bold("Publishing"));
28845
- sections.push(chalk56.gray(" Create and share your own skills"));
31105
+ sections.push(chalk61.cyan.bold("Publishing"));
31106
+ sections.push(chalk61.gray(" Create and share your own skills"));
28846
31107
  sections.push("");
28847
31108
  sections.push(formatCommand("init", "Initialize Hubify in your project"));
28848
31109
  sections.push(formatCommand("publish <path>", "Publish a skill to the registry"));
@@ -28850,31 +31111,31 @@ function formatGroupedHelp() {
28850
31111
  sections.push(formatCommand("evolve <skill>", "Evolve a skill based on feedback"));
28851
31112
  sections.push(formatCommand("import <url>", "Import a skill from external source"));
28852
31113
  sections.push("");
28853
- sections.push(chalk56.cyan.bold(".hub Manifests"));
28854
- sections.push(chalk56.gray(" Manage skill/agent manifest files"));
31114
+ sections.push(chalk61.cyan.bold(".hub Manifests"));
31115
+ sections.push(chalk61.gray(" Manage skill/agent manifest files"));
28855
31116
  sections.push("");
28856
31117
  sections.push(formatCommand("hub init [dir]", "Create a .hub manifest file"));
28857
31118
  sections.push(formatCommand("hub validate <file>", "Validate a .hub file against schema"));
28858
31119
  sections.push(formatCommand("hub update <file>", "Update hashes and timestamps"));
28859
31120
  sections.push(formatCommand("hub info <file>", "Display .hub file information"));
28860
31121
  sections.push("");
28861
- sections.push(chalk56.cyan.bold("Analytics"));
28862
- sections.push(chalk56.gray(" Track and report skill executions"));
31122
+ sections.push(chalk61.cyan.bold("Analytics"));
31123
+ sections.push(chalk61.gray(" Track and report skill executions"));
28863
31124
  sections.push("");
28864
31125
  sections.push(formatCommand("report <skill>", "Report skill execution results"));
28865
31126
  sections.push(formatCommand("report stats [skill]", "View execution statistics"));
28866
31127
  sections.push(formatCommand("report leaderboard", "Show top skills by executions"));
28867
31128
  sections.push(formatCommand("stats", "View registry-wide statistics"));
28868
31129
  sections.push("");
28869
- sections.push(chalk56.cyan.bold("Authentication"));
28870
- sections.push(chalk56.gray(" Manage CLI authentication and API tokens"));
31130
+ sections.push(chalk61.cyan.bold("Authentication"));
31131
+ sections.push(chalk61.gray(" Manage CLI authentication and API tokens"));
28871
31132
  sections.push("");
28872
31133
  sections.push(formatCommand("auth login --token <t>", "Authenticate with an API token"));
28873
31134
  sections.push(formatCommand("auth whoami", "Show current identity and token status"));
28874
31135
  sections.push(formatCommand("auth logout", "Remove stored credentials"));
28875
31136
  sections.push("");
28876
- sections.push(chalk56.cyan.bold("Learning & Evolution"));
28877
- sections.push(chalk56.gray(" Skill intelligence, evolution tracking, and canary management"));
31137
+ sections.push(chalk61.cyan.bold("Learning & Evolution"));
31138
+ sections.push(chalk61.gray(" Skill intelligence, evolution tracking, and canary management"));
28878
31139
  sections.push("");
28879
31140
  sections.push(formatCommand("learn stats <skill>", "Get learning statistics for a skill"));
28880
31141
  sections.push(formatCommand("learn lineage <skill>", "Show full evolution tree"));
@@ -28883,8 +31144,8 @@ function formatGroupedHelp() {
28883
31144
  sections.push(formatCommand("learn triggers <skill>", "Detect evolution triggers"));
28884
31145
  sections.push(formatCommand("learn status <skill>", "Evolution status overview"));
28885
31146
  sections.push("");
28886
- sections.push(chalk56.cyan.bold("Labs"));
28887
- sections.push(chalk56.gray(" Experiment swarms, DAGs, and frontier discovery"));
31147
+ sections.push(chalk61.cyan.bold("Labs"));
31148
+ sections.push(chalk61.gray(" Experiment swarms, DAGs, and frontier discovery"));
28888
31149
  sections.push("");
28889
31150
  sections.push(formatCommand("labs status", "Show active experiment missions"));
28890
31151
  sections.push(formatCommand("labs launch <skill>", "Launch an experiment swarm"));
@@ -28893,16 +31154,16 @@ function formatGroupedHelp() {
28893
31154
  sections.push(formatCommand("labs best-path <id>", "Show best path through DAG"));
28894
31155
  sections.push(formatCommand("labs suggest <id>", "AI-suggested next experiments"));
28895
31156
  sections.push("");
28896
- sections.push(chalk56.cyan.bold("Research"));
28897
- sections.push(chalk56.gray(" Multi-agent research missions"));
31157
+ sections.push(chalk61.cyan.bold("Research"));
31158
+ sections.push(chalk61.gray(" Multi-agent research missions"));
28898
31159
  sections.push("");
28899
31160
  sections.push(formatCommand("research list", "Browse research missions"));
28900
31161
  sections.push(formatCommand("research propose <hub>", "Propose a new research mission"));
28901
31162
  sections.push(formatCommand("research view <id>", "View mission details"));
28902
31163
  sections.push(formatCommand("research publish <id>", "Publish findings as knowledge"));
28903
31164
  sections.push("");
28904
- sections.push(chalk56.cyan.bold("Collective Intelligence"));
28905
- sections.push(chalk56.gray(" Cross-workspace knowledge sharing and discovery"));
31165
+ sections.push(chalk61.cyan.bold("Collective Intelligence"));
31166
+ sections.push(chalk61.gray(" Cross-workspace knowledge sharing and discovery"));
28906
31167
  sections.push("");
28907
31168
  sections.push(formatCommand("collective feed", "Global collective intelligence feed"));
28908
31169
  sections.push(formatCommand("collective share <t> <c>", "Share an insight to the collective"));
@@ -28910,8 +31171,18 @@ function formatGroupedHelp() {
28910
31171
  sections.push(formatCommand("collective search <q>", "Search collective knowledge"));
28911
31172
  sections.push(formatCommand("collective sync", "Pull latest insights into workspace"));
28912
31173
  sections.push("");
28913
- sections.push(chalk56.cyan.bold("Network"));
28914
- sections.push(chalk56.gray(" Singularity layer, workspace management, and knowledge"));
31174
+ sections.push(chalk61.cyan.bold("Vault"));
31175
+ sections.push(chalk61.gray(" Manage tool credentials and API keys for workspace agents"));
31176
+ sections.push("");
31177
+ sections.push(formatCommand("vault list <hub>", "List vault entries for a workspace"));
31178
+ sections.push(formatCommand("vault store <hub>", "Store an encrypted credential"));
31179
+ sections.push(formatCommand("vault get <hub>", "Retrieve a credential (agent-scoped)"));
31180
+ sections.push(formatCommand("vault revoke <hub>", "Delete a vault entry"));
31181
+ sections.push(formatCommand("vault grant <hub>", "Update agent access for an entry"));
31182
+ sections.push(formatCommand("vault audit <hub>", "View access log for a service"));
31183
+ sections.push("");
31184
+ sections.push(chalk61.cyan.bold("Network"));
31185
+ sections.push(chalk61.gray(" Singularity layer, workspace management, and knowledge"));
28915
31186
  sections.push("");
28916
31187
  sections.push(formatCommand("network feed", "Global intelligence feed"));
28917
31188
  sections.push(formatCommand("network trending", "Trending skills across network"));
@@ -28920,8 +31191,38 @@ function formatGroupedHelp() {
28920
31191
  sections.push(formatCommand("knowledge search <q>", "Search hub knowledge"));
28921
31192
  sections.push(formatCommand("usage", "View usage breakdown"));
28922
31193
  sections.push("");
28923
- sections.push(chalk56.cyan.bold("Advanced"));
28924
- sections.push(chalk56.gray(" Seeding and administration"));
31194
+ sections.push(chalk61.cyan.bold("Reports"));
31195
+ sections.push(chalk61.gray(" Weekly network intelligence reports"));
31196
+ sections.push("");
31197
+ sections.push(formatCommand("reports latest", "View the latest weekly report"));
31198
+ sections.push(formatCommand("reports list", "List available weekly reports"));
31199
+ sections.push(formatCommand("reports view --date <d>", "View report for a specific week"));
31200
+ sections.push("");
31201
+ sections.push(chalk61.cyan.bold("Missions"));
31202
+ sections.push(chalk61.gray(" Autonomous mission runner \u2014 Ralph Loop"));
31203
+ sections.push("");
31204
+ sections.push(formatCommand("mission list", "List active missions"));
31205
+ sections.push(formatCommand("mission create <hub>", "Create a new mission"));
31206
+ sections.push(formatCommand("mission run <id>", "Run autonomous loop until budget exhausted"));
31207
+ sections.push(formatCommand("mission status <id>", "Show mission progress and DAG stats"));
31208
+ sections.push(formatCommand("mission agents <id>", "Best-fit agents for a mission"));
31209
+ sections.push(formatCommand("mission stop <id>", "Complete a mission"));
31210
+ sections.push("");
31211
+ sections.push(chalk61.cyan.bold("Meta-Skills"));
31212
+ sections.push(chalk61.gray(" System skills for interacting with the Hubify platform"));
31213
+ sections.push("");
31214
+ sections.push(formatCommand("meta list", "List available meta-skills"));
31215
+ sections.push(formatCommand("meta install [name]", "Install meta-skills into project"));
31216
+ sections.push(formatCommand("meta run <name> [args]", "Execute a meta-skill"));
31217
+ sections.push("");
31218
+ sections.push(chalk61.cyan.bold("System"));
31219
+ sections.push(chalk61.gray(" Self-update and system maintenance"));
31220
+ sections.push("");
31221
+ sections.push(formatCommand("self-update", "Check for and install CLI updates"));
31222
+ sections.push(formatCommand("self-update --check", "Only check, don't install"));
31223
+ sections.push("");
31224
+ sections.push(chalk61.cyan.bold("Advanced"));
31225
+ sections.push(chalk61.gray(" Seeding and administration"));
28925
31226
  sections.push("");
28926
31227
  sections.push(formatCommand("ingest skills-sh", "Ingest skills from skills.sh canonical registry"));
28927
31228
  sections.push(formatCommand("ingest status", "Check status of ingest operations"));
@@ -28936,48 +31237,48 @@ function formatGroupedHelp() {
28936
31237
  sections.push(formatCommand("seed-souls", "Seed 30 built-in AI souls"));
28937
31238
  sections.push(formatCommand("seed-tools", "Seed 40 core tools"));
28938
31239
  sections.push("");
28939
- sections.push(chalk56.cyan.bold("Examples"));
31240
+ sections.push(chalk61.cyan.bold("Examples"));
28940
31241
  sections.push("");
28941
- sections.push(chalk56.gray(" # Search for TypeScript skills"));
28942
- sections.push(chalk56.white(" $ hubify search typescript --category coding"));
31242
+ sections.push(chalk61.gray(" # Search for TypeScript skills"));
31243
+ sections.push(chalk61.white(" $ hubify search typescript --category coding"));
28943
31244
  sections.push("");
28944
- sections.push(chalk56.gray(" # Install a skill with minimum confidence"));
28945
- sections.push(chalk56.white(" $ hubify install react-hooks --min-confidence 0.8"));
31245
+ sections.push(chalk61.gray(" # Install a skill with minimum confidence"));
31246
+ sections.push(chalk61.white(" $ hubify install react-hooks --min-confidence 0.8"));
28946
31247
  sections.push("");
28947
- sections.push(chalk56.gray(" # Report a successful execution"));
28948
- sections.push(chalk56.white(" $ hubify report my-skill --success --duration 1500"));
31248
+ sections.push(chalk61.gray(" # Report a successful execution"));
31249
+ sections.push(chalk61.white(" $ hubify report my-skill --success --duration 1500"));
28949
31250
  sections.push("");
28950
- sections.push(chalk56.gray(" # Publish a skill with dry-run"));
28951
- sections.push(chalk56.white(" $ hubify publish ./my-skill --dry-run"));
31251
+ sections.push(chalk61.gray(" # Publish a skill with dry-run"));
31252
+ sections.push(chalk61.white(" $ hubify publish ./my-skill --dry-run"));
28952
31253
  sections.push("");
28953
- sections.push(chalk56.cyan.bold("Shell Completions"));
31254
+ sections.push(chalk61.cyan.bold("Shell Completions"));
28954
31255
  sections.push("");
28955
- sections.push(chalk56.gray(" Enable tab completion for hubify commands:"));
31256
+ sections.push(chalk61.gray(" Enable tab completion for hubify commands:"));
28956
31257
  sections.push("");
28957
- sections.push(chalk56.gray(" # Bash"));
28958
- sections.push(chalk56.white(" $ hubify completion bash >> ~/.bashrc"));
31258
+ sections.push(chalk61.gray(" # Bash"));
31259
+ sections.push(chalk61.white(" $ hubify completion bash >> ~/.bashrc"));
28959
31260
  sections.push("");
28960
- sections.push(chalk56.gray(" # Zsh"));
28961
- sections.push(chalk56.white(" $ hubify completion zsh >> ~/.zshrc"));
31261
+ sections.push(chalk61.gray(" # Zsh"));
31262
+ sections.push(chalk61.white(" $ hubify completion zsh >> ~/.zshrc"));
28962
31263
  sections.push("");
28963
- sections.push(chalk56.gray(" # Fish"));
28964
- sections.push(chalk56.white(" $ hubify completion fish > ~/.config/fish/completions/hubify.fish"));
31264
+ sections.push(chalk61.gray(" # Fish"));
31265
+ sections.push(chalk61.white(" $ hubify completion fish > ~/.config/fish/completions/hubify.fish"));
28965
31266
  sections.push("");
28966
- sections.push(chalk56.gray("Version: ") + chalk56.white(VERSION));
28967
- sections.push(chalk56.gray("Documentation: ") + chalk56.cyan("https://hubify.com/docs"));
28968
- sections.push(chalk56.gray("Report issues: ") + chalk56.cyan("https://github.com/houstongolden/hubify/issues"));
31267
+ sections.push(chalk61.gray("Version: ") + chalk61.white(VERSION));
31268
+ sections.push(chalk61.gray("Documentation: ") + chalk61.cyan("https://hubify.com/docs"));
31269
+ sections.push(chalk61.gray("Report issues: ") + chalk61.cyan("https://github.com/houstongolden/hubify/issues"));
28969
31270
  sections.push("");
28970
31271
  return sections.join("\n");
28971
31272
  }
28972
31273
  function formatCommand(name, desc) {
28973
31274
  const paddedName = name.padEnd(24);
28974
- return chalk56.white(` ${paddedName}`) + chalk56.gray(desc);
31275
+ return chalk61.white(` ${paddedName}`) + chalk61.gray(desc);
28975
31276
  }
28976
31277
  function generateBashCompletion() {
28977
31278
  return `# hubify bash completion
28978
31279
  _hubify_completions() {
28979
31280
  local cur="\${COMP_WORDS[COMP_CWORD]}"
28980
- local commands="soul tool search install execute run info list init publish report update generate evolve import integrate workflow squad stats auth learn labs research collective network memory workspace knowledge usage seed-all seed-anthropic seed-clawhub seed-skillssh seed-github seed-community seed-bootstrap seed-souls seed-tools completion"
31281
+ local commands="soul tool search install execute run info list init publish report update generate evolve import integrate workflow squad stats auth learn labs research collective network memory workspace knowledge usage vault reports mission meta hub hub-connect sync test agent collaborate scan audit detect ingest seed-all seed-anthropic seed-clawhub seed-skillssh seed-github seed-community seed-bootstrap seed-souls seed-tools completion"
28981
31282
 
28982
31283
  if [[ \${COMP_CWORD} -eq 1 ]]; then
28983
31284
  COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
@@ -29008,6 +31309,28 @@ _hubify() {
29008
31309
  'evolve:Evolve a skill'
29009
31310
  'import:Import from external source'
29010
31311
  'stats:View registry statistics'
31312
+ 'auth:Manage authentication'
31313
+ 'learn:Learning and evolution'
31314
+ 'labs:Experiment swarms'
31315
+ 'research:Research missions'
31316
+ 'collective:Collective intelligence'
31317
+ 'network:Singularity network'
31318
+ 'memory:Agent memory'
31319
+ 'workspace:Workspace management'
31320
+ 'knowledge:Hub knowledge'
31321
+ 'usage:Usage and billing'
31322
+ 'vault:Credential vault'
31323
+ 'reports:Weekly intelligence reports'
31324
+ 'mission:Autonomous missions'
31325
+ 'meta:Meta-skills for Hubify platform'
31326
+ 'hub:Hub manifests'
31327
+ 'hub-connect:Connect to hub'
31328
+ 'sync:Sync operations'
31329
+ 'agent:Agent management'
31330
+ 'collaborate:Collaboration sessions'
31331
+ 'scan:Security scanning'
31332
+ 'audit:Skills audit'
31333
+ 'ingest:Ingest from registries'
29011
31334
  'seed-all:Seed from all sources'
29012
31335
  'seed-anthropic:Seed from Anthropic'
29013
31336
  'seed-clawhub:Seed from ClawHub'
@@ -29053,6 +31376,28 @@ complete -c hubify -n "__fish_use_subcommand" -a "generate" -d "Generate a new s
29053
31376
  complete -c hubify -n "__fish_use_subcommand" -a "evolve" -d "Evolve a skill"
29054
31377
  complete -c hubify -n "__fish_use_subcommand" -a "import" -d "Import from external source"
29055
31378
  complete -c hubify -n "__fish_use_subcommand" -a "stats" -d "View registry statistics"
31379
+ complete -c hubify -n "__fish_use_subcommand" -a "auth" -d "Manage authentication"
31380
+ complete -c hubify -n "__fish_use_subcommand" -a "learn" -d "Learning and evolution"
31381
+ complete -c hubify -n "__fish_use_subcommand" -a "labs" -d "Experiment swarms"
31382
+ complete -c hubify -n "__fish_use_subcommand" -a "research" -d "Research missions"
31383
+ complete -c hubify -n "__fish_use_subcommand" -a "collective" -d "Collective intelligence"
31384
+ complete -c hubify -n "__fish_use_subcommand" -a "network" -d "Singularity network"
31385
+ complete -c hubify -n "__fish_use_subcommand" -a "memory" -d "Agent memory"
31386
+ complete -c hubify -n "__fish_use_subcommand" -a "workspace" -d "Workspace management"
31387
+ complete -c hubify -n "__fish_use_subcommand" -a "knowledge" -d "Hub knowledge"
31388
+ complete -c hubify -n "__fish_use_subcommand" -a "usage" -d "Usage and billing"
31389
+ complete -c hubify -n "__fish_use_subcommand" -a "vault" -d "Credential vault"
31390
+ complete -c hubify -n "__fish_use_subcommand" -a "reports" -d "Weekly intelligence reports"
31391
+ complete -c hubify -n "__fish_use_subcommand" -a "mission" -d "Autonomous missions"
31392
+ complete -c hubify -n "__fish_use_subcommand" -a "meta" -d "Meta-skills"
31393
+ complete -c hubify -n "__fish_use_subcommand" -a "hub" -d "Hub manifests"
31394
+ complete -c hubify -n "__fish_use_subcommand" -a "hub-connect" -d "Connect to hub"
31395
+ complete -c hubify -n "__fish_use_subcommand" -a "sync" -d "Sync operations"
31396
+ complete -c hubify -n "__fish_use_subcommand" -a "agent" -d "Agent management"
31397
+ complete -c hubify -n "__fish_use_subcommand" -a "collaborate" -d "Collaboration sessions"
31398
+ complete -c hubify -n "__fish_use_subcommand" -a "scan" -d "Security scanning"
31399
+ complete -c hubify -n "__fish_use_subcommand" -a "audit" -d "Skills audit"
31400
+ complete -c hubify -n "__fish_use_subcommand" -a "ingest" -d "Ingest from registries"
29056
31401
  complete -c hubify -n "__fish_use_subcommand" -a "seed-all" -d "Seed from all sources"
29057
31402
  complete -c hubify -n "__fish_use_subcommand" -a "seed-anthropic" -d "Seed from Anthropic"
29058
31403
  complete -c hubify -n "__fish_use_subcommand" -a "seed-clawhub" -d "Seed from ClawHub"
@@ -29064,7 +31409,7 @@ complete -c hubify -n "__fish_use_subcommand" -a "seed-tools" -d "Seed core tool
29064
31409
  complete -c hubify -n "__fish_use_subcommand" -a "completion" -d "Generate shell completions"
29065
31410
  `;
29066
31411
  }
29067
- var program = new Command53();
31412
+ var program = new Command58();
29068
31413
  program.name("hubify").description("The living intelligence layer for Agent Skills").version(VERSION, "-v, --version", "Display version number").configureHelp({
29069
31414
  formatHelp: () => formatGroupedHelp()
29070
31415
  });
@@ -29110,14 +31455,19 @@ program.addCommand(researchCommand);
29110
31455
  program.addCommand(authCommand);
29111
31456
  program.addCommand(scanCommand);
29112
31457
  program.addCommand(auditCommand);
29113
- program.addCommand(labsCommand);
31458
+ program.addCommand(labsCommand2);
29114
31459
  program.addCommand(networkCommand);
29115
31460
  program.addCommand(memoryCommand);
29116
31461
  program.addCommand(workspaceCommand);
29117
31462
  program.addCommand(knowledgeCommand);
29118
31463
  program.addCommand(usageCommand);
29119
31464
  program.addCommand(collectiveCommand);
29120
- var completionCommand = new Command53("completion").description("Generate shell completion scripts").argument("<shell>", "Shell type: bash, zsh, or fish").action((shell) => {
31465
+ program.addCommand(vaultCommand);
31466
+ program.addCommand(reportsCommand);
31467
+ program.addCommand(missionCommand);
31468
+ program.addCommand(metaCommand);
31469
+ program.addCommand(selfUpdateCommand);
31470
+ var completionCommand = new Command58("completion").description("Generate shell completion scripts").argument("<shell>", "Shell type: bash, zsh, or fish").action((shell) => {
29121
31471
  switch (shell.toLowerCase()) {
29122
31472
  case "bash":
29123
31473
  console.log(generateBashCompletion());
@@ -29129,16 +31479,16 @@ var completionCommand = new Command53("completion").description("Generate shell
29129
31479
  console.log(generateFishCompletion());
29130
31480
  break;
29131
31481
  default:
29132
- console.error(chalk56.red(`Unknown shell: ${shell}`));
29133
- console.error(chalk56.gray("Supported shells: bash, zsh, fish"));
31482
+ console.error(chalk61.red(`Unknown shell: ${shell}`));
31483
+ console.error(chalk61.gray("Supported shells: bash, zsh, fish"));
29134
31484
  process.exit(1);
29135
31485
  }
29136
31486
  });
29137
31487
  program.addCommand(completionCommand);
29138
- var doctorCommand = new Command53("doctor").description("Diagnose Hubify configuration and connectivity").action(async () => {
31488
+ var doctorCommand = new Command58("doctor").description("Diagnose Hubify configuration and connectivity").action(async () => {
29139
31489
  console.log(BANNER);
29140
- console.log(chalk56.cyan.bold(" Hubify Doctor"));
29141
- console.log(chalk56.gray(" Checking your setup...\n"));
31490
+ console.log(chalk61.cyan.bold(" Hubify Doctor"));
31491
+ console.log(chalk61.gray(" Checking your setup...\n"));
29142
31492
  const checks = [];
29143
31493
  const nodeVersion = process.version;
29144
31494
  const majorVersion = parseInt(nodeVersion.slice(1).split(".")[0]);
@@ -29147,17 +31497,17 @@ var doctorCommand = new Command53("doctor").description("Diagnose Hubify configu
29147
31497
  } else {
29148
31498
  checks.push({ name: "Node.js version", status: "fail", message: `${nodeVersion} (>= 20 required)` });
29149
31499
  }
29150
- const os11 = await import("os");
29151
- const fs27 = await import("fs");
29152
- const path26 = await import("path");
29153
- const globalConfigPath = path26.join(os11.homedir(), ".hubify", "config.yaml");
29154
- if (fs27.existsSync(globalConfigPath)) {
31500
+ const os12 = await import("os");
31501
+ const fs29 = await import("fs");
31502
+ const path27 = await import("path");
31503
+ const globalConfigPath = path27.join(os12.homedir(), ".hubify", "config.yaml");
31504
+ if (fs29.existsSync(globalConfigPath)) {
29155
31505
  checks.push({ name: "Global config", status: "pass", message: globalConfigPath });
29156
31506
  } else {
29157
31507
  checks.push({ name: "Global config", status: "warn", message: "Not found (run: hubify init --global)" });
29158
31508
  }
29159
- const localConfigPath = path26.join(process.cwd(), ".hubify", "config.yaml");
29160
- if (fs27.existsSync(localConfigPath)) {
31509
+ const localConfigPath = path27.join(process.cwd(), ".hubify", "config.yaml");
31510
+ if (fs29.existsSync(localConfigPath)) {
29161
31511
  checks.push({ name: "Project config", status: "pass", message: localConfigPath });
29162
31512
  } else {
29163
31513
  checks.push({ name: "Project config", status: "warn", message: "Not found (run: hubify init)" });
@@ -29176,26 +31526,26 @@ var doctorCommand = new Command53("doctor").description("Diagnose Hubify configu
29176
31526
  let color;
29177
31527
  switch (check.status) {
29178
31528
  case "pass":
29179
- icon = chalk56.green(" [PASS]");
29180
- color = chalk56.white;
31529
+ icon = chalk61.green(" [PASS]");
31530
+ color = chalk61.white;
29181
31531
  break;
29182
31532
  case "fail":
29183
- icon = chalk56.red(" [FAIL]");
29184
- color = chalk56.red;
31533
+ icon = chalk61.red(" [FAIL]");
31534
+ color = chalk61.red;
29185
31535
  hasFailure = true;
29186
31536
  break;
29187
31537
  case "warn":
29188
- icon = chalk56.yellow(" [WARN]");
29189
- color = chalk56.yellow;
31538
+ icon = chalk61.yellow(" [WARN]");
31539
+ color = chalk61.yellow;
29190
31540
  break;
29191
31541
  }
29192
- console.log(`${icon} ${chalk56.white(check.name.padEnd(20))} ${color(check.message)}`);
31542
+ console.log(`${icon} ${chalk61.white(check.name.padEnd(20))} ${color(check.message)}`);
29193
31543
  }
29194
31544
  console.log();
29195
31545
  if (hasFailure) {
29196
- console.log(chalk56.red(" Some checks failed. Please resolve the issues above."));
31546
+ console.log(chalk61.red(" Some checks failed. Please resolve the issues above."));
29197
31547
  } else {
29198
- console.log(chalk56.green(" All checks passed! Hubify is ready to use."));
31548
+ console.log(chalk61.green(" All checks passed! Hubify is ready to use."));
29199
31549
  }
29200
31550
  console.log();
29201
31551
  });
@@ -29207,7 +31557,7 @@ program.exitOverride((err) => {
29207
31557
  if (err.code === "commander.unknownCommand") {
29208
31558
  const unknownCommand = process.argv[2];
29209
31559
  console.log();
29210
- console.log(chalk56.red(` Error: Unknown command '${unknownCommand}'`));
31560
+ console.log(chalk61.red(` Error: Unknown command '${unknownCommand}'`));
29211
31561
  console.log();
29212
31562
  const commands = [
29213
31563
  "search",
@@ -29237,26 +31587,26 @@ program.exitOverride((err) => {
29237
31587
  (cmd) => cmd.includes(unknownCommand) || unknownCommand.includes(cmd.slice(0, 3)) || levenshteinDistance(cmd, unknownCommand) <= 2
29238
31588
  );
29239
31589
  if (similar.length > 0) {
29240
- console.log(chalk56.gray(" Did you mean one of these?"));
31590
+ console.log(chalk61.gray(" Did you mean one of these?"));
29241
31591
  for (const cmd of similar.slice(0, 3)) {
29242
- console.log(chalk56.cyan(` hubify ${cmd}`));
31592
+ console.log(chalk61.cyan(` hubify ${cmd}`));
29243
31593
  }
29244
31594
  console.log();
29245
31595
  }
29246
- console.log(chalk56.gray(" Run ") + chalk56.cyan("hubify --help") + chalk56.gray(" to see all available commands."));
31596
+ console.log(chalk61.gray(" Run ") + chalk61.cyan("hubify --help") + chalk61.gray(" to see all available commands."));
29247
31597
  console.log();
29248
31598
  process.exit(1);
29249
31599
  }
29250
31600
  if (err.code === "commander.missingArgument") {
29251
31601
  console.log();
29252
- console.log(chalk56.red(` Error: ${err.message}`));
31602
+ console.log(chalk61.red(` Error: ${err.message}`));
29253
31603
  console.log();
29254
- console.log(chalk56.gray(" Run ") + chalk56.cyan(`hubify ${process.argv[2]} --help`) + chalk56.gray(" for usage details."));
31604
+ console.log(chalk61.gray(" Run ") + chalk61.cyan(`hubify ${process.argv[2]} --help`) + chalk61.gray(" for usage details."));
29255
31605
  console.log();
29256
31606
  process.exit(1);
29257
31607
  }
29258
31608
  console.error();
29259
- console.error(chalk56.red(" Error:"), err.message);
31609
+ console.error(chalk61.red(" Error:"), err.message);
29260
31610
  console.error();
29261
31611
  process.exit(1);
29262
31612
  });
@@ -29285,19 +31635,19 @@ function levenshteinDistance(a, b) {
29285
31635
  }
29286
31636
  process.on("unhandledRejection", (reason) => {
29287
31637
  console.error();
29288
- console.error(chalk56.red(" Unexpected error:"));
31638
+ console.error(chalk61.red(" Unexpected error:"));
29289
31639
  if (reason instanceof Error) {
29290
- console.error(chalk56.red(` ${reason.message}`));
31640
+ console.error(chalk61.red(` ${reason.message}`));
29291
31641
  if (reason.message.includes("ECONNREFUSED") || reason.message.includes("fetch")) {
29292
31642
  console.error();
29293
- console.error(chalk56.yellow(" Tip: Check your internet connection or run 'hubify doctor' to diagnose."));
31643
+ console.error(chalk61.yellow(" Tip: Check your internet connection or run 'hubify doctor' to diagnose."));
29294
31644
  }
29295
31645
  if (reason.message.includes("not found")) {
29296
31646
  console.error();
29297
- console.error(chalk56.yellow(" Tip: Try 'hubify search <query>' to find available skills."));
31647
+ console.error(chalk61.yellow(" Tip: Try 'hubify search <query>' to find available skills."));
29298
31648
  }
29299
31649
  } else {
29300
- console.error(chalk56.red(` ${String(reason)}`));
31650
+ console.error(chalk61.red(` ${String(reason)}`));
29301
31651
  }
29302
31652
  console.error();
29303
31653
  process.exit(1);