@fusedframes/cli 0.1.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.
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +40 -0
- package/dist/commands/graph.d.ts +2 -0
- package/dist/commands/graph.js +11 -0
- package/dist/commands/libraries.d.ts +2 -0
- package/dist/commands/libraries.js +42 -0
- package/dist/commands/patterns.d.ts +2 -0
- package/dist/commands/patterns.js +46 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.js +23 -0
- package/dist/commands/traverse.d.ts +2 -0
- package/dist/commands/traverse.js +18 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +55 -0
- package/dist/lib/client.d.ts +6 -0
- package/dist/lib/client.js +47 -0
- package/dist/lib/config.d.ts +16 -0
- package/dist/lib/config.js +58 -0
- package/dist/lib/output.d.ts +2 -0
- package/dist/lib/output.js +7 -0
- package/dist/lib/types.d.ts +101 -0
- package/dist/lib/types.js +2 -0
- package/package.json +34 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { readConfig, writeConfig, getConfigInfo } from "../lib/config.js";
|
|
2
|
+
import { outputSuccess, outputError } from "../lib/output.js";
|
|
3
|
+
function readStdin() {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
let data = "";
|
|
6
|
+
process.stdin.setEncoding("utf-8");
|
|
7
|
+
process.stdin.on("data", (chunk) => (data += chunk));
|
|
8
|
+
process.stdin.on("end", () => resolve(data.trim()));
|
|
9
|
+
process.stdin.on("error", reject);
|
|
10
|
+
// If stdin is a TTY (interactive terminal), prompt the user
|
|
11
|
+
if (process.stdin.isTTY) {
|
|
12
|
+
process.stderr.write("Enter API key: ");
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export function registerConfigCommands(program) {
|
|
17
|
+
const config = program.command("config").description("Manage CLI configuration");
|
|
18
|
+
config
|
|
19
|
+
.command("set-key [apiKey]")
|
|
20
|
+
.description("Set the API key (reads from stdin if not provided)")
|
|
21
|
+
.action(async (apiKey) => {
|
|
22
|
+
let key = apiKey;
|
|
23
|
+
// If no argument provided, read from stdin
|
|
24
|
+
if (!key) {
|
|
25
|
+
key = await readStdin();
|
|
26
|
+
}
|
|
27
|
+
if (!key) {
|
|
28
|
+
outputError("validation_error", "No API key provided");
|
|
29
|
+
}
|
|
30
|
+
const existing = readConfig();
|
|
31
|
+
writeConfig({ ...existing, apiKey: key });
|
|
32
|
+
outputSuccess({ success: true, message: "API key saved" });
|
|
33
|
+
});
|
|
34
|
+
config
|
|
35
|
+
.command("show")
|
|
36
|
+
.description("Show current configuration")
|
|
37
|
+
.action(() => {
|
|
38
|
+
outputSuccess(getConfigInfo());
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { request } from "../lib/client.js";
|
|
2
|
+
import { outputSuccess } from "../lib/output.js";
|
|
3
|
+
export function registerGraphCommand(program) {
|
|
4
|
+
program
|
|
5
|
+
.command("graph <libraryId>")
|
|
6
|
+
.description("Get the full pattern graph for a library")
|
|
7
|
+
.action(async (libraryId) => {
|
|
8
|
+
const data = await request(`/libraries/${libraryId}/graph`);
|
|
9
|
+
outputSuccess(data);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { request } from "../lib/client.js";
|
|
2
|
+
import { outputSuccess } from "../lib/output.js";
|
|
3
|
+
export function registerLibraryCommands(program) {
|
|
4
|
+
const libraries = program
|
|
5
|
+
.command("libraries")
|
|
6
|
+
.description("Browse pattern libraries");
|
|
7
|
+
libraries
|
|
8
|
+
.command("list")
|
|
9
|
+
.description("List all accessible pattern libraries")
|
|
10
|
+
.action(async () => {
|
|
11
|
+
const data = await request("/libraries");
|
|
12
|
+
outputSuccess(data);
|
|
13
|
+
});
|
|
14
|
+
libraries
|
|
15
|
+
.command("get <id>")
|
|
16
|
+
.description("Get pattern library detail")
|
|
17
|
+
.action(async (id) => {
|
|
18
|
+
const data = await request(`/libraries/${id}`);
|
|
19
|
+
outputSuccess(data);
|
|
20
|
+
});
|
|
21
|
+
libraries
|
|
22
|
+
.command("categories <id>")
|
|
23
|
+
.description("List categories with pattern counts")
|
|
24
|
+
.action(async (id) => {
|
|
25
|
+
const data = await request(`/libraries/${id}/categories`);
|
|
26
|
+
outputSuccess(data);
|
|
27
|
+
});
|
|
28
|
+
libraries
|
|
29
|
+
.command("tags <id>")
|
|
30
|
+
.description("List tags with pattern counts")
|
|
31
|
+
.action(async (id) => {
|
|
32
|
+
const data = await request(`/libraries/${id}/tags`);
|
|
33
|
+
outputSuccess(data);
|
|
34
|
+
});
|
|
35
|
+
libraries
|
|
36
|
+
.command("applications <id>")
|
|
37
|
+
.description("List applications with pattern counts")
|
|
38
|
+
.action(async (id) => {
|
|
39
|
+
const data = await request(`/libraries/${id}/applications`);
|
|
40
|
+
outputSuccess(data);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { request } from "../lib/client.js";
|
|
2
|
+
import { outputSuccess } from "../lib/output.js";
|
|
3
|
+
export function registerPatternCommands(program) {
|
|
4
|
+
const patterns = program
|
|
5
|
+
.command("patterns")
|
|
6
|
+
.description("Query patterns");
|
|
7
|
+
patterns
|
|
8
|
+
.command("list <libraryId>")
|
|
9
|
+
.description("List patterns in a library")
|
|
10
|
+
.option("--category <value>", "Filter by category")
|
|
11
|
+
.option("--tag <value>", "Filter by tag")
|
|
12
|
+
.option("--app <value>", "Filter by application")
|
|
13
|
+
.option("--search <value>", "Search term")
|
|
14
|
+
.option("--page <number>", "Page number", "1")
|
|
15
|
+
.option("--page-size <number>", "Results per page", "20")
|
|
16
|
+
.action(async (libraryId, opts) => {
|
|
17
|
+
const data = await request(`/libraries/${libraryId}/patterns`, {
|
|
18
|
+
category: opts.category,
|
|
19
|
+
tag: opts.tag,
|
|
20
|
+
application: opts.app,
|
|
21
|
+
search: opts.search,
|
|
22
|
+
page: opts.page,
|
|
23
|
+
pageSize: opts.pageSize,
|
|
24
|
+
});
|
|
25
|
+
outputSuccess(data);
|
|
26
|
+
});
|
|
27
|
+
patterns
|
|
28
|
+
.command("get <id>")
|
|
29
|
+
.description("Get full pattern detail with inline edges")
|
|
30
|
+
.action(async (id) => {
|
|
31
|
+
const data = await request(`/patterns/${id}`);
|
|
32
|
+
outputSuccess(data);
|
|
33
|
+
});
|
|
34
|
+
patterns
|
|
35
|
+
.command("evidence <id>")
|
|
36
|
+
.description("Get evidence actions for a pattern")
|
|
37
|
+
.option("--page <number>", "Page number", "1")
|
|
38
|
+
.option("--page-size <number>", "Results per page", "20")
|
|
39
|
+
.action(async (id, opts) => {
|
|
40
|
+
const data = await request(`/patterns/${id}/evidence`, {
|
|
41
|
+
page: opts.page,
|
|
42
|
+
pageSize: opts.pageSize,
|
|
43
|
+
});
|
|
44
|
+
outputSuccess(data);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { request } from "../lib/client.js";
|
|
2
|
+
import { outputSuccess } from "../lib/output.js";
|
|
3
|
+
export function registerSearchCommand(program) {
|
|
4
|
+
program
|
|
5
|
+
.command("search <query>")
|
|
6
|
+
.description("Search patterns across all accessible libraries")
|
|
7
|
+
.option("--category <value>", "Filter by category")
|
|
8
|
+
.option("--tag <value>", "Filter by tag")
|
|
9
|
+
.option("--library <value>", "Filter by library ID")
|
|
10
|
+
.option("--page <number>", "Page number", "1")
|
|
11
|
+
.option("--page-size <number>", "Results per page", "20")
|
|
12
|
+
.action(async (query, opts) => {
|
|
13
|
+
const data = await request("/search/patterns", {
|
|
14
|
+
q: query,
|
|
15
|
+
category: opts.category,
|
|
16
|
+
tag: opts.tag,
|
|
17
|
+
libraryId: opts.library,
|
|
18
|
+
page: opts.page,
|
|
19
|
+
pageSize: opts.pageSize,
|
|
20
|
+
});
|
|
21
|
+
outputSuccess(data);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { request } from "../lib/client.js";
|
|
2
|
+
import { outputSuccess } from "../lib/output.js";
|
|
3
|
+
export function registerTraverseCommand(program) {
|
|
4
|
+
program
|
|
5
|
+
.command("traverse <patternId>")
|
|
6
|
+
.description("Traverse edges from a pattern")
|
|
7
|
+
.option("--direction <value>", "Traversal direction (outgoing, incoming, both)", "both")
|
|
8
|
+
.option("--label <value>", "Filter by edge label")
|
|
9
|
+
.option("--depth <number>", "Traversal depth (1-3)", "1")
|
|
10
|
+
.action(async (patternId, opts) => {
|
|
11
|
+
const data = await request(`/patterns/${patternId}/traverse`, {
|
|
12
|
+
direction: opts.direction,
|
|
13
|
+
label: opts.label,
|
|
14
|
+
depth: opts.depth,
|
|
15
|
+
});
|
|
16
|
+
outputSuccess(data);
|
|
17
|
+
});
|
|
18
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { registerConfigCommands } from "./commands/config.js";
|
|
4
|
+
import { registerLibraryCommands } from "./commands/libraries.js";
|
|
5
|
+
import { registerPatternCommands } from "./commands/patterns.js";
|
|
6
|
+
import { registerGraphCommand } from "./commands/graph.js";
|
|
7
|
+
import { registerTraverseCommand } from "./commands/traverse.js";
|
|
8
|
+
import { registerSearchCommand } from "./commands/search.js";
|
|
9
|
+
import { outputError } from "./lib/output.js";
|
|
10
|
+
import { FusedFramesError } from "./lib/client.js";
|
|
11
|
+
const program = new Command();
|
|
12
|
+
program
|
|
13
|
+
.name("fusedframes")
|
|
14
|
+
.description("Query FusedFrames behavioural patterns")
|
|
15
|
+
.version("0.1.0");
|
|
16
|
+
// Register all command groups
|
|
17
|
+
registerConfigCommands(program);
|
|
18
|
+
registerLibraryCommands(program);
|
|
19
|
+
registerPatternCommands(program);
|
|
20
|
+
registerGraphCommand(program);
|
|
21
|
+
registerTraverseCommand(program);
|
|
22
|
+
registerSearchCommand(program);
|
|
23
|
+
// Override commander to throw instead of exit, but keep help/version output
|
|
24
|
+
program.exitOverride();
|
|
25
|
+
// Global error handler
|
|
26
|
+
async function main() {
|
|
27
|
+
try {
|
|
28
|
+
await program.parseAsync(process.argv);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error instanceof FusedFramesError) {
|
|
32
|
+
outputError(error.code, error.message);
|
|
33
|
+
}
|
|
34
|
+
else if (error instanceof Error) {
|
|
35
|
+
// Commander exits with code 'commander.helpDisplayed' or 'commander.version'
|
|
36
|
+
const commanderError = error;
|
|
37
|
+
if (commanderError.code === "commander.helpDisplayed" ||
|
|
38
|
+
commanderError.code === "commander.version") {
|
|
39
|
+
// These are expected — commander already wrote output
|
|
40
|
+
process.exit(0);
|
|
41
|
+
}
|
|
42
|
+
if (commanderError.code === "commander.missingArgument" ||
|
|
43
|
+
commanderError.code === "commander.unknownCommand" ||
|
|
44
|
+
commanderError.code === "commander.unknownOption" ||
|
|
45
|
+
commanderError.code === "commander.missingMandatoryOptionValue") {
|
|
46
|
+
outputError("validation_error", error.message);
|
|
47
|
+
}
|
|
48
|
+
outputError("error", error.message);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
outputError("error", "An unexpected error occurred");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
main();
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { requireApiKey, getApiUrl } from "./config.js";
|
|
2
|
+
export class FusedFramesError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
status;
|
|
5
|
+
constructor(code, message, status) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.status = status;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export async function request(path, params) {
|
|
12
|
+
const apiKey = requireApiKey();
|
|
13
|
+
const baseUrl = getApiUrl();
|
|
14
|
+
// Enforce HTTPS (allow http://localhost for dev)
|
|
15
|
+
if (!baseUrl.startsWith("https://") && !baseUrl.startsWith("http://localhost")) {
|
|
16
|
+
throw new FusedFramesError("config_error", "API URL must use HTTPS. API keys cannot be sent over unencrypted connections.", 0);
|
|
17
|
+
}
|
|
18
|
+
// Build URL with query params
|
|
19
|
+
const url = new URL(path, baseUrl);
|
|
20
|
+
if (params) {
|
|
21
|
+
for (const [key, value] of Object.entries(params)) {
|
|
22
|
+
if (value !== undefined && value !== "") {
|
|
23
|
+
url.searchParams.set(key, value);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const response = await fetch(url.toString(), {
|
|
28
|
+
method: "GET",
|
|
29
|
+
headers: {
|
|
30
|
+
Authorization: `Bearer ${apiKey}`,
|
|
31
|
+
Accept: "application/json",
|
|
32
|
+
"User-Agent": "@fusedframes/cli/0.1.0",
|
|
33
|
+
},
|
|
34
|
+
signal: AbortSignal.timeout(30_000),
|
|
35
|
+
});
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
let errorBody;
|
|
38
|
+
try {
|
|
39
|
+
errorBody = (await response.json());
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
throw new FusedFramesError("server_error", `HTTP ${response.status}`, response.status);
|
|
43
|
+
}
|
|
44
|
+
throw new FusedFramesError(errorBody.error?.code || "unknown", errorBody.error?.message || `HTTP ${response.status}`, response.status);
|
|
45
|
+
}
|
|
46
|
+
return (await response.json());
|
|
47
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface Config {
|
|
2
|
+
apiKey?: string;
|
|
3
|
+
}
|
|
4
|
+
export declare function readConfig(): Config;
|
|
5
|
+
export declare function writeConfig(config: Config): void;
|
|
6
|
+
export declare function getApiKey(): string | undefined;
|
|
7
|
+
export declare function getApiUrl(): string;
|
|
8
|
+
export declare function requireApiKey(): string;
|
|
9
|
+
export declare function getConfigInfo(): {
|
|
10
|
+
apiKey: string | null;
|
|
11
|
+
apiKeySource: string;
|
|
12
|
+
apiUrl: string;
|
|
13
|
+
apiUrlSource: string;
|
|
14
|
+
configPath: string;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
2
|
+
import { homedir } from "os";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
function getConfigDir() {
|
|
5
|
+
return join(homedir(), ".config", "fusedframes");
|
|
6
|
+
}
|
|
7
|
+
function getConfigPath() {
|
|
8
|
+
return join(getConfigDir(), "config.json");
|
|
9
|
+
}
|
|
10
|
+
export function readConfig() {
|
|
11
|
+
try {
|
|
12
|
+
const data = readFileSync(getConfigPath(), "utf-8");
|
|
13
|
+
return JSON.parse(data);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function writeConfig(config) {
|
|
20
|
+
const dir = getConfigDir();
|
|
21
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
22
|
+
const path = getConfigPath();
|
|
23
|
+
writeFileSync(path, JSON.stringify(config, null, 2) + "\n", {
|
|
24
|
+
mode: 0o600,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export function getApiKey() {
|
|
28
|
+
// Env var takes precedence
|
|
29
|
+
if (process.env.FUSEDFRAMES_API_KEY) {
|
|
30
|
+
return process.env.FUSEDFRAMES_API_KEY;
|
|
31
|
+
}
|
|
32
|
+
return readConfig().apiKey;
|
|
33
|
+
}
|
|
34
|
+
export function getApiUrl() {
|
|
35
|
+
return process.env.FUSEDFRAMES_API_URL || "https://api.fusedframes.com";
|
|
36
|
+
}
|
|
37
|
+
export function requireApiKey() {
|
|
38
|
+
const key = getApiKey();
|
|
39
|
+
if (!key) {
|
|
40
|
+
throw new Error("API key not configured. Run: fusedframes config set-key <api-key>");
|
|
41
|
+
}
|
|
42
|
+
return key;
|
|
43
|
+
}
|
|
44
|
+
export function getConfigInfo() {
|
|
45
|
+
const envKey = process.env.FUSEDFRAMES_API_KEY;
|
|
46
|
+
const fileConfig = readConfig();
|
|
47
|
+
return {
|
|
48
|
+
apiKey: envKey
|
|
49
|
+
? `${envKey.slice(0, 8)}...`
|
|
50
|
+
: fileConfig.apiKey
|
|
51
|
+
? `${fileConfig.apiKey.slice(0, 8)}...`
|
|
52
|
+
: null,
|
|
53
|
+
apiKeySource: envKey ? "environment" : fileConfig.apiKey ? "config" : "none",
|
|
54
|
+
apiUrl: getApiUrl(),
|
|
55
|
+
apiUrlSource: process.env.FUSEDFRAMES_API_URL ? "environment" : "default",
|
|
56
|
+
configPath: getConfigPath(),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export interface LibrarySummary {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
description: string | null;
|
|
5
|
+
categories: string[];
|
|
6
|
+
tags: string[];
|
|
7
|
+
patternCount: number;
|
|
8
|
+
createdAt: string;
|
|
9
|
+
updatedAt: string;
|
|
10
|
+
}
|
|
11
|
+
export interface LibraryDetail extends LibrarySummary {
|
|
12
|
+
edgeCount: number;
|
|
13
|
+
}
|
|
14
|
+
export interface CategoryCount {
|
|
15
|
+
name: string;
|
|
16
|
+
patternCount: number;
|
|
17
|
+
}
|
|
18
|
+
export interface TagCount {
|
|
19
|
+
name: string;
|
|
20
|
+
patternCount: number;
|
|
21
|
+
}
|
|
22
|
+
export interface ApplicationCount {
|
|
23
|
+
name: string;
|
|
24
|
+
patternCount: number;
|
|
25
|
+
}
|
|
26
|
+
export interface PatternSummary {
|
|
27
|
+
id: string;
|
|
28
|
+
title: string;
|
|
29
|
+
behaviour: string;
|
|
30
|
+
reasoning: string;
|
|
31
|
+
trigger: string;
|
|
32
|
+
outcome: string;
|
|
33
|
+
category: string;
|
|
34
|
+
tags: string[];
|
|
35
|
+
applications: string | null;
|
|
36
|
+
actionCount: number;
|
|
37
|
+
connectionCount: number;
|
|
38
|
+
firstSeen: string | null;
|
|
39
|
+
lastSeen: string | null;
|
|
40
|
+
createdAt: string;
|
|
41
|
+
updatedAt: string;
|
|
42
|
+
}
|
|
43
|
+
export interface PatternDetail extends PatternSummary {
|
|
44
|
+
library: {
|
|
45
|
+
id: string;
|
|
46
|
+
name: string;
|
|
47
|
+
};
|
|
48
|
+
edges: {
|
|
49
|
+
outgoing: {
|
|
50
|
+
id: string;
|
|
51
|
+
targetPatternId: string;
|
|
52
|
+
targetPatternTitle: string;
|
|
53
|
+
label: string;
|
|
54
|
+
actionCount: number;
|
|
55
|
+
}[];
|
|
56
|
+
incoming: {
|
|
57
|
+
id: string;
|
|
58
|
+
sourcePatternId: string;
|
|
59
|
+
sourcePatternTitle: string;
|
|
60
|
+
label: string;
|
|
61
|
+
actionCount: number;
|
|
62
|
+
}[];
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export interface EvidenceAction {
|
|
66
|
+
id: string;
|
|
67
|
+
question: string;
|
|
68
|
+
response: string | null;
|
|
69
|
+
createdAt: string;
|
|
70
|
+
events: string[];
|
|
71
|
+
}
|
|
72
|
+
export interface GraphEdge {
|
|
73
|
+
id: string;
|
|
74
|
+
sourcePatternId: string;
|
|
75
|
+
targetPatternId: string;
|
|
76
|
+
label: string;
|
|
77
|
+
actionCount: number;
|
|
78
|
+
}
|
|
79
|
+
export interface TraverseNode {
|
|
80
|
+
id: string;
|
|
81
|
+
title: string;
|
|
82
|
+
behaviour: string;
|
|
83
|
+
category: string;
|
|
84
|
+
applications: string | null;
|
|
85
|
+
actionCount: number;
|
|
86
|
+
depth: number;
|
|
87
|
+
}
|
|
88
|
+
export interface SearchPattern {
|
|
89
|
+
id: string;
|
|
90
|
+
title: string;
|
|
91
|
+
behaviour: string;
|
|
92
|
+
category: string;
|
|
93
|
+
tags: string[];
|
|
94
|
+
applications: string | null;
|
|
95
|
+
actionCount: number;
|
|
96
|
+
connectionCount: number;
|
|
97
|
+
library: {
|
|
98
|
+
id: string;
|
|
99
|
+
name: string;
|
|
100
|
+
};
|
|
101
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fusedframes/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for querying FusedFrames behavioural patterns from AI agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"fusedframes": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=18.0.0"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc && chmod +x dist/index.js",
|
|
17
|
+
"prepublishOnly": "npm run build",
|
|
18
|
+
"typecheck": "tsc --noEmit"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"commander": "^13.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"typescript": "^5.9.0",
|
|
25
|
+
"@types/node": "^22.0.0"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"fusedframes",
|
|
29
|
+
"cli",
|
|
30
|
+
"patterns",
|
|
31
|
+
"ai-agent"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT"
|
|
34
|
+
}
|