frely-cli 0.3.7 → 0.4.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.
@@ -0,0 +1,52 @@
1
+ import { type AuthCredential } from "../auth.js";
2
+ export type SkillCapabilityLevel = "base" | "advanced";
3
+ export type SkillEntrypoint = "model" | "mcp" | "a2a";
4
+ export interface SkillCapability {
5
+ readonly id: string;
6
+ readonly level: SkillCapabilityLevel;
7
+ readonly entrypoints: readonly SkillEntrypoint[];
8
+ }
9
+ export interface SkillInvocationResult {
10
+ readonly text: string;
11
+ readonly usage?: Readonly<Record<string, unknown>>;
12
+ }
13
+ export declare class SkillInvocationError extends Error {
14
+ readonly code: "payment_required" | "entitlement_required" | "remote_authorization_failed" | "capability_unavailable";
15
+ readonly details: Readonly<{
16
+ readonly capabilityId?: string;
17
+ readonly registrationUrl?: string;
18
+ }>;
19
+ constructor(code: "payment_required" | "entitlement_required" | "remote_authorization_failed" | "capability_unavailable", details?: Readonly<{
20
+ readonly capabilityId?: string;
21
+ readonly registrationUrl?: string;
22
+ }>);
23
+ }
24
+ export interface RemoteAgentMcpInvoker {
25
+ invoke(input: {
26
+ readonly relayUrl: string;
27
+ readonly modelId: string;
28
+ readonly token: string;
29
+ readonly credential?: AuthCredential;
30
+ readonly task: string;
31
+ readonly capabilityId?: string;
32
+ readonly signal?: AbortSignal;
33
+ }): Promise<SkillInvocationResult>;
34
+ }
35
+ export interface SkillRouterOptions {
36
+ readonly relayUrl?: string;
37
+ readonly modelId: string;
38
+ readonly task: string;
39
+ readonly entrypoint?: SkillEntrypoint;
40
+ readonly capability?: SkillCapability;
41
+ readonly registrationUrl?: string;
42
+ readonly baseSkill: () => Promise<SkillInvocationResult>;
43
+ readonly remoteAgentMcp: RemoteAgentMcpInvoker;
44
+ readonly signal?: AbortSignal;
45
+ }
46
+ /**
47
+ * Route one Skill step according to the REQ-NEXT-SKILL-003 state machine.
48
+ * Local token presence is checked once and is intentionally not validated.
49
+ */
50
+ export declare function invokeSkill(options: SkillRouterOptions): Promise<SkillInvocationResult>;
51
+ /** Minimal stateless MCP client used by the router's remote path. */
52
+ export declare const remoteAgentMcpInvoker: RemoteAgentMcpInvoker;
@@ -0,0 +1,125 @@
1
+ import { hasConfiguredLocalToken, normalizeRelayUrl, readConfiguredLocalCredential, } from "../auth.js";
2
+ export class SkillInvocationError extends Error {
3
+ code;
4
+ details;
5
+ constructor(code, details = {}) {
6
+ super(code);
7
+ this.code = code;
8
+ this.details = details;
9
+ this.name = "SkillInvocationError";
10
+ }
11
+ }
12
+ /**
13
+ * Route one Skill step according to the REQ-NEXT-SKILL-003 state machine.
14
+ * Local token presence is checked once and is intentionally not validated.
15
+ */
16
+ export async function invokeSkill(options) {
17
+ const entrypoint = options.entrypoint ?? "model";
18
+ const capability = options.capability;
19
+ if (capability !== undefined && !capability.entrypoints.includes(entrypoint)) {
20
+ throw new SkillInvocationError("capability_unavailable", { capabilityId: capability.id });
21
+ }
22
+ const relayUrl = normalizeRelayUrl(options.relayUrl);
23
+ const tokenConfigured = await hasConfiguredLocalToken(relayUrl);
24
+ if (!tokenConfigured) {
25
+ if (capability?.level === "advanced") {
26
+ if (options.registrationUrl === undefined || !isSafeRegistrationUrl(options.registrationUrl)) {
27
+ throw new Error("registration_url_required");
28
+ }
29
+ throw new SkillInvocationError("payment_required", {
30
+ capabilityId: capability.id,
31
+ registrationUrl: options.registrationUrl,
32
+ });
33
+ }
34
+ return options.baseSkill();
35
+ }
36
+ // Do not fall back to baseSkill when the remote invocation rejects: a
37
+ // configured-but-expired/revoked token must remain on the remote route.
38
+ const credential = await readConfiguredLocalCredential(relayUrl);
39
+ if (credential === null || credential.value.length === 0) {
40
+ throw new SkillInvocationError("remote_authorization_failed", {
41
+ ...(capability === undefined ? {} : { capabilityId: capability.id }),
42
+ });
43
+ }
44
+ try {
45
+ return await options.remoteAgentMcp.invoke({
46
+ relayUrl,
47
+ modelId: options.modelId,
48
+ token: credential.value,
49
+ credential,
50
+ task: options.task,
51
+ ...(capability === undefined ? {} : { capabilityId: capability.id }),
52
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
53
+ });
54
+ }
55
+ catch (error) {
56
+ if (error instanceof SkillInvocationError)
57
+ throw error;
58
+ throw new SkillInvocationError("remote_authorization_failed", {
59
+ ...(capability === undefined ? {} : { capabilityId: capability.id }),
60
+ });
61
+ }
62
+ }
63
+ /** Minimal stateless MCP client used by the router's remote path. */
64
+ export const remoteAgentMcpInvoker = {
65
+ async invoke(input) {
66
+ const endpoint = new URL(`/mcp/${encodeURIComponent(input.modelId)}`, input.relayUrl);
67
+ const response = await fetch(endpoint, {
68
+ method: "POST",
69
+ headers: {
70
+ accept: "application/json",
71
+ "content-type": "application/json",
72
+ ...(input.credential?.scheme === "cookie"
73
+ ? { cookie: input.credential.value }
74
+ : { authorization: `Bearer ${input.token}` }),
75
+ },
76
+ body: JSON.stringify({
77
+ jsonrpc: "2.0",
78
+ id: "skill-invoke",
79
+ method: "tools/call",
80
+ params: {
81
+ name: "invoke",
82
+ arguments: {
83
+ input: input.task,
84
+ ...(input.capabilityId === undefined ? {} : { capabilityId: input.capabilityId }),
85
+ },
86
+ },
87
+ }),
88
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
89
+ });
90
+ const payload = await response.json().catch(() => null);
91
+ if (!response.ok || !isRecord(payload)) {
92
+ throw new SkillInvocationError("remote_authorization_failed");
93
+ }
94
+ if (isRecord(payload.error)) {
95
+ const data = isRecord(payload.error.data) ? payload.error.data : {};
96
+ const code = data.code === "entitlement_required"
97
+ ? "entitlement_required"
98
+ : data.code === "capability_unavailable" ? "capability_unavailable" : "remote_authorization_failed";
99
+ throw new SkillInvocationError(code);
100
+ }
101
+ const result = isRecord(payload.result) ? payload.result : undefined;
102
+ const content = result && Array.isArray(result.content) ? result.content : [];
103
+ const text = content
104
+ .filter((item) => isRecord(item) && item.type === "text" && typeof item.text === "string")
105
+ .map((item) => item.text)
106
+ .join("");
107
+ if (result === undefined || result.isError === true || text.length === 0) {
108
+ throw new SkillInvocationError("remote_authorization_failed");
109
+ }
110
+ return Object.freeze({ text });
111
+ },
112
+ };
113
+ function isRecord(value) {
114
+ return value !== null && typeof value === "object" && !Array.isArray(value);
115
+ }
116
+ function isSafeRegistrationUrl(value) {
117
+ try {
118
+ const url = new URL(value);
119
+ return url.protocol === "https:" && !url.username && !url.password && !url.hash;
120
+ }
121
+ catch {
122
+ return false;
123
+ }
124
+ }
125
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/skill/router.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frely-cli",
3
- "version": "0.3.7",
3
+ "version": "0.4.0",
4
4
  "description": "Frely account CLI and local MCP runtime",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {