@floomhq/skills 0.2.1 → 0.2.3
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 +32 -14
- package/dist/index.js.map +3 -3
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2407,7 +2407,7 @@ function getApiBaseUrls(preferred) {
|
|
|
2407
2407
|
}
|
|
2408
2408
|
|
|
2409
2409
|
// src/version.ts
|
|
2410
|
-
var VERSION = "0.2.
|
|
2410
|
+
var VERSION = "0.2.3";
|
|
2411
2411
|
|
|
2412
2412
|
// src/api-client.ts
|
|
2413
2413
|
var DEFAULT_TIMEOUT_MS = 2e4;
|
|
@@ -2598,6 +2598,14 @@ async function whoamiCommand() {
|
|
|
2598
2598
|
log.info("Not logged in. Run: floom login");
|
|
2599
2599
|
return;
|
|
2600
2600
|
}
|
|
2601
|
+
try {
|
|
2602
|
+
await api("/me", { authRequired: true });
|
|
2603
|
+
} catch (e) {
|
|
2604
|
+
log.err(`Stored login is not accepted by the Floom API: ${e.message}`);
|
|
2605
|
+
log.info("Run: floom login");
|
|
2606
|
+
process.exitCode = 1;
|
|
2607
|
+
return;
|
|
2608
|
+
}
|
|
2601
2609
|
log.heading("Logged in as:");
|
|
2602
2610
|
log.kv("handle", `@${auth.handle}`);
|
|
2603
2611
|
log.kv("email", auth.email);
|
|
@@ -2920,7 +2928,11 @@ async function readLock(projectDir) {
|
|
|
2920
2928
|
try {
|
|
2921
2929
|
const raw = await readFile7(join7(projectDir, "floom.lock"), "utf8");
|
|
2922
2930
|
const parsed = JSON.parse(raw);
|
|
2923
|
-
|
|
2931
|
+
if (parsed.schema_version === "0.1") return parsed;
|
|
2932
|
+
const version = typeof parsed.schema_version === "string" ? parsed.schema_version : "missing";
|
|
2933
|
+
throw new Error(
|
|
2934
|
+
`LOCK_SCHEMA_UNSUPPORTED: floom.lock schema_version ${version} is not supported by this CLI. The existing floom.lock was left unchanged; migrate it or reinstall skills with the current CLI.`
|
|
2935
|
+
);
|
|
2924
2936
|
} catch (e) {
|
|
2925
2937
|
if (e.code === "ENOENT") return { ...EMPTY };
|
|
2926
2938
|
throw e;
|
|
@@ -3349,7 +3361,7 @@ async function libraryLeaveCommand(librarySlug) {
|
|
|
3349
3361
|
// src/commands/mcp.ts
|
|
3350
3362
|
import { mkdtemp, mkdir as mkdir6, readdir as readdir4, readFile as readFile8, rename as rename3, rm as rm3, writeFile as writeFile4 } from "node:fs/promises";
|
|
3351
3363
|
import { join as join10 } from "node:path";
|
|
3352
|
-
import {
|
|
3364
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
3353
3365
|
import { z as z2 } from "zod";
|
|
3354
3366
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3355
3367
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -3371,11 +3383,7 @@ async function resolveToken() {
|
|
|
3371
3383
|
if (fromEnv) return fromEnv;
|
|
3372
3384
|
const auth = await readAuth();
|
|
3373
3385
|
if (auth?.token) return auth.token;
|
|
3374
|
-
|
|
3375
|
-
const raw = await readFile8(authPath, "utf8");
|
|
3376
|
-
const parsed = JSON.parse(raw);
|
|
3377
|
-
if (!parsed.token) throw new Error("Missing token in ~/.floom/auth.json");
|
|
3378
|
-
return parsed.token;
|
|
3386
|
+
throw new Error("Authentication required. Run `floom login` or set FLOOM_API_TOKEN.");
|
|
3379
3387
|
}
|
|
3380
3388
|
async function apiWithToken(token, path, query) {
|
|
3381
3389
|
const auth = await readAuth();
|
|
@@ -3466,14 +3474,15 @@ async function parseSkillBundle(bundle) {
|
|
|
3466
3474
|
}
|
|
3467
3475
|
}
|
|
3468
3476
|
async function mcpCommand() {
|
|
3469
|
-
const token = await resolveToken();
|
|
3470
3477
|
const server = new McpServer({ name: "floom", version: VERSION });
|
|
3471
3478
|
server.tool("search_skills", { query: z2.string().min(1), workspace: z2.string().optional(), library: z2.string().optional() }, async ({ query, workspace, library }) => {
|
|
3479
|
+
const token = await resolveToken();
|
|
3472
3480
|
const workspaceSlug = workspace ?? library;
|
|
3473
3481
|
const result = await apiWithToken(token, "/skills", { q: query, ...workspaceSlug ? { library: workspaceSlug } : {} });
|
|
3474
3482
|
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
3475
3483
|
});
|
|
3476
3484
|
server.tool("get_skill", { ref: z2.string().min(3) }, async ({ ref }) => {
|
|
3485
|
+
const token = await resolveToken();
|
|
3477
3486
|
const parsed = parseSkillRef(ref);
|
|
3478
3487
|
if (!parsed) throw new Error("Invalid ref. Expected @owner/slug or workspace/slug");
|
|
3479
3488
|
const meta = await apiWithToken(token, `/skills/${parsed.owner}/${parsed.slug}`);
|
|
@@ -3483,12 +3492,14 @@ async function mcpCommand() {
|
|
|
3483
3492
|
return { content: [{ type: "text", text: JSON.stringify({ ref, meta, ...parsedBundle }) }] };
|
|
3484
3493
|
});
|
|
3485
3494
|
async function listWorkspaces() {
|
|
3495
|
+
const token = await resolveToken();
|
|
3486
3496
|
const result = await apiWithToken(token, "/libraries");
|
|
3487
3497
|
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
3488
3498
|
}
|
|
3489
3499
|
server.tool("list_workspaces", {}, listWorkspaces);
|
|
3490
3500
|
server.tool("list_libraries", {}, listWorkspaces);
|
|
3491
3501
|
server.tool("install_skill", { ref: z2.string().min(3), target: z2.enum(["claude", "codex", "cursor", "kimi", "opencode", "gemini"]) }, async ({ ref, target }) => {
|
|
3502
|
+
const token = await resolveToken();
|
|
3492
3503
|
const installed = await installViaApi(token, ref, target);
|
|
3493
3504
|
return { content: [{ type: "text", text: JSON.stringify(installed) }] };
|
|
3494
3505
|
});
|
|
@@ -3508,6 +3519,9 @@ function textOf(result) {
|
|
|
3508
3519
|
function pass(name, detail) {
|
|
3509
3520
|
return { name, ok: true, detail };
|
|
3510
3521
|
}
|
|
3522
|
+
function warn(name, detail) {
|
|
3523
|
+
return { name, ok: true, detail, status: "warn" };
|
|
3524
|
+
}
|
|
3511
3525
|
function fail(name, detail) {
|
|
3512
3526
|
return { name, ok: false, detail };
|
|
3513
3527
|
}
|
|
@@ -3523,9 +3537,7 @@ async function doctorCommand(opts = {}) {
|
|
|
3523
3537
|
const auth = await readAuth();
|
|
3524
3538
|
const token = process.env.FLOOM_API_TOKEN?.trim() || auth?.token;
|
|
3525
3539
|
if (!token) {
|
|
3526
|
-
checks.push(
|
|
3527
|
-
emitDoctor(checks, opts.json);
|
|
3528
|
-
process.exit(1);
|
|
3540
|
+
checks.push(warn("fresh_agent_auth", "missing token; API-backed tool calls skipped"));
|
|
3529
3541
|
}
|
|
3530
3542
|
const cliPath = process.argv[1];
|
|
3531
3543
|
if (!cliPath) {
|
|
@@ -3543,8 +3555,8 @@ async function doctorCommand(opts = {}) {
|
|
|
3543
3555
|
env: {
|
|
3544
3556
|
...process.env,
|
|
3545
3557
|
HOME: tmpHome,
|
|
3546
|
-
FLOOM_API_TOKEN: token,
|
|
3547
3558
|
FLOOM_SKILLS_DIR: tmpSkills,
|
|
3559
|
+
...token ? { FLOOM_API_TOKEN: token } : {},
|
|
3548
3560
|
...auth?.apiUrl ? { FLOOM_API_URL: auth.apiUrl } : {}
|
|
3549
3561
|
},
|
|
3550
3562
|
stderr: "pipe"
|
|
@@ -3557,6 +3569,11 @@ async function doctorCommand(opts = {}) {
|
|
|
3557
3569
|
const expected = ["get_skill", "install_skill", "list_workspaces", "search_skills"];
|
|
3558
3570
|
const missing = expected.filter((name) => !toolNames.includes(name));
|
|
3559
3571
|
checks.push(missing.length === 0 ? pass("mcp_tools", toolNames.join(", ")) : fail("mcp_tools", `missing ${missing.join(", ")}`));
|
|
3572
|
+
if (!token) {
|
|
3573
|
+
checks.push(warn("mcp_api_calls", "skipped because no FLOOM_API_TOKEN or ~/.floom/auth.json was available"));
|
|
3574
|
+
emitDoctor(checks, opts.json);
|
|
3575
|
+
return;
|
|
3576
|
+
}
|
|
3560
3577
|
const workspaces = await client.callTool({ name: "list_workspaces", arguments: {} });
|
|
3561
3578
|
checks.push(textOf(workspaces).length > 0 ? pass("mcp_list_workspaces", `${textOf(workspaces).length} chars`) : fail("mcp_list_workspaces", "empty response"));
|
|
3562
3579
|
const search = await client.callTool({ name: "search_skills", arguments: { query: opts.query ?? "pdf" } });
|
|
@@ -3588,7 +3605,8 @@ function emitDoctor(checks, json) {
|
|
|
3588
3605
|
log.heading("Floom doctor");
|
|
3589
3606
|
for (const check of checks) {
|
|
3590
3607
|
const detail = check.detail ? ` ${check.detail}` : "";
|
|
3591
|
-
if (check.
|
|
3608
|
+
if (check.status === "warn") log.warn(`${check.name}${detail}`);
|
|
3609
|
+
else if (check.ok) log.ok(`${check.name}${detail}`);
|
|
3592
3610
|
else log.err(`${check.name}${detail}`);
|
|
3593
3611
|
}
|
|
3594
3612
|
}
|