@floomhq/skills 0.2.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 (82) hide show
  1. package/dist/api-client.d.ts +9 -0
  2. package/dist/api-client.js +61 -0
  3. package/dist/api-client.js.map +1 -0
  4. package/dist/commands/info.d.ts +1 -0
  5. package/dist/commands/info.js +24 -0
  6. package/dist/commands/info.js.map +1 -0
  7. package/dist/commands/init.d.ts +1 -0
  8. package/dist/commands/init.js +108 -0
  9. package/dist/commands/init.js.map +1 -0
  10. package/dist/commands/install.d.ts +8 -0
  11. package/dist/commands/install.js +136 -0
  12. package/dist/commands/install.js.map +1 -0
  13. package/dist/commands/installed.d.ts +4 -0
  14. package/dist/commands/installed.js +22 -0
  15. package/dist/commands/installed.js.map +1 -0
  16. package/dist/commands/library.d.ts +4 -0
  17. package/dist/commands/library.js +29 -0
  18. package/dist/commands/library.js.map +1 -0
  19. package/dist/commands/list.d.ts +7 -0
  20. package/dist/commands/list.js +32 -0
  21. package/dist/commands/list.js.map +1 -0
  22. package/dist/commands/login.d.ts +1 -0
  23. package/dist/commands/login.js +57 -0
  24. package/dist/commands/login.js.map +1 -0
  25. package/dist/commands/logout.d.ts +1 -0
  26. package/dist/commands/logout.js +19 -0
  27. package/dist/commands/logout.js.map +1 -0
  28. package/dist/commands/outdated.d.ts +1 -0
  29. package/dist/commands/outdated.js +50 -0
  30. package/dist/commands/outdated.js.map +1 -0
  31. package/dist/commands/publish.d.ts +4 -0
  32. package/dist/commands/publish.js +84 -0
  33. package/dist/commands/publish.js.map +1 -0
  34. package/dist/commands/share.d.ts +5 -0
  35. package/dist/commands/share.js +34 -0
  36. package/dist/commands/share.js.map +1 -0
  37. package/dist/commands/update.d.ts +4 -0
  38. package/dist/commands/update.js +92 -0
  39. package/dist/commands/update.js.map +1 -0
  40. package/dist/commands/validate.d.ts +32 -0
  41. package/dist/commands/validate.js +108 -0
  42. package/dist/commands/validate.js.map +1 -0
  43. package/dist/commands/whoami.d.ts +1 -0
  44. package/dist/commands/whoami.js +14 -0
  45. package/dist/commands/whoami.js.map +1 -0
  46. package/dist/config.d.ts +11 -0
  47. package/dist/config.js +39 -0
  48. package/dist/config.js.map +1 -0
  49. package/dist/index.d.ts +2 -0
  50. package/dist/index.js +99 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/lib/floom-lock.d.ts +22 -0
  53. package/dist/lib/floom-lock.js +66 -0
  54. package/dist/lib/floom-lock.js.map +1 -0
  55. package/dist/lib/output.d.ts +11 -0
  56. package/dist/lib/output.js +17 -0
  57. package/dist/lib/output.js.map +1 -0
  58. package/dist/version.d.ts +1 -0
  59. package/dist/version.js +2 -0
  60. package/dist/version.js.map +1 -0
  61. package/package.json +39 -0
  62. package/src/api-client.ts +80 -0
  63. package/src/commands/info.ts +36 -0
  64. package/src/commands/init.ts +109 -0
  65. package/src/commands/install.ts +176 -0
  66. package/src/commands/installed.ts +29 -0
  67. package/src/commands/library.ts +41 -0
  68. package/src/commands/list.ts +59 -0
  69. package/src/commands/login.ts +77 -0
  70. package/src/commands/logout.ts +18 -0
  71. package/src/commands/outdated.ts +57 -0
  72. package/src/commands/publish.ts +111 -0
  73. package/src/commands/share.ts +41 -0
  74. package/src/commands/update.ts +116 -0
  75. package/src/commands/validate.ts +132 -0
  76. package/src/commands/whoami.ts +14 -0
  77. package/src/config.ts +44 -0
  78. package/src/index.ts +109 -0
  79. package/src/lib/floom-lock.ts +81 -0
  80. package/src/lib/output.ts +17 -0
  81. package/src/version.ts +1 -0
  82. package/tsconfig.json +9 -0
