@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 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/extensions/link.ts"
22
- import { linkWallet } from "@kybernesis/payments";
23
- export default linkWallet();
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` is built against an older eve; the tools mount
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 { linkWallet } from "./extension.js";
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 { linkWallet } from "./extension.js";
4
+ export { linkTool, linkClient, sanitizeLinkOutput, LINK_TOOL_NAMES } from "./link-tools.js";
@@ -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. `link__create_spend_request` with that merchant, those line items and that total. Send the person the approval link it returns, as a plain link, and wait. Do not create a second request for the same purchase.\n3. When `link__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 `link__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";
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";
@@ -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. \`link__create_spend_request\` with that merchant, those line items and that total. Send the person the approval link it returns, as a plain link, and wait. Do not create a second request for the same purchase.
8
- 3. When \`link__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 \`link__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.
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 { type LinkCliAuthOptions } from "./link-cli-auth.js";
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" | "name" | "exp_month" | "exp_year" | "expiration" | "cvc" | "postal_code";
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" | "name" | "exp_month" | "exp_year" | "expiration" | "cvc" | "postal_code";
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;
@@ -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 { linkCliAuth } from "./link-cli-auth.js";
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 auth = linkCliAuth(options);
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.1.0",
4
- "description": "A Link wallet for an eve agent on its owner's behalf: Stripe's Link tools behind the owner's link-cli sign-in, 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.",
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": {