shopstack 0.2.4 → 0.2.5
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 -2
- package/SKILL.md +5 -0
- package/package.json +1 -1
- package/src/cli.js +79 -1
package/README.md
CHANGED
|
@@ -70,7 +70,7 @@ deliberately has no card-input or payment-approval tool.
|
|
|
70
70
|
|
|
71
71
|
The canonical agent skill ships as `SKILL.md` in this package. After
|
|
72
72
|
publication it is available at
|
|
73
|
-
`https://unpkg.com/shopstack@0.2.
|
|
73
|
+
`https://unpkg.com/shopstack@0.2.5/SKILL.md` with the release-pinned package.
|
|
74
74
|
|
|
75
75
|
## Connections
|
|
76
76
|
|
|
@@ -80,7 +80,10 @@ shopstack connect link
|
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
Link is currently the only persistent payment provider. Connecting it is
|
|
83
|
-
optional.
|
|
83
|
+
optional. `shopstack connect link` opens the HTTPS Link setup page, displays the
|
|
84
|
+
confirmation phrase, and checks the connection every five seconds for up to
|
|
85
|
+
five minutes. It prints `Link connected` when the connection is ready. If a
|
|
86
|
+
browser cannot open automatically, use the exact URL printed in the terminal.
|
|
84
87
|
|
|
85
88
|
## Run a checkout
|
|
86
89
|
|
package/SKILL.md
CHANGED
|
@@ -69,6 +69,11 @@ shopstack connect list
|
|
|
69
69
|
shopstack connect link
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
The Link command opens the HTTPS setup page, displays the confirmation phrase,
|
|
73
|
+
and checks every five seconds for up to five minutes. Continue only after it
|
|
74
|
+
prints `Link connected` and reports `checkout_ready: true`. If the browser does
|
|
75
|
+
not open automatically, open the exact URL printed in the terminal.
|
|
76
|
+
|
|
72
77
|
Include `payment_provider: "link"` only when the active user's Link connection reports checkout-ready. Otherwise omit `payment_provider`. Shopstack will run until card entry and request one protected checkout-scoped card through the SDK or no-echo CLI prompt.
|
|
73
78
|
|
|
74
79
|
Never put card data in MCP arguments, natural-language messages, model output, logs, or ordinary CLI flags.
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
1
2
|
import { readFile } from "node:fs/promises";
|
|
2
3
|
import { createInterface } from "node:readline/promises";
|
|
3
4
|
|
|
@@ -7,6 +8,8 @@ import { ConfigStore } from "./config.js";
|
|
|
7
8
|
const VERSION = JSON.parse(
|
|
8
9
|
await readFile(new URL("../package.json", import.meta.url), "utf8"),
|
|
9
10
|
).version;
|
|
11
|
+
const LINK_POLL_ATTEMPTS = 60;
|
|
12
|
+
const LINK_POLL_INTERVAL_MS = 5_000;
|
|
10
13
|
|
|
11
14
|
const HELP = `Shopstack CLI ${VERSION}
|
|
12
15
|
|
|
@@ -92,6 +95,77 @@ function writeJson(stream, value) {
|
|
|
92
95
|
stream.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
93
96
|
}
|
|
94
97
|
|
|
98
|
+
function delay(milliseconds) {
|
|
99
|
+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function openExternal(url) {
|
|
103
|
+
const parsed = new URL(url);
|
|
104
|
+
if (parsed.protocol !== "https:") {
|
|
105
|
+
throw new Error("Only HTTPS connection URLs can be opened.");
|
|
106
|
+
}
|
|
107
|
+
const [command, args] =
|
|
108
|
+
process.platform === "darwin"
|
|
109
|
+
? ["open", [url]]
|
|
110
|
+
: process.platform === "win32"
|
|
111
|
+
? ["cmd.exe", ["/d", "/s", "/c", "start", "", url]]
|
|
112
|
+
: ["xdg-open", [url]];
|
|
113
|
+
await new Promise((resolve, reject) => {
|
|
114
|
+
const child = spawn(command, args, { detached: true, stdio: "ignore" });
|
|
115
|
+
child.once("error", reject);
|
|
116
|
+
child.once("spawn", () => {
|
|
117
|
+
child.unref();
|
|
118
|
+
resolve();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function connectLink(client, dependencies) {
|
|
124
|
+
let result = await client.connect("link");
|
|
125
|
+
if (
|
|
126
|
+
result.connection_status !== "action_required" ||
|
|
127
|
+
typeof result.connect_url !== "string"
|
|
128
|
+
) {
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
dependencies.stderr.write(`Open Link: ${result.connect_url}\n`);
|
|
133
|
+
if (typeof result.phrase === "string") {
|
|
134
|
+
dependencies.stderr.write(`Confirmation phrase: ${result.phrase}\n`);
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
await dependencies.openExternal(result.connect_url);
|
|
138
|
+
} catch {
|
|
139
|
+
dependencies.stderr.write(
|
|
140
|
+
"The browser could not open automatically. Open the URL shown above.\n",
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
dependencies.stderr.write("Waiting for Link confirmation...\n");
|
|
144
|
+
|
|
145
|
+
for (let attempt = 0; attempt < dependencies.linkPollAttempts; attempt += 1) {
|
|
146
|
+
await dependencies.delay(dependencies.linkPollIntervalMs);
|
|
147
|
+
result = await client.connect("link");
|
|
148
|
+
if (
|
|
149
|
+
result.connection_status === "active" &&
|
|
150
|
+
result.checkout_ready === true
|
|
151
|
+
) {
|
|
152
|
+
dependencies.stderr.write("✓ Link connected\n");
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
if (
|
|
156
|
+
result.connection_status !== "action_required" &&
|
|
157
|
+
result.connection_status !== "connecting"
|
|
158
|
+
) {
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
dependencies.stderr.write(
|
|
164
|
+
"Link setup is still pending. Run `shopstack connect link` to resume.\n",
|
|
165
|
+
);
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
|
|
95
169
|
async function readJsonFile(path) {
|
|
96
170
|
return JSON.parse(await readFile(path, "utf8"));
|
|
97
171
|
}
|
|
@@ -266,6 +340,10 @@ export async function runCli(args, supplied = {}) {
|
|
|
266
340
|
clientFactory: (options) => new ShopstackClient(options),
|
|
267
341
|
configStore: new ConfigStore(),
|
|
268
342
|
confirm: undefined,
|
|
343
|
+
delay,
|
|
344
|
+
linkPollAttempts: LINK_POLL_ATTEMPTS,
|
|
345
|
+
linkPollIntervalMs: LINK_POLL_INTERVAL_MS,
|
|
346
|
+
openExternal,
|
|
269
347
|
prompt: undefined,
|
|
270
348
|
readJsonFile,
|
|
271
349
|
secretPrompt: undefined,
|
|
@@ -474,7 +552,7 @@ export async function runCli(args, supplied = {}) {
|
|
|
474
552
|
const result =
|
|
475
553
|
action === "list"
|
|
476
554
|
? await client.listConnections()
|
|
477
|
-
: await client
|
|
555
|
+
: await connectLink(client, dependencies);
|
|
478
556
|
writeJson(dependencies.stdout, result);
|
|
479
557
|
return;
|
|
480
558
|
}
|