@@ -0,0 +1,50 @@
1
+ import { api } from "../api-client.js";
2
+ import { readLock } from "../lib/floom-lock.js";
3
+ import { log } from "../lib/output.js";
4
+ function cmpSemver(a, b) {
5
+ const pa = a.split(".").map((p) => parseInt(p, 10));
6
+ const pb = b.split(".").map((p) => parseInt(p, 10));
7
+ for (let i = 0; i < 3; i++) {
8
+ const d = (pa[i] ?? 0) - (pb[i] ?? 0);
9
+ if (d !== 0)
10
+ return d;
11
+ }
12
+ return 0;
13
+ }
14
+ export async function outdatedCommand() {
15
+ const lock = await readLock(process.cwd());
16
+ const entries = Object.entries(lock.skills);
17
+ if (entries.length === 0) {
18
+ log.info("No skills installed.");
19
+ return;
20
+ }
21
+ log.heading("Checking for updates...");
22
+ const outdated = [];
23
+ for (const [ref, e] of entries) {
24
+ const [, owner, slug] = /^@([^/]+)\/([^@]+)/.exec(ref) ?? [];
25
+ if (!owner || !slug)
26
+ continue;
27
+ try {
28
+ const info = await api(`/skills/${owner}/${slug}`);
29
+ if (cmpSemver(info.latest_version, e.version) > 0) {
30
+ outdated.push({ ref, current: e.version, latest: info.latest_version });
31
+ }
32
+ }
33
+ catch (err) {
34
+ log.warn(`Could not check ${ref}: ${err.message}`);
35
+ }
36
+ }
37
+ log.blank();
38
+ if (outdated.length === 0) {
39
+ log.ok("All installed skills are up to date.");
40
+ return;
41
+ }
42
+ log.heading("Outdated skills");
43
+ for (const o of outdated) {
44
+ console.log(` ${o.ref.padEnd(40)} ${o.current.padEnd(10)} -> ${o.latest.padEnd(10)} floom update ${o.ref}`);
45
+ }
46
+ log.blank();
47
+ log.info(`${outdated.length} skill${outdated.length === 1 ? "" : "s"} can be updated.`);
48
+ process.exit(1); // useful in CI
49
+ }
50
+ //# sourceMappingURL=outdated.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outdated.js","sourceRoot":"","sources":["../../src/commands/outdated.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export interface PublishOptions {
2
+ library?: string;
3
+ }
4
+ export declare function publishCommand(opts?: PublishOptions): Promise<void>;
@@ -0,0 +1,84 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { readManifest, parseSkillFrontmatter, collectBundle, packBundle, FloomError, } from "@floom/shared";
4
+ import { api, rawPut } from "../api-client.js";
5
+ import { readAuth } from "../config.js";
6
+ import { log } from "../lib/output.js";
7
+ import { validateSkill } from "./validate.js";
8
+ export async function publishCommand(opts = {}) {
9
+ const auth = await readAuth();
10
+ if (!auth) {
11
+ log.err("Not logged in. Run: floom login");
12
+ process.exit(1);
13
+ }
14
+ const dir = process.cwd();
15
+ log.heading("Validating skill...");
16
+ const report = await validateSkill(dir);
17
+ if (!report.ok) {
18
+ log.err("Validation failed. Run `floom validate` for details.");
19
+ process.exit(1);
20
+ }
21
+ log.ok("Validation passed.");
22
+ const m = await readManifest(dir);
23
+ if (!m.ok) {
24
+ log.err(m.error);
25
+ process.exit(1);
26
+ }
27
+ const manifest = m.manifest;
28
+ const skillMd = await readFile(join(dir, "SKILL.md"), "utf8");
29
+ const { meta } = parseSkillFrontmatter(skillMd);
30
+ const refRoot = opts.library ?? auth.handle;
31
+ log.heading(`Publishing ${refRoot}/${manifest.name}@${manifest.version}`);
32
+ log.step("Packing bundle...");
33
+ const bundle = await collectBundle(dir);
34
+ const packed = await packBundle(bundle);
35
+ log.kv("files", String(bundle.files.length));
36
+ log.kv("size", `${packed.bytes.length} bytes (${(packed.bytes.length / 1024).toFixed(1)} KB)`);
37
+ log.kv("sha256", packed.sha256);
38
+ log.step("Requesting upload URL...");
39
+ let initResp;
40
+ try {
41
+ initResp = await api(`/skills/${refRoot}/${manifest.name}/versions`, {
42
+ method: "POST",
43
+ authRequired: true,
44
+ body: {
45
+ manifest,
46
+ skill_md: skillMd,
47
+ bundle: {
48
+ sha256: packed.sha256,
49
+ size_bytes: packed.bytes.length,
50
+ },
51
+ files: bundle.files.map((f) => ({
52
+ path: f.relPath,
53
+ sha256: f.sha256,
54
+ size_bytes: f.size,
55
+ })),
56
+ has_scripts: bundle.hasScripts,
57
+ },
58
+ });
59
+ }
60
+ catch (e) {
61
+ if (e instanceof FloomError && e.code === "VERSION_ALREADY_EXISTS") {
62
+ log.err(`Version ${manifest.version} already exists for @${auth.handle}/${manifest.name}.`);
63
+ log.info("Bump the version in skill.json (e.g. 0.1.1) and try again.");
64
+ process.exit(1);
65
+ }
66
+ throw e;
67
+ }
68
+ log.step("Uploading bundle...");
69
+ await rawPut(initResp.upload.url, packed.bytes, "application/gzip");
70
+ log.step("Finalizing...");
71
+ const complete = await api(`/versions/${initResp.version_id}/complete`, {
72
+ method: "POST",
73
+ authRequired: true,
74
+ body: { bundle_sha256: packed.sha256 },
75
+ });
76
+ log.blank();
77
+ log.ok(`Published ${complete.ref}`);
78
+ log.blank();
79
+ log.info("View:");
80
+ log.kv("", `${auth.apiUrl.replace("/api/v1", "")}/@${auth.handle}/${manifest.name}`);
81
+ log.info("Install:");
82
+ log.kv("", complete.install_command);
83
+ }
84
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface ShareOptions {
2
+ role?: "viewer" | "editor";
3
+ }
4
+ export declare function shareCommand(refStr: string, email: string, opts?: ShareOptions): Promise<void>;
5
+ export declare function unshareCommand(refStr: string, email: string): Promise<void>;
@@ -0,0 +1,34 @@
1
+ import { parseSkillRef } from "@floom/shared";
2
+ import { api } from "../api-client.js";
3
+ import { log } from "../lib/output.js";
4
+ export async function shareCommand(refStr, email, opts = {}) {
5
+ const ref = parseSkillRef(refStr);
6
+ if (!ref) {
7
+ log.err(`Invalid skill ref: ${refStr}`);
8
+ process.exit(1);
9
+ }
10
+ const role = opts.role ?? "viewer";
11
+ const r = await api(`/skills/${ref.owner}/${ref.slug}/grants`, {
12
+ method: "POST",
13
+ authRequired: true,
14
+ body: { email, role },
15
+ });
16
+ log.ok(`Shared ${refStr} with ${r.grant.email} as ${r.grant.role}.`);
17
+ log.info("No email is sent in V0. They will see the skill under 'Shared with Me' on next login.");
18
+ }
19
+ export async function unshareCommand(refStr, email) {
20
+ const ref = parseSkillRef(refStr);
21
+ if (!ref) {
22
+ log.err(`Invalid skill ref: ${refStr}`);
23
+ process.exit(1);
24
+ }
25
+ const list = await api(`/skills/${ref.owner}/${ref.slug}/grants`, { authRequired: true });
26
+ const grant = list.grants.find((g) => (g.email ?? "").toLowerCase() === email.toLowerCase());
27
+ if (!grant) {
28
+ log.err(`No active grant for ${email} on ${refStr}.`);
29
+ process.exit(1);
30
+ }
31
+ await api(`/skills/${ref.owner}/${ref.slug}/grants/${grant.id}`, { method: "DELETE", authRequired: true });
32
+ log.ok(`Removed ${email}'s access to ${refStr}.`);
33
+ }
34
+ //# sourceMappingURL=share.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"share.js","sourceRoot":"","sources":["../../src/commands/share.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAUvC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAc,EAAE,KAAa,EAAE,OAAqB,EAAE;IACvF,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,GAAG,EAAE,CAAC;QAAC,GAAG,CAAC,GAAG,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAC;QAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAAC,CAAC;IACvE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC;IACnC,MAAM,CAAC,GAAG,MAAM,GAAG,CAAgB,WAAW,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,SAAS,EAAE;QAC5E,MAAM,EAAE,MAAM;QACd,YAAY,EAAE,IAAI;QAClB,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;KACtB,CAAC,CAAC;IACH,GAAG,CAAC,EAAE,CAAC,UAAU,MAAM,SAAS,CAAC,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;IACrE,GAAG,CAAC,IAAI,CAAC,uFAAuF,CAAC,CAAC;AACpG,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAc,EAAE,KAAa;IAChE,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,GAAG,EAAE,CAAC;QAAC,GAAG,CAAC,GAAG,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAC;QAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAAC,CAAC;IACvE,MAAM,IAAI,GAAG,MAAM,GAAG,CAAoB,WAAW,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,SAAS,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7G,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7F,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,GAAG,CAAC,GAAG,CAAC,uBAAuB,KAAK,OAAO,MAAM,GAAG,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,GAAG,CAAC,WAAW,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,WAAW,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3G,GAAG,CAAC,EAAE,CAAC,WAAW,KAAK,gBAAgB,MAAM,GAAG,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,4 @@
1
+ export interface UpdateOptions {
2
+ force?: boolean;
3
+ }
4
+ export declare function updateCommand(refStr?: string, opts?: UpdateOptions): Promise<void>;
@@ -0,0 +1,92 @@
1
+ import { rm, rename, mkdir } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { join, resolve } from "node:path";
4
+ import { extractBundle, verifyBundleHash } from "@floom/shared";
5
+ import { api, rawGet } from "../api-client.js";
6
+ import { readLock, writeLock, setLockEntry, hashInstalledFolder } from "../lib/floom-lock.js";
7
+ import { log } from "../lib/output.js";
8
+ function cmpSemver(a, b) {
9
+ const pa = a.split(".").map((p) => parseInt(p, 10));
10
+ const pb = b.split(".").map((p) => parseInt(p, 10));
11
+ for (let i = 0; i < 3; i++) {
12
+ const d = (pa[i] ?? 0) - (pb[i] ?? 0);
13
+ if (d !== 0)
14
+ return d;
15
+ }
16
+ return 0;
17
+ }
18
+ export async function updateCommand(refStr, opts = {}) {
19
+ const projectDir = process.cwd();
20
+ const lock = await readLock(projectDir);
21
+ const all = Object.entries(lock.skills);
22
+ if (all.length === 0) {
23
+ log.info("No installed skills.");
24
+ return;
25
+ }
26
+ const targets = refStr ? all.filter(([r]) => r === refStr) : all;
27
+ if (refStr && targets.length === 0) {
28
+ log.err(`Not installed: ${refStr}`);
29
+ process.exit(1);
30
+ }
31
+ let updated = 0, skipped = 0;
32
+ for (const [ref, entry] of targets) {
33
+ const [, owner, slug] = /^@([^/]+)\/([^@]+)/.exec(ref) ?? [];
34
+ if (!owner || !slug)
35
+ continue;
36
+ let info;
37
+ try {
38
+ info = await api(`/skills/${owner}/${slug}`);
39
+ }
40
+ catch (e) {
41
+ log.warn(`Skip ${ref}: ${e.message}`);
42
+ skipped++;
43
+ continue;
44
+ }
45
+ if (cmpSemver(info.latest_version, entry.version) <= 0) {
46
+ log.step(`${ref} is already at latest (${entry.version}).`);
47
+ continue;
48
+ }
49
+ const installDir = resolve(projectDir, entry.path);
50
+ // Detect local edits via floom-lock recorded bundle_sha256 — simplistic: we
51
+ // re-compute on-disk content and compare collective hash to recorded bundle.
52
+ // V0 hardening: full per-file lock would be richer; we use a simple gate.
53
+ if (!opts.force) {
54
+ const current = await hashInstalledFolder(installDir);
55
+ // The recorded bundle_sha256 is the tarball hash, not folder hash, so we
56
+ // can't compare directly. For now: if force isn't set and folder exists,
57
+ // we proceed with confirmation in a real terminal. In V0 we just warn.
58
+ // (Full editorial detection lands when files-table-per-version syncs.)
59
+ log.step(`Updating ${ref}: ${entry.version} -> ${info.latest_version}`);
60
+ }
61
+ const dl = await api(`/skills/${owner}/${slug}/download`);
62
+ const buf = await rawGet(dl.download.url);
63
+ if (!verifyBundleHash(buf, dl.bundle_sha256)) {
64
+ log.err(`Bundle hash mismatch for ${ref} — skipping.`);
65
+ skipped++;
66
+ continue;
67
+ }
68
+ const tmp = await import("node:fs/promises").then((m) => m.mkdtemp(join(tmpdir(), `floom-update-${slug}-`)));
69
+ try {
70
+ await extractBundle(buf, tmp);
71
+ await rm(installDir, { recursive: true, force: true });
72
+ await mkdir(installDir.replace(/\/[^/]+$/, ""), { recursive: true });
73
+ await rename(tmp, installDir);
74
+ }
75
+ catch (e) {
76
+ await rm(tmp, { recursive: true, force: true }).catch(() => { });
77
+ throw e;
78
+ }
79
+ const next = setLockEntry(lock, ref, {
80
+ ...entry,
81
+ version: dl.version,
82
+ bundle_sha256: dl.bundle_sha256,
83
+ installed_at: new Date().toISOString(),
84
+ });
85
+ await writeLock(projectDir, next);
86
+ log.ok(`Updated ${ref}: ${entry.version} -> ${dl.version}`);
87
+ updated++;
88
+ }
89
+ log.blank();
90
+ log.info(`${updated} updated, ${skipped} skipped.`);
91
+ }
92
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { scanSkillMarkdown } from "@floom/shared";
2
+ export interface ValidateOptions {
3
+ json?: boolean;
4
+ }
5
+ export interface ValidateReport {
6
+ ok: boolean;
7
+ manifest: {
8
+ ok: boolean;
9
+ message?: string;
10
+ };
11
+ skill_md: {
12
+ ok: boolean;
13
+ message?: string;
14
+ };
15
+ name_matches: {
16
+ ok: boolean;
17
+ message?: string;
18
+ };
19
+ bundle: {
20
+ ok: boolean;
21
+ message?: string;
22
+ files?: number;
23
+ size?: number;
24
+ has_scripts?: boolean;
25
+ };
26
+ security: {
27
+ ok: boolean;
28
+ findings: ReturnType<typeof scanSkillMarkdown>;
29
+ };
30
+ }
31
+ export declare function validateSkill(dir: string): Promise<ValidateReport>;
32
+ export declare function validateCommand(opts?: ValidateOptions): Promise<void>;
@@ -0,0 +1,108 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { readManifest, parseSkillFrontmatter, validateSkillFrontmatter, collectBundle, scanSkillMarkdown, } from "@floom/shared";
4
+ import { log } from "../lib/output.js";
5
+ export async function validateSkill(dir) {
6
+ const report = {
7
+ ok: true,
8
+ manifest: { ok: true },
9
+ skill_md: { ok: true },
10
+ name_matches: { ok: true },
11
+ bundle: { ok: true },
12
+ security: { ok: true, findings: [] },
13
+ };
14
+ // manifest
15
+ const m = await readManifest(dir);
16
+ if (!m.ok) {
17
+ report.manifest = { ok: false, message: m.error };
18
+ report.ok = false;
19
+ return report;
20
+ }
21
+ // SKILL.md presence + frontmatter
22
+ let skillMd;
23
+ try {
24
+ skillMd = await readFile(join(dir, "SKILL.md"), "utf8");
25
+ }
26
+ catch {
27
+ report.skill_md = { ok: false, message: "SKILL.md not found" };
28
+ report.ok = false;
29
+ return report;
30
+ }
31
+ const { meta } = parseSkillFrontmatter(skillMd);
32
+ const fmErr = validateSkillFrontmatter(meta);
33
+ if (fmErr) {
34
+ report.skill_md = { ok: false, message: fmErr };
35
+ report.ok = false;
36
+ }
37
+ if (meta.name && meta.name !== m.manifest.name) {
38
+ report.name_matches = {
39
+ ok: false,
40
+ message: `skill.json name="${m.manifest.name}" but SKILL.md frontmatter name="${meta.name}"`,
41
+ };
42
+ report.ok = false;
43
+ }
44
+ // bundle (path traversal, symlinks, file/size limits)
45
+ try {
46
+ const bundle = await collectBundle(dir);
47
+ report.bundle = {
48
+ ok: true,
49
+ files: bundle.files.length,
50
+ size: bundle.totalUncompressedBytes,
51
+ has_scripts: bundle.hasScripts,
52
+ };
53
+ }
54
+ catch (e) {
55
+ report.bundle = { ok: false, message: e.message };
56
+ report.ok = false;
57
+ }
58
+ // security: secrets + prompt injection in SKILL.md
59
+ const findings = scanSkillMarkdown(skillMd);
60
+ if (findings.length > 0) {
61
+ const secretFindings = findings.filter((f) => f.category === "secret");
62
+ report.security = { ok: secretFindings.length === 0, findings };
63
+ if (secretFindings.length > 0)
64
+ report.ok = false;
65
+ }
66
+ return report;
67
+ }
68
+ export async function validateCommand(opts = {}) {
69
+ const dir = process.cwd();
70
+ const r = await validateSkill(dir);
71
+ if (opts.json) {
72
+ console.log(JSON.stringify(r, null, 2));
73
+ process.exit(r.ok ? 0 : 1);
74
+ }
75
+ log.heading("Validating skill...");
76
+ const line = (ok, label, detail) => ok ? log.ok(`${label.padEnd(28)} ${detail ?? ""}`.trim())
77
+ : log.err(`${label.padEnd(28)} ${detail ?? ""}`.trim());
78
+ line(r.manifest.ok, "manifest schema", r.manifest.message);
79
+ line(r.skill_md.ok, "SKILL.md present", r.skill_md.message);
80
+ line(r.name_matches.ok, "name fields match", r.name_matches.message);
81
+ if (r.bundle.ok) {
82
+ line(true, "files + size limits", `${r.bundle.files} files, ${(r.bundle.size ?? 0) / 1024 | 0} KB`);
83
+ }
84
+ else {
85
+ line(false, "files + size limits", r.bundle.message);
86
+ }
87
+ if (r.security.findings.length === 0) {
88
+ line(true, "secrets + prompt injection", "clean");
89
+ }
90
+ else {
91
+ line(r.security.ok, "secrets + prompt injection", `${r.security.findings.length} finding(s)`);
92
+ for (const f of r.security.findings) {
93
+ log.warn(` line ${f.line} [${f.category}] ${f.label}: ${f.preview}`);
94
+ }
95
+ }
96
+ if (r.bundle.has_scripts) {
97
+ log.warn("This skill contains scripts/. Agents may execute these — review before activating.");
98
+ }
99
+ log.blank();
100
+ if (r.ok) {
101
+ log.ok("Valid.");
102
+ }
103
+ else {
104
+ log.err("Invalid.");
105
+ process.exit(1);
106
+ }
107
+ }
108
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function whoamiCommand(): Promise<void>;
@@ -0,0 +1,14 @@
1
+ import { readAuth } from "../config.js";
2
+ import { log } from "../lib/output.js";
3
+ export async function whoamiCommand() {
4
+ const auth = await readAuth();
5
+ if (!auth) {
6
+ log.info("Not logged in. Run: floom login");
7
+ return;
8
+ }
9
+ log.heading("Logged in as:");
10
+ log.kv("handle", `@${auth.handle}`);
11
+ log.kv("email", auth.email);
12
+ log.kv("api url", auth.apiUrl);
13
+ }
14
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAEvC,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,GAAG,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IACD,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5B,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface AuthState {
2
+ token: string;
3
+ handle: string;
4
+ email: string;
5
+ apiUrl: string;
6
+ }
7
+ export declare const DEFAULT_API_URL: string;
8
+ export declare function readAuth(): Promise<AuthState | null>;
9
+ export declare function writeAuth(state: AuthState): Promise<void>;
10
+ export declare function clearAuth(): Promise<void>;
11
+ export declare function getApiUrl(): string;
package/dist/config.js ADDED
@@ -0,0 +1,39 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ import { mkdir, readFile, writeFile, chmod } from "node:fs/promises";
4
+ const CONFIG_DIR = join(homedir(), ".floom");
5
+ const AUTH_FILE = join(CONFIG_DIR, "auth.json");
6
+ export const DEFAULT_API_URL = process.env.FLOOM_API_URL ?? "https://floom-v0.vercel.app/api/v1";
7
+ async function ensureDir() {
8
+ await mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });
9
+ }
10
+ export async function readAuth() {
11
+ try {
12
+ const raw = await readFile(AUTH_FILE, "utf8");
13
+ return JSON.parse(raw);
14
+ }
15
+ catch (e) {
16
+ if (e.code === "ENOENT")
17
+ return null;
18
+ throw e;
19
+ }
20
+ }
21
+ export async function writeAuth(state) {
22
+ await ensureDir();
23
+ await writeFile(AUTH_FILE, JSON.stringify(state, null, 2), { mode: 0o600 });
24
+ try {
25
+ await chmod(AUTH_FILE, 0o600);
26
+ }
27
+ catch { /* best effort on win */ }
28
+ }
29
+ export async function clearAuth() {
30
+ const { unlink } = await import("node:fs/promises");
31
+ try {
32
+ await unlink(AUTH_FILE);
33
+ }
34
+ catch { /* ignore */ }
35
+ }
36
+ export function getApiUrl() {
37
+ return process.env.FLOOM_API_URL ?? DEFAULT_API_URL;
38
+ }
39
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAErE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AAShD,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,oCAAoC,CAAC;AAEjG,KAAK,UAAU,SAAS;IACtB,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;IACtC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAK,CAA2B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAChE,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAgB;IAC9C,MAAM,SAAS,EAAE,CAAC;IAClB,MAAM,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5E,IAAI,CAAC;QAAC,MAAM,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,wBAAwB,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACpD,IAAI,CAAC;QAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,eAAe,CAAC;AACtD,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { FloomError } from "@floom/shared";
4
+ import { log } from "./lib/output.js";
5
+ import { loginCommand } from "./commands/login.js";
6
+ import { logoutCommand } from "./commands/logout.js";
7
+ import { whoamiCommand } from "./commands/whoami.js";
8
+ import { initCommand } from "./commands/init.js";
9
+ import { validateCommand } from "./commands/validate.js";
10
+ import { publishCommand } from "./commands/publish.js";
11
+ import { installCommand } from "./commands/install.js";
12
+ import { installedCommand } from "./commands/installed.js";
13
+ import { outdatedCommand } from "./commands/outdated.js";
14
+ import { updateCommand } from "./commands/update.js";
15
+ import { listCommand } from "./commands/list.js";
16
+ import { infoCommand } from "./commands/info.js";
17
+ import { shareCommand, unshareCommand } from "./commands/share.js";
18
+ import { libraryCreateCommand, libraryInviteCommand, libraryLeaveCommand, libraryListCommand } from "./commands/library.js";
19
+ import { VERSION } from "./version.js";
20
+ const program = new Command();
21
+ program
22
+ .name("floom")
23
+ .description("Floom CLI — publish, install, sync, and share AI agent skills.")
24
+ .version(VERSION);
25
+ program.command("login").description("Log in via browser (device code).").action(loginCommand);
26
+ program.command("logout").description("Log out and revoke local token.").action(logoutCommand);
27
+ program.command("whoami").description("Show the logged-in user.").action(whoamiCommand);
28
+ program.command("init").description("Scaffold a new skill in the current directory.").action(initCommand);
29
+ program
30
+ .command("validate")
31
+ .description("Validate the skill in the current directory.")
32
+ .option("--json", "Emit machine-readable JSON")
33
+ .action((opts) => validateCommand(opts));
34
+ program
35
+ .command("publish")
36
+ .description("Publish the skill in the current directory.")
37
+ .option("--library <slug>", "Publish into a shared library slug (default: personal)")
38
+ .action((opts) => publishCommand(opts));
39
+ program.command("push").description("Alias for `publish`.").option("--library <slug>").action((opts) => publishCommand(opts));
40
+ program
41
+ .command("install <ref>")
42
+ .description("Install a skill (default: .agents/skills/<slug>/).")
43
+ .option("--for <target>", "Tool preset: claude | codex | cursor | gemini | opencode | kimi | all")
44
+ .option("--to <path>", "Explicit install directory")
45
+ .option("--global", "Install to user-level folder instead of project-local")
46
+ .option("--force", "Overwrite existing folder")
47
+ .action((ref, opts) => installCommand(ref, opts));
48
+ program.command("installed").description("List installed skills in this project.").option("--json").action(installedCommand);
49
+ program.command("outdated").description("Show installed skills with newer versions available.").action(outdatedCommand);
50
+ program
51
+ .command("update [ref]")
52
+ .description("Update installed skills to latest.")
53
+ .option("--force", "Overwrite local edits")
54
+ .action((ref, opts) => updateCommand(ref, opts));
55
+ program
56
+ .command("list")
57
+ .description("List remote skills.")
58
+ .option("--mine", "Only your own skills (default)")
59
+ .option("--library <slug>", "Filter by library slug")
60
+ .option("--folder <uuid>", "Filter by folder id")
61
+ .option("--flat", "Print one ref per line")
62
+ .option("--query <q>", "Filter by query")
63
+ .action(listCommand);
64
+ program.command("info <ref>").description("Show details for a remote skill.").action(infoCommand);
65
+ program
66
+ .command("share <ref> <email>")
67
+ .description("Invite someone to a skill by email.")
68
+ .option("--role <role>", "viewer (default) or editor")
69
+ .action((ref, email, opts) => shareCommand(ref, email, opts));
70
+ program
71
+ .command("unshare <ref> <email>")
72
+ .description("Revoke someone's access.")
73
+ .action((ref, email) => unshareCommand(ref, email));
74
+ const lib = program.command("library").description("Manage libraries");
75
+ lib.command("list").action(libraryListCommand);
76
+ lib.command("create <slug> <name>").action((slug, name) => libraryCreateCommand(slug, name));
77
+ lib.command("invite <librarySlug> <email>").option("--role <role>", "viewer|editor|admin", "viewer").action((librarySlug, email, opts) => libraryInviteCommand(librarySlug, email, opts.role));
78
+ lib.command("leave <librarySlug>").action((librarySlug) => libraryLeaveCommand(librarySlug));
79
+ // Global error handler
80
+ async function main() {
81
+ try {
82
+ await program.parseAsync(process.argv);
83
+ }
84
+ catch (e) {
85
+ if (e instanceof FloomError) {
86
+ log.err(e.message);
87
+ if (e.code === "AUTH_REQUIRED" || e.code === "TOKEN_EXPIRED") {
88
+ log.info("Run: floom login");
89
+ }
90
+ process.exit(1);
91
+ }
92
+ log.err(e.message ?? "Unknown error");
93
+ if (process.env.FLOOM_DEBUG)
94
+ console.error(e);
95
+ process.exit(1);
96
+ }
97
+ }
98
+ main();
99
+ //# sourceMappingURL=index.js.map