@cleanslop/cli 0.0.0-stage → 0.1.0-beta.1.2
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 +86 -2
- package/assets/skill-core.md +62 -0
- package/dist/action.d.ts +5 -0
- package/dist/action.js +22 -0
- package/dist/action.js.map +1 -0
- package/dist/args.d.ts +4 -0
- package/dist/args.js +243 -0
- package/dist/args.js.map +1 -0
- package/dist/commands/credits.d.ts +29 -0
- package/dist/commands/credits.js +267 -0
- package/dist/commands/credits.js.map +1 -0
- package/dist/commands/email.d.ts +3 -0
- package/dist/commands/email.js +51 -0
- package/dist/commands/email.js.map +1 -0
- package/dist/commands/link-identity.d.ts +3 -0
- package/dist/commands/link-identity.js +37 -0
- package/dist/commands/link-identity.js.map +1 -0
- package/dist/commands/link-login.d.ts +3 -0
- package/dist/commands/link-login.js +63 -0
- package/dist/commands/link-login.js.map +1 -0
- package/dist/commands/login.d.ts +6 -0
- package/dist/commands/login.js +198 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +2 -0
- package/dist/commands/logout.js +40 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/report.d.ts +8 -0
- package/dist/commands/report.js +55 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/scan-upload.d.ts +3 -0
- package/dist/commands/scan-upload.js +85 -0
- package/dist/commands/scan-upload.js.map +1 -0
- package/dist/commands/scan.d.ts +3 -0
- package/dist/commands/scan.js +81 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/setup.d.ts +19 -0
- package/dist/commands/setup.js +154 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.js +29 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.js +44 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.js +46 -0
- package/dist/config.js.map +1 -0
- package/dist/credentials.d.ts +64 -0
- package/dist/credentials.js +220 -0
- package/dist/credentials.js.map +1 -0
- package/dist/deps.d.ts +58 -0
- package/dist/deps.js +148 -0
- package/dist/deps.js.map +1 -0
- package/dist/exit.d.ts +24 -0
- package/dist/exit.js +29 -0
- package/dist/exit.js.map +1 -0
- package/dist/git.d.ts +14 -0
- package/dist/git.js +161 -0
- package/dist/git.js.map +1 -0
- package/dist/http.d.ts +16 -0
- package/dist/http.js +210 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/link.d.ts +106 -0
- package/dist/link.js +650 -0
- package/dist/link.js.map +1 -0
- package/dist/main.d.ts +6 -0
- package/dist/main.js +75 -0
- package/dist/main.js.map +1 -0
- package/dist/mcp-config.d.ts +13 -0
- package/dist/mcp-config.js +65 -0
- package/dist/mcp-config.js.map +1 -0
- package/dist/output.d.ts +9 -0
- package/dist/output.js +65 -0
- package/dist/output.js.map +1 -0
- package/dist/pack.d.ts +30 -0
- package/dist/pack.js +283 -0
- package/dist/pack.js.map +1 -0
- package/dist/redact.d.ts +2 -0
- package/dist/redact.js +17 -0
- package/dist/redact.js.map +1 -0
- package/dist/skill.d.ts +10 -0
- package/dist/skill.js +110 -0
- package/dist/skill.js.map +1 -0
- package/dist/types.d.ts +144 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ustar.d.ts +7 -0
- package/dist/ustar.js +128 -0
- package/dist/ustar.js.map +1 -0
- package/dist/wait.d.ts +11 -0
- package/dist/wait.js +80 -0
- package/dist/wait.js.map +1 -0
- package/package.json +30 -4
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { writeAction } from "../action.js";
|
|
2
|
+
import { asRecord, httpRequest, requireOk } from "../http.js";
|
|
3
|
+
import { createLinkSpendRequest, ensureLinkPaymentScope, retrieveLinkSpendRequest, retrieveSharedPaymentToken, } from "../link.js";
|
|
4
|
+
import { deletePendingSpend, readPendingSpend, requireToken, resolveOrigin, writePendingSpend, } from "../credentials.js";
|
|
5
|
+
import { actionError, CliError, EXIT_OK, EXIT_PAYMENT, usageError, } from "../exit.js";
|
|
6
|
+
const CREDIT_PACKS = {
|
|
7
|
+
p5: 5,
|
|
8
|
+
p15: 15,
|
|
9
|
+
p40: 40,
|
|
10
|
+
};
|
|
11
|
+
function isCreditPackId(value) {
|
|
12
|
+
return value === "p5" || value === "p15" || value === "p40";
|
|
13
|
+
}
|
|
14
|
+
function spendRequestContext(pack, scans) {
|
|
15
|
+
const text = `CleanSlop ${scans} scan credits (pack ${pack}). Approve this Shared Payment Token so your coding agent can add credits to this CleanSlop account. This is a one-time charge for scan credits only.`;
|
|
16
|
+
return text.length >= 100 ? text : text.padEnd(100, ".");
|
|
17
|
+
}
|
|
18
|
+
/** Fixed Link approval budget. Auto-buy ignores `scan --wait`. */
|
|
19
|
+
export const LINK_APPROVAL_WAIT_MS = 10 * 60 * 1000;
|
|
20
|
+
export function linkApprovalWaitMs(args, opts = {}) {
|
|
21
|
+
if (opts.autoBuy)
|
|
22
|
+
return LINK_APPROVAL_WAIT_MS;
|
|
23
|
+
return args.wait ? args.waitMs : LINK_APPROVAL_WAIT_MS;
|
|
24
|
+
}
|
|
25
|
+
function purchaseUrlFor(origin) {
|
|
26
|
+
return `${origin}/api/agent/v1/credits/purchases`;
|
|
27
|
+
}
|
|
28
|
+
function asStripeSptOffer(value) {
|
|
29
|
+
const rec = asRecord(value);
|
|
30
|
+
if (!rec || rec.kind !== "stripe_spt")
|
|
31
|
+
return null;
|
|
32
|
+
const pack = typeof rec.pack === "string" ? rec.pack : "";
|
|
33
|
+
if (!isCreditPackId(pack))
|
|
34
|
+
return null;
|
|
35
|
+
const amount = typeof rec.amount === "number" ? rec.amount : Number(rec.amount);
|
|
36
|
+
if (!Number.isInteger(amount) || amount < 1)
|
|
37
|
+
return null;
|
|
38
|
+
const networkId = typeof rec.networkId === "string" ? rec.networkId.trim() : "";
|
|
39
|
+
const purchaseUrl = typeof rec.purchaseUrl === "string" ? rec.purchaseUrl.trim() : "";
|
|
40
|
+
if (!networkId || !purchaseUrl)
|
|
41
|
+
return null;
|
|
42
|
+
return {
|
|
43
|
+
pack,
|
|
44
|
+
amount,
|
|
45
|
+
currency: typeof rec.currency === "string" && rec.currency.trim()
|
|
46
|
+
? rec.currency.trim()
|
|
47
|
+
: "usd",
|
|
48
|
+
networkId,
|
|
49
|
+
purchaseUrl,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** Read a matching `stripe_spt` offer from a 402 `out_of_scans` body. */
|
|
53
|
+
export function stripeSptOfferFromErrorBody(json, packHint) {
|
|
54
|
+
const payment = asRecord(asRecord(json)?.payment);
|
|
55
|
+
const methods = Array.isArray(payment?.methods) ? payment.methods : [];
|
|
56
|
+
const offers = methods
|
|
57
|
+
.map(asStripeSptOffer)
|
|
58
|
+
.filter((offer) => offer != null);
|
|
59
|
+
if (offers.length === 0)
|
|
60
|
+
return null;
|
|
61
|
+
const wanted = packHint && isCreditPackId(packHint) ? packHint : "p5";
|
|
62
|
+
return offers.find((offer) => offer.pack === wanted) ?? offers[0] ?? null;
|
|
63
|
+
}
|
|
64
|
+
function tokenMissingAction(spendRequestId) {
|
|
65
|
+
throw actionError("The Link payment token is not ready yet. Retry the same spend request.", {
|
|
66
|
+
kind: "wait",
|
|
67
|
+
humanPrompt: "The person already approved this payment in Link, but the token is not ready. Run `cleanslop credits buy --link --resume` — do not create a new spend request.",
|
|
68
|
+
code: spendRequestId,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
async function persistPending(deps, pending) {
|
|
72
|
+
await writePendingSpend(deps, pending);
|
|
73
|
+
}
|
|
74
|
+
async function pollUntilApproved(deps, pending, waitMs) {
|
|
75
|
+
const deadline = deps.clock.now() + waitMs;
|
|
76
|
+
while (deps.clock.now() < deadline) {
|
|
77
|
+
const snap = await retrieveLinkSpendRequest(deps, pending.spendRequestId);
|
|
78
|
+
switch (snap.status) {
|
|
79
|
+
case "approved":
|
|
80
|
+
return;
|
|
81
|
+
case "denied":
|
|
82
|
+
case "expired":
|
|
83
|
+
case "canceled":
|
|
84
|
+
deletePendingSpend(deps);
|
|
85
|
+
throw actionError(`The Link spend request was ${snap.status}.`, {
|
|
86
|
+
kind: "ask_human",
|
|
87
|
+
humanPrompt: `The Link payment was ${snap.status}. Ask the person to approve a new spend request, then retry.`,
|
|
88
|
+
});
|
|
89
|
+
case "requires_action":
|
|
90
|
+
if (snap.resolution === "auto_resume") {
|
|
91
|
+
await deps.clock.sleep(2000);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
deletePendingSpend(deps);
|
|
95
|
+
throw actionError(snap.displayMessage ?? "This spend request needs another approval step.", {
|
|
96
|
+
kind: "ask_human",
|
|
97
|
+
humanPrompt: snap.displayMessage ??
|
|
98
|
+
"Link asked for an extra approval step that CleanSlop cannot resume. Start a new spend request.",
|
|
99
|
+
});
|
|
100
|
+
case "pending":
|
|
101
|
+
case "unknown":
|
|
102
|
+
await deps.clock.sleep(2000);
|
|
103
|
+
break;
|
|
104
|
+
default: {
|
|
105
|
+
const _exhaustive = snap.status;
|
|
106
|
+
throw _exhaustive;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
throw actionError("Timed out waiting for Link payment approval.", {
|
|
111
|
+
kind: "ask_human",
|
|
112
|
+
humanPrompt: "The person has not approved the Link payment yet. Run `cleanslop credits buy --link --resume` after they approve it.",
|
|
113
|
+
code: pending.spendRequestId,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
async function postPurchase(deps, origin, pending, token, sharedPaymentToken) {
|
|
117
|
+
const result = await httpRequest(deps, origin, "POST", "/api/agent/v1/credits/purchases", {
|
|
118
|
+
token,
|
|
119
|
+
body: {
|
|
120
|
+
pack: pending.pack,
|
|
121
|
+
sharedPaymentToken,
|
|
122
|
+
spendRequestId: pending.spendRequestId,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
try {
|
|
126
|
+
requireOk(result);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
if (err instanceof CliError && err.exitCode === EXIT_PAYMENT) {
|
|
130
|
+
deletePendingSpend(deps);
|
|
131
|
+
}
|
|
132
|
+
throw err;
|
|
133
|
+
}
|
|
134
|
+
const rec = asRecord(result.json);
|
|
135
|
+
const credits = typeof rec?.credits === "number" ? rec.credits : 0;
|
|
136
|
+
const pack = typeof rec?.pack === "string" ? rec.pack : pending.pack;
|
|
137
|
+
const paymentIntentId = typeof rec?.paymentIntentId === "string" ? rec.paymentIntentId : null;
|
|
138
|
+
return { credits, pack, paymentIntentId };
|
|
139
|
+
}
|
|
140
|
+
export async function buyLinkCredits(deps, args, offer = null, opts = {}) {
|
|
141
|
+
const origin = resolveOrigin(deps);
|
|
142
|
+
const stored = requireToken(deps, origin);
|
|
143
|
+
const storedPending = readPendingSpend(deps);
|
|
144
|
+
const existing = storedPending && storedPending.origin === origin ? storedPending : null;
|
|
145
|
+
if (args.resume && storedPending && !existing && !args.spendRequestId?.trim()) {
|
|
146
|
+
throw actionError("Pending Link spend request is for another origin.", {
|
|
147
|
+
kind: "ask_human",
|
|
148
|
+
humanPrompt: `A pending Link spend request is for ${storedPending.origin}, but this CLI is using ${origin}. Drop --resume to start a new spend request, or set CLEANSLOP_ORIGIN back to ${storedPending.origin}.`,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
const resumeId = args.spendRequestId?.trim() || existing?.spendRequestId || null;
|
|
152
|
+
if (args.resume && !resumeId) {
|
|
153
|
+
throw actionError("No pending Link spend request to resume.", {
|
|
154
|
+
kind: "ask_human",
|
|
155
|
+
humanPrompt: "There is no pending spend request. Run `cleanslop credits buy --link --pack p5` after a scan 402, or resume the saved spend request.",
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
let pending;
|
|
159
|
+
if (resumeId) {
|
|
160
|
+
const fromStore = existing && existing.spendRequestId === resumeId ? existing : null;
|
|
161
|
+
pending = {
|
|
162
|
+
version: 1,
|
|
163
|
+
origin,
|
|
164
|
+
spendRequestId: resumeId,
|
|
165
|
+
pack: isCreditPackId(args.pack)
|
|
166
|
+
? args.pack
|
|
167
|
+
: fromStore?.pack ?? offer?.pack ?? "p5",
|
|
168
|
+
amount: args.amount ?? fromStore?.amount ?? offer?.amount ?? 0,
|
|
169
|
+
currency: fromStore?.currency ?? offer?.currency ?? "usd",
|
|
170
|
+
networkId: args.networkId?.trim() ||
|
|
171
|
+
fromStore?.networkId ||
|
|
172
|
+
deps.env.get("CLEANSLOP_STRIPE_PROFILE_ID")?.trim() ||
|
|
173
|
+
offer?.networkId ||
|
|
174
|
+
"",
|
|
175
|
+
purchaseUrl: purchaseUrlFor(origin),
|
|
176
|
+
createdAt: fromStore?.createdAt ?? deps.clock.now(),
|
|
177
|
+
};
|
|
178
|
+
if (!pending.amount || !pending.networkId) {
|
|
179
|
+
throw usageError("Resuming a spend request still needs the saved pack price and network id.");
|
|
180
|
+
}
|
|
181
|
+
await persistPending(deps, pending);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
const pack = isCreditPackId(args.pack)
|
|
185
|
+
? args.pack
|
|
186
|
+
: offer?.pack ?? "p5";
|
|
187
|
+
const amount = args.amount ?? offer?.amount ?? null;
|
|
188
|
+
const networkId = args.networkId?.trim() ||
|
|
189
|
+
deps.env.get("CLEANSLOP_STRIPE_PROFILE_ID")?.trim() ||
|
|
190
|
+
offer?.networkId ||
|
|
191
|
+
"";
|
|
192
|
+
if (!amount) {
|
|
193
|
+
throw usageError("credits buy --link needs a 402 stripe_spt offer (from scan) or a test --amount");
|
|
194
|
+
}
|
|
195
|
+
if (!networkId) {
|
|
196
|
+
throw usageError("credits buy --link needs a 402 stripe_spt networkId or CLEANSLOP_STRIPE_PROFILE_ID");
|
|
197
|
+
}
|
|
198
|
+
const scans = CREDIT_PACKS[pack];
|
|
199
|
+
const currency = offer?.currency ?? "usd";
|
|
200
|
+
await ensureLinkPaymentScope(deps);
|
|
201
|
+
const created = await createLinkSpendRequest(deps, {
|
|
202
|
+
networkId,
|
|
203
|
+
amount,
|
|
204
|
+
currency,
|
|
205
|
+
context: spendRequestContext(pack, scans),
|
|
206
|
+
lineItem: `name:CleanSlop ${scans} scan credits,unit_amount:${amount},quantity:1`,
|
|
207
|
+
total: `type:total,display_text:Total,amount:${amount}`,
|
|
208
|
+
idempotencyKey: deps.randomId(),
|
|
209
|
+
});
|
|
210
|
+
pending = {
|
|
211
|
+
version: 1,
|
|
212
|
+
origin,
|
|
213
|
+
spendRequestId: created.id,
|
|
214
|
+
pack,
|
|
215
|
+
amount,
|
|
216
|
+
currency,
|
|
217
|
+
networkId,
|
|
218
|
+
purchaseUrl: purchaseUrlFor(origin),
|
|
219
|
+
createdAt: deps.clock.now(),
|
|
220
|
+
};
|
|
221
|
+
await persistPending(deps, pending);
|
|
222
|
+
const packLine = `Approve this CleanSlop credit pack in your Link app (${pack}, ${amount} usd).`;
|
|
223
|
+
if (created.approvalUrl) {
|
|
224
|
+
writeAction(deps, {
|
|
225
|
+
kind: "approve",
|
|
226
|
+
humanPrompt: `Ask the human to open this link and approve this CleanSlop credit pack (${pack}, ${amount} usd). Link may also send a notification.`,
|
|
227
|
+
url: created.approvalUrl,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
deps.io.stderr(`${packLine}\n`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const waitMs = linkApprovalWaitMs(args, opts);
|
|
235
|
+
await pollUntilApproved(deps, pending, waitMs);
|
|
236
|
+
const sharedPaymentToken = await retrieveSharedPaymentToken(deps, pending.spendRequestId);
|
|
237
|
+
if (!sharedPaymentToken) {
|
|
238
|
+
tokenMissingAction(pending.spendRequestId);
|
|
239
|
+
}
|
|
240
|
+
const paid = await postPurchase(deps, origin, pending, stored.token, sharedPaymentToken);
|
|
241
|
+
deletePendingSpend(deps);
|
|
242
|
+
deps.io.stdout(`Added ${paid.pack} scan credits. Balance: ${paid.credits}.\n`);
|
|
243
|
+
return EXIT_OK;
|
|
244
|
+
}
|
|
245
|
+
export async function runCredits(deps, args) {
|
|
246
|
+
if (args.id && args.id !== "buy") {
|
|
247
|
+
throw usageError("Usage: cleanslop credits buy --link");
|
|
248
|
+
}
|
|
249
|
+
if (args.id !== "buy") {
|
|
250
|
+
throw usageError("Usage: cleanslop credits buy --link");
|
|
251
|
+
}
|
|
252
|
+
if (!args.link) {
|
|
253
|
+
throw usageError("credits buy requires --link");
|
|
254
|
+
}
|
|
255
|
+
return buyLinkCredits(deps, args);
|
|
256
|
+
}
|
|
257
|
+
/** If a scan 402 offers `stripe_spt`, buy that pack and retry the scan once. */
|
|
258
|
+
export async function recoverOutOfScansIfOffered(deps, args, result, retry) {
|
|
259
|
+
if (result.status !== 402)
|
|
260
|
+
return result;
|
|
261
|
+
const offer = stripeSptOfferFromErrorBody(result.json, args.pack);
|
|
262
|
+
if (!offer)
|
|
263
|
+
return result;
|
|
264
|
+
await buyLinkCredits(deps, args, offer, { autoBuy: true });
|
|
265
|
+
return retry();
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=credits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credits.js","sourceRoot":"","sources":["../../src/commands/credits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { requireToken, resolveOrigin, peekStoredCreds } from "../credentials.js";
|
|
2
|
+
import { CliError, EXIT_ACTION, EXIT_OK, usageError } from "../exit.js";
|
|
3
|
+
import { httpRequest, requireOk } from "../http.js";
|
|
4
|
+
import { writeJson } from "../output.js";
|
|
5
|
+
function resolveScanId(deps, origin, id) {
|
|
6
|
+
if (id)
|
|
7
|
+
return id;
|
|
8
|
+
const stored = peekStoredCreds(deps, origin);
|
|
9
|
+
if (stored?.lastScanId)
|
|
10
|
+
return stored.lastScanId;
|
|
11
|
+
throw usageError("Pass a scan id or run a scan first.");
|
|
12
|
+
}
|
|
13
|
+
export async function runEmail(deps, args) {
|
|
14
|
+
const origin = resolveOrigin(deps);
|
|
15
|
+
const creds = requireToken(deps, origin);
|
|
16
|
+
const scanId = resolveScanId(deps, origin, args.id);
|
|
17
|
+
if (!args.consent) {
|
|
18
|
+
const preview = await httpRequest(deps, origin, "GET", `/api/agent/v1/scans/${encodeURIComponent(scanId)}/email`, { token: creds.token });
|
|
19
|
+
requireOk(preview);
|
|
20
|
+
const body = (preview.json ?? {});
|
|
21
|
+
if (args.json) {
|
|
22
|
+
writeJson(deps, body);
|
|
23
|
+
return EXIT_OK;
|
|
24
|
+
}
|
|
25
|
+
const prompt = body.prompt ?? "Ask the human the exact masked-recipient question.";
|
|
26
|
+
deps.io.stdout(`${prompt}\n`);
|
|
27
|
+
throw new CliError("Ask the human the exact question above. If they agree, rerun with --consent quoting it.", EXIT_ACTION, {
|
|
28
|
+
kind: "ask_human",
|
|
29
|
+
humanPrompt: prompt,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const result = await httpRequest(deps, origin, "POST", `/api/agent/v1/scans/${encodeURIComponent(scanId)}/email`, {
|
|
33
|
+
token: creds.token,
|
|
34
|
+
body: {
|
|
35
|
+
decision: "granted",
|
|
36
|
+
promptText: args.consent,
|
|
37
|
+
...(args.reply ? { humanReply: args.reply } : {}),
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
requireOk(result);
|
|
41
|
+
if (args.json) {
|
|
42
|
+
writeJson(deps, result.json);
|
|
43
|
+
return EXIT_OK;
|
|
44
|
+
}
|
|
45
|
+
const body = (result.json ?? {});
|
|
46
|
+
const masked = body.recipientMasked ?? "the verified address";
|
|
47
|
+
const when = body.sends === "now" ? "now" : "when the scan finishes";
|
|
48
|
+
deps.io.stdout(`Email consent recorded for ${masked}. CleanSlop will send ${when}.\n`);
|
|
49
|
+
return EXIT_OK;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=email.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email.js","sourceRoot":"","sources":["../../src/commands/email.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { requireToken, resolveOrigin } from "../credentials.js";
|
|
2
|
+
import { CliError, EXIT_OK, EXIT_UNEXPECTED } from "../exit.js";
|
|
3
|
+
import { asRecord, hasIdentityPresentationChallenge, httpRequest, requireOk, } from "../http.js";
|
|
4
|
+
import { ensureLinkAuth, linkAuthMode, presentLinkIdentity, readLinkClaimsChallenge, requireLinkBridgeConsent, } from "../link.js";
|
|
5
|
+
export async function runLinkIdentity(deps, args) {
|
|
6
|
+
const authMode = linkAuthMode(args);
|
|
7
|
+
const origin = resolveOrigin(deps);
|
|
8
|
+
const creds = requireToken(deps, origin);
|
|
9
|
+
const consentSource = await requireLinkBridgeConsent(deps, args, origin);
|
|
10
|
+
await ensureLinkAuth(deps, {
|
|
11
|
+
mode: authMode,
|
|
12
|
+
command: "cleanslop link-identity",
|
|
13
|
+
});
|
|
14
|
+
const started = await httpRequest(deps, origin, "POST", "/api/agent/v1/identity/link", { token: creds.token, body: { consentSource } });
|
|
15
|
+
if (!hasIdentityPresentationChallenge(started)) {
|
|
16
|
+
requireOk(started);
|
|
17
|
+
throw new CliError("Link bridge did not return a claims challenge.", EXIT_UNEXPECTED);
|
|
18
|
+
}
|
|
19
|
+
const challenge = readLinkClaimsChallenge(started.json, origin);
|
|
20
|
+
const presented = await presentLinkIdentity(deps, {
|
|
21
|
+
aud: challenge.aud,
|
|
22
|
+
nonce: challenge.nonce,
|
|
23
|
+
});
|
|
24
|
+
const completed = await httpRequest(deps, origin, "POST", "/api/agent/v1/identity/link", {
|
|
25
|
+
token: creds.token,
|
|
26
|
+
headers: {
|
|
27
|
+
"Identity-Presentation": presented.presentation,
|
|
28
|
+
"CleanSlop-Interaction": challenge.interactionId,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
requireOk(completed);
|
|
32
|
+
const rec = asRecord(completed.json);
|
|
33
|
+
const emailMasked = rec && typeof rec.emailMasked === "string" ? rec.emailMasked : "your Link email";
|
|
34
|
+
deps.io.stdout(`Linked ${emailMasked} to this account.\n`);
|
|
35
|
+
return EXIT_OK;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=link-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-identity.js","sourceRoot":"","sources":["../../src/commands/link-identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEhE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EACL,QAAQ,EACR,gCAAgC,EAChC,WAAW,EACX,SAAS,GACV,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AAGpB,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAa,EACb,IAAgB;IAEhB,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACzC,MAAM,aAAa,GAAG,MAAM,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACzE,MAAM,cAAc,CAAC,IAAI,EAAE;QACzB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,yBAAyB;KACnC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,MAAM,WAAW,CAC/B,IAAI,EACJ,MAAM,EACN,MAAM,EACN,6BAA6B,EAC7B,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,EAAE,CAChD,CAAC;IACF,IAAI,CAAC,gCAAgC,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/C,SAAS,CAAC,OAAO,CAAC,CAAC;QACnB,MAAM,IAAI,QAAQ,CAAC,gDAAgD,EAAE,eAAe,CAAC,CAAC;IACxF,CAAC;IACD,MAAM,SAAS,GAAG,uBAAuB,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChE,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,IAAI,EAAE;QAChD,GAAG,EAAE,SAAS,CAAC,GAAG;QAClB,KAAK,EAAE,SAAS,CAAC,KAAK;KACvB,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,MAAM,WAAW,CACjC,IAAI,EACJ,MAAM,EACN,MAAM,EACN,6BAA6B,EAC7B;QACE,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,OAAO,EAAE;YACP,uBAAuB,EAAE,SAAS,CAAC,YAAY;YAC/C,uBAAuB,EAAE,SAAS,CAAC,aAAa;SACjD;KACF,CACF,CAAC;IACF,SAAS,CAAC,SAAS,CAAC,CAAC;IACrB,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,WAAW,GACf,GAAG,IAAI,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,iBAAiB,CAAC;IACnF,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,WAAW,qBAAqB,CAAC,CAAC;IAC3D,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { CLIENT_ID, TERMS_UPDATED_ON } from "../config.js";
|
|
2
|
+
import { resolveOrigin, storeToken } from "../credentials.js";
|
|
3
|
+
import { CliError, EXIT_OK, EXIT_POLICY, EXIT_UNEXPECTED } from "../exit.js";
|
|
4
|
+
import { asErrorBody, hasIdentityPresentationChallenge, httpRequest, throwHttpError, } from "../http.js";
|
|
5
|
+
import { ensureLinkAuth, linkAuthMode, linkSignupBody, popAttestation, presentLinkIdentity, readLinkClaimsChallenge, requireLinkSignupConsent, } from "../link.js";
|
|
6
|
+
export async function runLinkLogin(deps, args) {
|
|
7
|
+
const authMode = linkAuthMode(args);
|
|
8
|
+
const origin = resolveOrigin(deps);
|
|
9
|
+
const consentSource = await requireLinkSignupConsent(deps, args, origin);
|
|
10
|
+
await ensureLinkAuth(deps, { mode: authMode });
|
|
11
|
+
const attestation = await popAttestation(deps);
|
|
12
|
+
const started = await httpRequest(deps, origin, "POST", "/oauth/link", {
|
|
13
|
+
headers: { Authorization: attestation.authorization },
|
|
14
|
+
body: linkSignupBody(deps, TERMS_UPDATED_ON, consentSource),
|
|
15
|
+
});
|
|
16
|
+
if (!hasIdentityPresentationChallenge(started)) {
|
|
17
|
+
throwHttpError(started);
|
|
18
|
+
}
|
|
19
|
+
const challenge = readLinkClaimsChallenge(started.json, origin);
|
|
20
|
+
const presented = await presentLinkIdentity(deps, {
|
|
21
|
+
aud: challenge.aud,
|
|
22
|
+
nonce: challenge.nonce,
|
|
23
|
+
});
|
|
24
|
+
const completed = await httpRequest(deps, origin, "POST", "/oauth/link", {
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: attestation.authorization,
|
|
27
|
+
"Identity-Presentation": presented.presentation,
|
|
28
|
+
"CleanSlop-Interaction": challenge.interactionId,
|
|
29
|
+
},
|
|
30
|
+
body: {
|
|
31
|
+
client: CLIENT_ID,
|
|
32
|
+
acceptTerms: TERMS_UPDATED_ON,
|
|
33
|
+
consentSource,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const body = asErrorBody(completed.json);
|
|
37
|
+
if (completed.status >= 400) {
|
|
38
|
+
if (body.error === "link_pilot_required") {
|
|
39
|
+
throw new CliError("Link pilot access required.", EXIT_POLICY, {
|
|
40
|
+
kind: "beta",
|
|
41
|
+
humanPrompt: "This Link email is not in the CleanSlop Link pilot yet. Ask the CleanSlop team for access, then run `cleanslop login --link` again.",
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
throwHttpError(completed);
|
|
45
|
+
}
|
|
46
|
+
const issued = completed.json;
|
|
47
|
+
if (!issued || typeof issued.access_token !== "string") {
|
|
48
|
+
throw new CliError("Link login response was missing access_token.", EXIT_UNEXPECTED);
|
|
49
|
+
}
|
|
50
|
+
const account = issued.account;
|
|
51
|
+
const emailMasked = (typeof account?.emailMasked === "string" && account.emailMasked) ||
|
|
52
|
+
(typeof account?.email_masked === "string" && account.email_masked) ||
|
|
53
|
+
null;
|
|
54
|
+
await storeToken(deps, origin, {
|
|
55
|
+
token: issued.access_token,
|
|
56
|
+
githubLogin: issued.account?.github_login ?? null,
|
|
57
|
+
grantId: issued.grant_id ?? null,
|
|
58
|
+
});
|
|
59
|
+
const label = emailMasked || "your Link email";
|
|
60
|
+
deps.io.stdout(`Connected as ${label} (Link)\n`);
|
|
61
|
+
return EXIT_OK;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=link-login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-login.js","sourceRoot":"","sources":["../../src/commands/link-login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EACL,WAAW,EACX,gCAAgC,EAChC,WAAW,EACX,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,cAAc,EACd,YAAY,EACZ,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AAGpB,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAa,EACb,IAAgB;IAEhB,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,aAAa,GAAG,MAAM,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACzE,MAAM,cAAc,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IAE/C,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE;QACrE,OAAO,EAAE,EAAE,aAAa,EAAE,WAAW,CAAC,aAAa,EAAE;QACrD,IAAI,EAAE,cAAc,CAAC,IAAI,EAAE,gBAAgB,EAAE,aAAa,CAAC;KAC5D,CAAC,CAAC;IACH,IAAI,CAAC,gCAAgC,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/C,cAAc,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;IACD,MAAM,SAAS,GAAG,uBAAuB,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChE,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,IAAI,EAAE;QAChD,GAAG,EAAE,SAAS,CAAC,GAAG;QAClB,KAAK,EAAE,SAAS,CAAC,KAAK;KACvB,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE;QACvE,OAAO,EAAE;YACP,aAAa,EAAE,WAAW,CAAC,aAAa;YACxC,uBAAuB,EAAE,SAAS,CAAC,YAAY;YAC/C,uBAAuB,EAAE,SAAS,CAAC,aAAa;SACjD;QACD,IAAI,EAAE;YACJ,MAAM,EAAE,SAAS;YACjB,WAAW,EAAE,gBAAgB;YAC7B,aAAa;SACd;KACF,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,SAAS,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,KAAK,KAAK,qBAAqB,EAAE,CAAC;YACzC,MAAM,IAAI,QAAQ,CAAC,6BAA6B,EAAE,WAAW,EAAE;gBAC7D,IAAI,EAAE,MAAM;gBACZ,WAAW,EACT,qIAAqI;aACxI,CAAC,CAAC;QACL,CAAC;QACD,cAAc,CAAC,SAAS,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,MAAM,GAAG,SAAS,CAAC,IAAkC,CAAC;IAC5D,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;QACvD,MAAM,IAAI,QAAQ,CAAC,+CAA+C,EAAE,eAAe,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAEV,CAAC;IACd,MAAM,WAAW,GACf,CAAC,OAAO,OAAO,EAAE,WAAW,KAAK,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC;QACjE,CAAC,OAAO,OAAO,EAAE,YAAY,KAAK,QAAQ,IAAI,OAAO,CAAC,YAAY,CAAC;QACnE,IAAI,CAAC;IACP,MAAM,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE;QAC7B,KAAK,EAAE,MAAM,CAAC,YAAY;QAC1B,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,YAAY,IAAI,IAAI;QACjD,OAAO,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;KACjC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,WAAW,IAAI,iBAAiB,CAAC;IAC/C,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,gBAAgB,KAAK,WAAW,CAAC,CAAC;IACjD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CliDeps } from "../deps.js";
|
|
2
|
+
import type { ParsedArgs } from "../types.js";
|
|
3
|
+
/** Matches server DEVICE_EXTEND_TTL_MS — first /connect view extends the code. */
|
|
4
|
+
export declare const DEVICE_POLL_GRACE_MS: number;
|
|
5
|
+
export declare function devicePollDeadline(expiresAt: number): number;
|
|
6
|
+
export declare function runLogin(deps: CliDeps, args: ParsedArgs): Promise<number>;
|