@kybernesis/payments 0.1.0 → 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.
- package/README.md +5 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.js +3 -3
- package/dist/link-tools.d.ts +29 -0
- package/dist/link-tools.js +71 -0
- package/dist/pay-on-computer.d.ts +3 -3
- package/dist/pay-on-computer.js +2 -5
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ friends: the agent names a merchant and a total, the person approves it in the
|
|
|
7
7
|
Link app, and Link issues a one-time card for exactly that purchase. This
|
|
8
8
|
package adds the two pieces that make it usable by a Kybernesis agent:
|
|
9
9
|
|
|
10
|
+
- **`linkTool(name)`** — Link's tool catalog (`@stripe/link-sdk/tools`) as eve tools, one per file. `create_spend_request` asks the person in eve before Link asks them again; every result is stripped of card fields.
|
|
10
11
|
- **`linkCliAuth()`** — the owner's `link-cli` sign-in as the agent's wallet
|
|
11
12
|
credential. The owner runs `npx link-cli auth login --client-name <agent>` on
|
|
12
13
|
the agent's host once (a device-code flow approved in the Link app); the CLI
|
|
@@ -18,9 +19,9 @@ package adds the two pieces that make it usable by a Kybernesis agent:
|
|
|
18
19
|
own browser via `@kybernesis/computer`'s fill primitive. The model supplies CSS
|
|
19
20
|
selectors; the card goes Link → page and comes back only as brand + last four.
|
|
20
21
|
|
|
21
|
-
```ts title="agent/
|
|
22
|
-
import {
|
|
23
|
-
export default
|
|
22
|
+
```ts title="agent/tools/create_spend_request.ts"
|
|
23
|
+
import { linkTool } from "@kybernesis/payments";
|
|
24
|
+
export default linkTool("create_spend_request"); // one file per Link tool; see LINK_TOOL_NAMES
|
|
24
25
|
```
|
|
25
26
|
|
|
26
27
|
```ts title="agent/tools/pay_on_computer.ts"
|
|
@@ -42,9 +43,7 @@ approval link, wait, fill, screenshot, submit, report with `link__create_report`
|
|
|
42
43
|
|
|
43
44
|
## Gotchas
|
|
44
45
|
|
|
45
|
-
- `@stripe/link-integrations-eve
|
|
46
|
-
as a plain extension and have been exercised on eve 0.68, but a Link API change
|
|
47
|
-
shows up there first.
|
|
46
|
+
- Stripe's own eve extension (`@stripe/link-integrations-eve`, built with eve 0.66) does not mount on eve 0.68 — that is why the tools are wrapped here from the SDK instead.
|
|
48
47
|
- Link may require 3-D Secure or a verification step the agent cannot complete.
|
|
49
48
|
The instructions tell it to stop and describe the screen; the person can take
|
|
50
49
|
over the computer.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { linkCliAuth, linkCliAuthFile, readStoredAuth, NOT_SIGNED_IN, type LinkCliAuthOptions } from "./link-cli-auth.js";
|
|
2
2
|
export { payOnComputerTool } from "./pay-on-computer.js";
|
|
3
3
|
export { PAYMENTS_INSTRUCTIONS } from "./instructions.js";
|
|
4
|
-
export {
|
|
4
|
+
export { linkTool, linkClient, sanitizeLinkOutput, LINK_TOOL_NAMES, type LinkToolName } from "./link-tools.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { linkCliAuth, linkCliAuthFile, readStoredAuth, NOT_SIGNED_IN } from "./link-cli-auth.js";
|
|
2
2
|
export { payOnComputerTool } from "./pay-on-computer.js";
|
|
3
3
|
export { PAYMENTS_INSTRUCTIONS } from "./instructions.js";
|
|
4
|
-
export {
|
|
4
|
+
export { linkTool, linkClient, sanitizeLinkOutput, LINK_TOOL_NAMES } from "./link-tools.js";
|
package/dist/instructions.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PAYMENTS_INSTRUCTIONS = "## Paying for things\n\nYou can buy things with the person's Link wallet. Every purchase is their decision twice over: creating a spend request asks them here, and Link asks them again in their Link app before any card exists. Never work around either step.\n\nThe order, every time:\n1. Agree the exact purchase first: merchant, items, final total including tax and shipping, in the right currency. Get these from the actual checkout page in your own browser (open_browser, then look), not from memory.\n2. `
|
|
1
|
+
export declare const PAYMENTS_INSTRUCTIONS = "## Paying for things\n\nYou can buy things with the person's Link wallet. Every purchase is their decision twice over: creating a spend request asks them here, and Link asks them again in their Link app before any card exists. Never work around either step.\n\nThe order, every time:\n1. Agree the exact purchase first: merchant, items, final total including tax and shipping, in the right currency. Get these from the actual checkout page in your own browser (open_browser, then look), not from memory.\n2. `create_spend_request` with that merchant, those line items and that total. If it comes back without an approval link, call `request_spend_approval`. Send the person the approval link as a plain link, and wait. Do not create a second request for the same purchase.\n3. When `retrieve_spend_request` says approved, use `pay_on_computer` to type the one-time card into the checkout. You give it the selectors of the card fields you can see; the card itself never comes to you. Check the filled form in a screenshot, confirm the total still matches, then submit.\n4. Report the outcome with `create_report`: succeeded, failed, or what the merchant said. If the merchant needs more (3-D Secure, a code), stop and tell the person exactly what is on the screen; they can take over your screen.\n\nNever read card numbers or CVCs aloud, never paste them into chat or a file, never guess a total. If Link asks for verification you cannot complete, say so.\n";
|
package/dist/instructions.js
CHANGED
|
@@ -4,9 +4,9 @@ You can buy things with the person's Link wallet. Every purchase is their decisi
|
|
|
4
4
|
|
|
5
5
|
The order, every time:
|
|
6
6
|
1. Agree the exact purchase first: merchant, items, final total including tax and shipping, in the right currency. Get these from the actual checkout page in your own browser (open_browser, then look), not from memory.
|
|
7
|
-
2. \`
|
|
8
|
-
3. When \`
|
|
9
|
-
4. Report the outcome with \`
|
|
7
|
+
2. \`create_spend_request\` with that merchant, those line items and that total. If it comes back without an approval link, call \`request_spend_approval\`. Send the person the approval link as a plain link, and wait. Do not create a second request for the same purchase.
|
|
8
|
+
3. When \`retrieve_spend_request\` says approved, use \`pay_on_computer\` to type the one-time card into the checkout. You give it the selectors of the card fields you can see; the card itself never comes to you. Check the filled form in a screenshot, confirm the total still matches, then submit.
|
|
9
|
+
4. Report the outcome with \`create_report\`: succeeded, failed, or what the merchant said. If the merchant needs more (3-D Secure, a code), stop and tell the person exactly what is on the screen; they can take over your screen.
|
|
10
10
|
|
|
11
11
|
Never read card numbers or CVCs aloud, never paste them into chat or a file, never guess a total. If Link asks for verification you cannot complete, say so.
|
|
12
12
|
`;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Link } from "@stripe/link-sdk";
|
|
2
|
+
import { type ToolDefinition } from "eve/tools";
|
|
3
|
+
import { type LinkCliAuthOptions } from "./link-cli-auth.js";
|
|
4
|
+
/**
|
|
5
|
+
* Stripe's Link tools, mounted the Kybernesis way.
|
|
6
|
+
*
|
|
7
|
+
* Stripe ships an eve extension, but it is built against an older eve and
|
|
8
|
+
* eve 0.68 refuses to mount it. The same tool catalog is available
|
|
9
|
+
* framework-free from `@stripe/link-sdk/tools`, so each one is wrapped here as
|
|
10
|
+
* an eve tool: the owner's link-cli sign-in supplies the token on every call,
|
|
11
|
+
* creating a spend request asks the person in eve before it asks them in Link,
|
|
12
|
+
* and anything that could carry a card number is stripped from what the model
|
|
13
|
+
* sees — the card has exactly one path, `pay_on_computer`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const LINK_TOOL_NAMES: readonly ["retrieve_user_info", "list_payment_methods", "list_shipping_addresses", "list_spend_requests", "create_spend_request", "update_spend_request", "cancel_spend_request", "request_spend_approval", "retrieve_spend_request", "create_report"];
|
|
16
|
+
export type LinkToolName = (typeof LINK_TOOL_NAMES)[number];
|
|
17
|
+
/** A Link client whose token is the owner's current link-cli sign-in, read at call time. */
|
|
18
|
+
export declare function linkClient(options?: LinkCliAuthOptions): Link;
|
|
19
|
+
/** Remove anything that is or contains a card credential before it reaches the model. */
|
|
20
|
+
export declare function sanitizeLinkOutput<T>(value: T): T;
|
|
21
|
+
/**
|
|
22
|
+
* One Link tool as an eve tool. Mount each in `agent/tools/<name>.ts`:
|
|
23
|
+
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { linkTool } from "@kybernesis/payments";
|
|
26
|
+
* export default linkTool("create_spend_request");
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function linkTool<N extends LinkToolName>(name: N, options?: LinkCliAuthOptions): ToolDefinition<Record<string, unknown>, unknown>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Link } from "@stripe/link-sdk";
|
|
2
|
+
import { createLinkTools } from "@stripe/link-sdk/tools";
|
|
3
|
+
import { defineTool } from "eve/tools";
|
|
4
|
+
import { always, never } from "eve/tools/approval";
|
|
5
|
+
import { linkCliAuth } from "./link-cli-auth.js";
|
|
6
|
+
/**
|
|
7
|
+
* Stripe's Link tools, mounted the Kybernesis way.
|
|
8
|
+
*
|
|
9
|
+
* Stripe ships an eve extension, but it is built against an older eve and
|
|
10
|
+
* eve 0.68 refuses to mount it. The same tool catalog is available
|
|
11
|
+
* framework-free from `@stripe/link-sdk/tools`, so each one is wrapped here as
|
|
12
|
+
* an eve tool: the owner's link-cli sign-in supplies the token on every call,
|
|
13
|
+
* creating a spend request asks the person in eve before it asks them in Link,
|
|
14
|
+
* and anything that could carry a card number is stripped from what the model
|
|
15
|
+
* sees — the card has exactly one path, `pay_on_computer`.
|
|
16
|
+
*/
|
|
17
|
+
export const LINK_TOOL_NAMES = [
|
|
18
|
+
"retrieve_user_info",
|
|
19
|
+
"list_payment_methods",
|
|
20
|
+
"list_shipping_addresses",
|
|
21
|
+
"list_spend_requests",
|
|
22
|
+
"create_spend_request",
|
|
23
|
+
"update_spend_request",
|
|
24
|
+
"cancel_spend_request",
|
|
25
|
+
"request_spend_approval",
|
|
26
|
+
"retrieve_spend_request",
|
|
27
|
+
"create_report",
|
|
28
|
+
];
|
|
29
|
+
/** A Link client whose token is the owner's current link-cli sign-in, read at call time. */
|
|
30
|
+
export function linkClient(options = {}) {
|
|
31
|
+
const auth = linkCliAuth(options);
|
|
32
|
+
return new Link({ getAccessToken: async () => (await auth.getToken({})).token });
|
|
33
|
+
}
|
|
34
|
+
/** Remove anything that is or contains a card credential before it reaches the model. */
|
|
35
|
+
export function sanitizeLinkOutput(value) {
|
|
36
|
+
if (Array.isArray(value))
|
|
37
|
+
return value.map((v) => sanitizeLinkOutput(v));
|
|
38
|
+
if (value && typeof value === "object") {
|
|
39
|
+
const out = {};
|
|
40
|
+
for (const [k, v] of Object.entries(value)) {
|
|
41
|
+
if (k === "card" || k === "credential" || k === "number" || k === "cvc" || k === "payment_token" || k === "shared_payment_token")
|
|
42
|
+
continue;
|
|
43
|
+
out[k] = sanitizeLinkOutput(v);
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* One Link tool as an eve tool. Mount each in `agent/tools/<name>.ts`:
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* import { linkTool } from "@kybernesis/payments";
|
|
54
|
+
* export default linkTool("create_spend_request");
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function linkTool(name, options = {}) {
|
|
58
|
+
const catalog = createLinkTools(linkClient(options));
|
|
59
|
+
const tool = catalog[name];
|
|
60
|
+
return defineTool({
|
|
61
|
+
description: tool.description,
|
|
62
|
+
inputSchema: tool.inputSchema,
|
|
63
|
+
// Asking Link for money starts with asking the person here. Reading and
|
|
64
|
+
// reporting do not; Link's own approval step still gates every card.
|
|
65
|
+
approval: name === "create_spend_request" ? always() : never(),
|
|
66
|
+
async execute(input, ctx) {
|
|
67
|
+
const result = await tool.execute(input, ctx);
|
|
68
|
+
return sanitizeLinkOutput(result);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { LinkCliAuthOptions } from "./link-cli-auth.js";
|
|
2
2
|
/**
|
|
3
3
|
* Type the one-time card of an APPROVED Link spend request into a checkout
|
|
4
4
|
* form on the agent's own computer. The card number and CVC go from Link to
|
|
@@ -14,7 +14,7 @@ export declare function payOnComputerTool(options?: LinkCliAuthOptions): import(
|
|
|
14
14
|
spend_request_id: string;
|
|
15
15
|
page_url: string;
|
|
16
16
|
fields: {
|
|
17
|
-
field: "number" | "
|
|
17
|
+
field: "number" | "cvc" | "name" | "exp_month" | "exp_year" | "expiration" | "postal_code";
|
|
18
18
|
selector: string;
|
|
19
19
|
frameUrl?: string | undefined;
|
|
20
20
|
format?: "MM/YY" | "MM/YYYY" | undefined;
|
|
@@ -33,7 +33,7 @@ export declare function payOnComputerTool(options?: LinkCliAuthOptions): import(
|
|
|
33
33
|
spend_request_id: string;
|
|
34
34
|
page_url: string;
|
|
35
35
|
fields: {
|
|
36
|
-
field: "number" | "
|
|
36
|
+
field: "number" | "cvc" | "name" | "exp_month" | "exp_year" | "expiration" | "postal_code";
|
|
37
37
|
selector: string;
|
|
38
38
|
frameUrl?: string | undefined;
|
|
39
39
|
format?: "MM/YY" | "MM/YYYY" | undefined;
|
package/dist/pay-on-computer.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { Link } from "@stripe/link-sdk";
|
|
2
1
|
import { fillOnComputer } from "@kybernesis/computer";
|
|
3
2
|
import { defineTool } from "eve/tools";
|
|
4
3
|
import { never } from "eve/tools/approval";
|
|
5
4
|
import { z } from "zod";
|
|
6
|
-
import {
|
|
5
|
+
import { linkClient } from "./link-tools.js";
|
|
7
6
|
const fieldSchema = z.object({
|
|
8
7
|
field: z.enum(["name", "number", "exp_month", "exp_year", "expiration", "cvc", "postal_code"]),
|
|
9
8
|
selector: z.string().min(1).max(500).describe("CSS selector of that input on the checkout page."),
|
|
@@ -22,7 +21,7 @@ const fieldSchema = z.object({
|
|
|
22
21
|
* a request that is not approved is refused.
|
|
23
22
|
*/
|
|
24
23
|
export function payOnComputerTool(options = {}) {
|
|
25
|
-
const
|
|
24
|
+
const link = linkClient(options);
|
|
26
25
|
return defineTool({
|
|
27
26
|
description: "Type the one-time card from an APPROVED Link spend request into the checkout form open in your own browser. Give the CSS selector of each card field you can see (name, number, expiration or exp_month/exp_year, cvc, postal code). The card details never come back to you; the result says which fields were filled. Open the checkout with open_browser first and look at it.",
|
|
28
27
|
inputSchema: z.object({
|
|
@@ -32,8 +31,6 @@ export function payOnComputerTool(options = {}) {
|
|
|
32
31
|
}),
|
|
33
32
|
approval: never(),
|
|
34
33
|
async execute(input, ctx) {
|
|
35
|
-
const { token } = await auth.getToken({});
|
|
36
|
-
const link = new Link({ accessToken: token });
|
|
37
34
|
const request = await link.spendRequests.retrieve(input.spend_request_id, { include: ["card"] });
|
|
38
35
|
if (!request)
|
|
39
36
|
throw new Error("That spend request does not exist.");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kybernesis/payments",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Stripe Link as an eve agent's wallet, on its owner's behalf: Link's tool catalog mounted as eve tools behind the owner's link-cli sign-in, the person's approval on every purchase, and a one-time card typed into a checkout on the agent's own computer without the model ever seeing it.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@stripe/link-cli": "^0.26.0",
|
|
33
|
-
"@stripe/link-integrations-eve": "^0.2.4",
|
|
34
33
|
"@stripe/link-sdk": "^0.11.0"
|
|
35
34
|
},
|
|
36
35
|
"peerDependencies": {
|