@floomhq/floom 3.0.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3253,7 +3253,7 @@ async function getMachineIdentity() {
3253
3253
  }
3254
3254
 
3255
3255
  // src/version.ts
3256
- var VERSION = "3.0.1";
3256
+ var VERSION = "3.0.2";
3257
3257
 
3258
3258
  // src/api-client.ts
3259
3259
  var DEFAULT_TIMEOUT_MS = 2e4;
@@ -5877,9 +5877,9 @@ function buildApplyJson(workspaceName, applied, opts) {
5877
5877
  next: ["floom status"]
5878
5878
  };
5879
5879
  }
5880
- async function planForAgent(agent, scope, skillsDir) {
5880
+ async function planForAgent(agent, scope, skillsDir, statusFn = statusLibrary) {
5881
5881
  try {
5882
- const status = await statusLibrary(agent, { installDir: skillsDir });
5882
+ const status = await statusFn(agent, { installDir: skillsDir });
5883
5883
  return {
5884
5884
  agent,
5885
5885
  scope,
@@ -5892,7 +5892,12 @@ async function planForAgent(agent, scope, skillsDir) {
5892
5892
  return { agent, scope, skillsDir, pull: [], push: [], conflicts: [] };
5893
5893
  }
5894
5894
  }
5895
- async function syncCommand(rawOpts = {}) {
5895
+ async function syncCommand(rawOpts = {}, deps = {}) {
5896
+ const detectAgentsFn = deps.detectAgents ?? detectAgents;
5897
+ const runSyncFn = deps.runSyncForTarget ?? runSyncForTarget;
5898
+ const statusFn = deps.statusLibrary ?? statusLibrary;
5899
+ const fetchMeFn = deps.fetchMe ?? fetchMe;
5900
+ const readAuthFn = deps.readAuth ?? readAuth;
5896
5901
  const cleanup = installCancellationHandler();
5897
5902
  try {
5898
5903
  let flags;
@@ -5908,7 +5913,7 @@ async function syncCommand(rawOpts = {}) {
5908
5913
  }
5909
5914
  const json = flags.json;
5910
5915
  const planMode = isPlanMode(flags);
5911
- if (!await readAuth()) {
5916
+ if (!await readAuthFn()) {
5912
5917
  if (json) {
5913
5918
  emitJson({ workspace: { name: "Library", signedIn: false }, mode: "plan", applied: false, wouldMutate: false, hasSkipped: false, agents: [], next: ["floom login"] });
5914
5919
  } else {
@@ -5918,30 +5923,30 @@ async function syncCommand(rawOpts = {}) {
5918
5923
  process.exitCode = 2;
5919
5924
  return;
5920
5925
  }
5921
- const detected = await detectAgents();
5926
+ const detected = await detectAgentsFn();
5922
5927
  if (detected.length === 0) {
5923
5928
  if (json) {
5924
- emitJson({ workspace: { name: "Library", signedIn: true }, mode: "plan", applied: false, wouldMutate: false, hasSkipped: false, agents: [], next: ["floom sync --agent claude"] });
5929
+ emitJson({ workspace: { name: "Library", signedIn: true }, mode: "plan", applied: false, wouldMutate: false, hasSkipped: false, agents: [], error: "no agents detected \u2014 install Claude, Codex, Cursor, Gemini, or OpenCode", next: ["floom sync --agent claude"] });
5925
5930
  } else {
5926
- log.info("No AI agents found on this machine.");
5927
- log.info("Floom looks for Claude, Codex, Cursor, Gemini, or OpenCode.");
5931
+ log.err("No agents detected \u2014 install Claude, Codex, Cursor, Gemini, or OpenCode, then re-run.");
5932
+ log.info("Floom syncs into one of: Claude, Codex, Cursor, Gemini, OpenCode.");
5933
+ log.info("More: https://floom.dev/docs#agents");
5928
5934
  }
5929
5935
  process.exitCode = 1;
5930
5936
  return;
5931
5937
  }
5938
+ const defaultedToAll = flags.agents.length === 0 && !flags.allAgents;
5932
5939
  const selectedAgents = flags.agents.length > 0 ? flags.agents : detected;
5933
- if (!planMode && flags.agents.length === 0 && !flags.allAgents && !isInteractive()) {
5940
+ if (!planMode && !flags.yes && !isInteractive()) {
5934
5941
  if (json) {
5935
- emitJson({ workspace: { name: "Library", signedIn: true }, error: "floom sync needs to know which agents to update", next: ["floom sync --all-agents --yes"] });
5942
+ emitJson({ workspace: { name: "Library", signedIn: true }, error: "floom sync needs --yes to apply changes in a non-interactive shell", next: ["floom sync --yes"] });
5936
5943
  } else {
5937
- log.err("floom sync needs to know which agents to update.");
5938
- log.blank();
5939
- log.info("Pass --agent <name>, repeat --agent, or use --all-agents.");
5944
+ log.err("floom sync needs --yes to apply changes in a non-interactive shell.");
5940
5945
  log.blank();
5941
5946
  log.info("Examples:");
5947
+ log.command("floom sync --yes # sync every detected agent");
5942
5948
  log.command("floom sync --agent claude --yes");
5943
5949
  log.command("floom sync --agent claude,codex --yes");
5944
- log.command("floom sync --all-agents --yes");
5945
5950
  }
5946
5951
  process.exitCode = 2;
5947
5952
  return;
@@ -5951,7 +5956,7 @@ async function syncCommand(rawOpts = {}) {
5951
5956
  process.exitCode = 2;
5952
5957
  return;
5953
5958
  }
5954
- const me = await fetchMe().catch(() => null);
5959
+ const me = await fetchMeFn().catch(() => null);
5955
5960
  const workspaceName = me?.workspace?.name ?? "your Workspace";
5956
5961
  const hasProjectScope = await projectSkillsDirExists(process.cwd());
5957
5962
  const scopeChoice = flags.allScopes ? ["global", "project"] : flags.scope === "project" ? ["project"] : planMode && flags.scope === null && hasProjectScope ? ["global", "project"] : ["global"];
@@ -5960,7 +5965,7 @@ async function syncCommand(rawOpts = {}) {
5960
5965
  for (const scope of scopeChoice) {
5961
5966
  const dir = scope === "project" ? resolve6(projectSkillsDir(agent)) : resolve6(globalSkillsDir(agent));
5962
5967
  if (scope === "project" && !await projectSkillsDirExists(process.cwd())) continue;
5963
- plans.push(await planForAgent(agent, scope, dir));
5968
+ plans.push(await planForAgent(agent, scope, dir, statusFn));
5964
5969
  }
5965
5970
  }
5966
5971
  const actionable = plans.filter((p) => p.pull.length > 0 || p.push.length > 0);
@@ -6013,12 +6018,24 @@ async function syncCommand(rawOpts = {}) {
6013
6018
  return;
6014
6019
  }
6015
6020
  if (!wouldMutate && !hasSkipped) {
6021
+ if (json) {
6022
+ const noopApplied = plans.map((p) => ({ plan: p, ok: true, message: "up to date" }));
6023
+ emitJson(buildApplyJson(workspaceName, noopApplied, { failed: false, hasSkipped: false }));
6024
+ return;
6025
+ }
6026
+ if (defaultedToAll && detected.length > 1) {
6027
+ log.info(`Syncing every detected agent (${detected.map((a) => AGENT_LABELS[a]).join(", ")}).`);
6028
+ }
6016
6029
  log.info("Everything is in sync.");
6017
6030
  log.blank();
6018
6031
  for (const p of plans) log.row([AGENT_LABELS[p.agent], "up to date"], [10]);
6019
6032
  printNext([{ command: "floom status" }]);
6020
6033
  return;
6021
6034
  }
6035
+ if (defaultedToAll && detected.length > 1) {
6036
+ log.info(`Syncing every detected agent (${detected.map((a) => AGENT_LABELS[a]).join(", ")}).`);
6037
+ log.blank();
6038
+ }
6022
6039
  log.heading("Sync plan for this machine");
6023
6040
  log.blank();
6024
6041
  for (const p of plans) {
@@ -6056,7 +6073,7 @@ async function syncCommand(rawOpts = {}) {
6056
6073
  const applied = [];
6057
6074
  for (const p of toSync) {
6058
6075
  try {
6059
- const result = await runSyncForTarget({ target: p.agent, yes: true, installDir: p.skillsDir });
6076
+ const result = await runSyncFn({ target: p.agent, yes: true, installDir: p.skillsDir });
6060
6077
  const entry = appliedFromResult(p, result);
6061
6078
  if (!entry.ok) failed = true;
6062
6079
  applied.push(entry);
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = "3.0.1";
1
+ export const VERSION = "3.0.2";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floomhq/floom",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "description": "Floom CLI \u2014 one shared skill library, pulled into the AI agent you choose (Claude, Codex, Cursor, Gemini, OpenCode).",
5
5
  "license": "MIT",
6
6
  "homepage": "https://floom.dev",