@amdahl/cli 0.3.1 → 0.3.3
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 +11 -4
- package/dist/amdahl.js +243 -71
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,6 +68,7 @@ Set up in:
|
|
|
68
68
|
[ ] Codex
|
|
69
69
|
(Use the arrow keys, Space to tick or untick, then Enter)
|
|
70
70
|
Opening your browser…
|
|
71
|
+
Browser didn't open? Press Enter for the link.
|
|
71
72
|
✓ Signed in · Acme
|
|
72
73
|
✓ Added to Claude Code
|
|
73
74
|
Try it: in Claude Code, run /mcp once to connect, then say "make this email sound less like AI"
|
|
@@ -76,10 +77,16 @@ Try it: in Claude Code, run /mcp once to connect, then say "make this email soun
|
|
|
76
77
|
It finds Claude Code, Cursor and Codex by their command on your PATH
|
|
77
78
|
(`claude`, `cursor`, `codex`) or their folder in your home folder (`.claude`,
|
|
78
79
|
`.cursor`, `.codex`), and ticks the ones it finds. Enter accepts. If you are
|
|
79
|
-
not signed in, it signs you in through the browser first.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
not signed in, it signs you in through the browser first. Under "Opening
|
|
81
|
+
your browser…" it prints one short line. In a terminal that shows links
|
|
82
|
+
(iTerm2, VS Code, Warp, Terminal, WezTerm, Ghostty, Windows Terminal, VTE 0.50
|
|
83
|
+
or later) it reads "Browser didn't open? Open the sign-in page" and the last
|
|
84
|
+
words are a link; elsewhere it says to press Enter for the link.
|
|
85
|
+
`FORCE_HYPERLINK=1` or `0` overrides the guess, and `NO_COLOR` turns the link
|
|
86
|
+
off. Either way, Enter prints the full sign-in link once. If the browser
|
|
87
|
+
could not be opened, or with `--no-browser`, the full link prints at once.
|
|
88
|
+
It waits up to 15 minutes, so someone new can create their workspace on the
|
|
89
|
+
way and land back in the same setup. If the server
|
|
83
90
|
rejects a key set in
|
|
84
91
|
`AMDAHL_KEY` (or `AMDAHL_API_KEY`, `AMDAHL_ACCESS_TOKEN`, `--api-key`), it says
|
|
85
92
|
so and skips the browser sign-in, since that key would still win. Then it
|
package/dist/amdahl.js
CHANGED
|
@@ -1000,14 +1000,14 @@ var require_foldFlowLines = __commonJS({
|
|
|
1000
1000
|
var FOLD_FLOW = "flow";
|
|
1001
1001
|
var FOLD_BLOCK = "block";
|
|
1002
1002
|
var FOLD_QUOTED = "quoted";
|
|
1003
|
-
function foldFlowLines(
|
|
1003
|
+
function foldFlowLines(text2, indent, mode = "flow", { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) {
|
|
1004
1004
|
if (!lineWidth || lineWidth < 0)
|
|
1005
|
-
return
|
|
1005
|
+
return text2;
|
|
1006
1006
|
if (lineWidth < minContentWidth)
|
|
1007
1007
|
minContentWidth = 0;
|
|
1008
1008
|
const endStep = Math.max(1 + minContentWidth, 1 + lineWidth - indent.length);
|
|
1009
|
-
if (
|
|
1010
|
-
return
|
|
1009
|
+
if (text2.length <= endStep)
|
|
1010
|
+
return text2;
|
|
1011
1011
|
const folds = [];
|
|
1012
1012
|
const escapedFolds = {};
|
|
1013
1013
|
let end = lineWidth - indent.length;
|
|
@@ -1024,14 +1024,14 @@ var require_foldFlowLines = __commonJS({
|
|
|
1024
1024
|
let escStart = -1;
|
|
1025
1025
|
let escEnd = -1;
|
|
1026
1026
|
if (mode === FOLD_BLOCK) {
|
|
1027
|
-
i = consumeMoreIndentedLines(
|
|
1027
|
+
i = consumeMoreIndentedLines(text2, i, indent.length);
|
|
1028
1028
|
if (i !== -1)
|
|
1029
1029
|
end = i + endStep;
|
|
1030
1030
|
}
|
|
1031
|
-
for (let ch; ch =
|
|
1031
|
+
for (let ch; ch = text2[i += 1]; ) {
|
|
1032
1032
|
if (mode === FOLD_QUOTED && ch === "\\") {
|
|
1033
1033
|
escStart = i;
|
|
1034
|
-
switch (
|
|
1034
|
+
switch (text2[i + 1]) {
|
|
1035
1035
|
case "x":
|
|
1036
1036
|
i += 3;
|
|
1037
1037
|
break;
|
|
@@ -1048,12 +1048,12 @@ var require_foldFlowLines = __commonJS({
|
|
|
1048
1048
|
}
|
|
1049
1049
|
if (ch === "\n") {
|
|
1050
1050
|
if (mode === FOLD_BLOCK)
|
|
1051
|
-
i = consumeMoreIndentedLines(
|
|
1051
|
+
i = consumeMoreIndentedLines(text2, i, indent.length);
|
|
1052
1052
|
end = i + indent.length + endStep;
|
|
1053
1053
|
split = void 0;
|
|
1054
1054
|
} else {
|
|
1055
1055
|
if (ch === " " && prev && prev !== " " && prev !== "\n" && prev !== " ") {
|
|
1056
|
-
const next =
|
|
1056
|
+
const next = text2[i + 1];
|
|
1057
1057
|
if (next && next !== " " && next !== "\n" && next !== " ")
|
|
1058
1058
|
split = i;
|
|
1059
1059
|
}
|
|
@@ -1065,12 +1065,12 @@ var require_foldFlowLines = __commonJS({
|
|
|
1065
1065
|
} else if (mode === FOLD_QUOTED) {
|
|
1066
1066
|
while (prev === " " || prev === " ") {
|
|
1067
1067
|
prev = ch;
|
|
1068
|
-
ch =
|
|
1068
|
+
ch = text2[i += 1];
|
|
1069
1069
|
overflow = true;
|
|
1070
1070
|
}
|
|
1071
1071
|
const j = i > escEnd + 1 ? i - 2 : escStart - 1;
|
|
1072
1072
|
if (escapedFolds[j])
|
|
1073
|
-
return
|
|
1073
|
+
return text2;
|
|
1074
1074
|
folds.push(j);
|
|
1075
1075
|
escapedFolds[j] = true;
|
|
1076
1076
|
end = j + endStep;
|
|
@@ -1085,39 +1085,39 @@ var require_foldFlowLines = __commonJS({
|
|
|
1085
1085
|
if (overflow && onOverflow)
|
|
1086
1086
|
onOverflow();
|
|
1087
1087
|
if (folds.length === 0)
|
|
1088
|
-
return
|
|
1088
|
+
return text2;
|
|
1089
1089
|
if (onFold)
|
|
1090
1090
|
onFold();
|
|
1091
|
-
let res =
|
|
1091
|
+
let res = text2.slice(0, folds[0]);
|
|
1092
1092
|
for (let i2 = 0; i2 < folds.length; ++i2) {
|
|
1093
1093
|
const fold = folds[i2];
|
|
1094
|
-
const end2 = folds[i2 + 1] ||
|
|
1094
|
+
const end2 = folds[i2 + 1] || text2.length;
|
|
1095
1095
|
if (fold === 0)
|
|
1096
1096
|
res = `
|
|
1097
|
-
${indent}${
|
|
1097
|
+
${indent}${text2.slice(0, end2)}`;
|
|
1098
1098
|
else {
|
|
1099
1099
|
if (mode === FOLD_QUOTED && escapedFolds[fold])
|
|
1100
|
-
res += `${
|
|
1100
|
+
res += `${text2[fold]}\\`;
|
|
1101
1101
|
res += `
|
|
1102
|
-
${indent}${
|
|
1102
|
+
${indent}${text2.slice(fold + 1, end2)}`;
|
|
1103
1103
|
}
|
|
1104
1104
|
}
|
|
1105
1105
|
return res;
|
|
1106
1106
|
}
|
|
1107
|
-
function consumeMoreIndentedLines(
|
|
1107
|
+
function consumeMoreIndentedLines(text2, i, indent) {
|
|
1108
1108
|
let end = i;
|
|
1109
1109
|
let start = i + 1;
|
|
1110
|
-
let ch =
|
|
1110
|
+
let ch = text2[start];
|
|
1111
1111
|
while (ch === " " || ch === " ") {
|
|
1112
1112
|
if (i < start + indent) {
|
|
1113
|
-
ch =
|
|
1113
|
+
ch = text2[++i];
|
|
1114
1114
|
} else {
|
|
1115
1115
|
do {
|
|
1116
|
-
ch =
|
|
1116
|
+
ch = text2[++i];
|
|
1117
1117
|
} while (ch && ch !== "\n");
|
|
1118
1118
|
end = i;
|
|
1119
1119
|
start = i + 1;
|
|
1120
|
-
ch =
|
|
1120
|
+
ch = text2[start];
|
|
1121
1121
|
}
|
|
1122
1122
|
}
|
|
1123
1123
|
return end;
|
|
@@ -6347,15 +6347,15 @@ var require_parser = __commonJS({
|
|
|
6347
6347
|
var node_process = __require("process");
|
|
6348
6348
|
var cst = require_cst();
|
|
6349
6349
|
var lexer = require_lexer();
|
|
6350
|
-
function includesToken(
|
|
6351
|
-
for (let i = 0; i <
|
|
6352
|
-
if (
|
|
6350
|
+
function includesToken(list2, type) {
|
|
6351
|
+
for (let i = 0; i < list2.length; ++i)
|
|
6352
|
+
if (list2[i].type === type)
|
|
6353
6353
|
return true;
|
|
6354
6354
|
return false;
|
|
6355
6355
|
}
|
|
6356
|
-
function findNonEmptyIndex(
|
|
6357
|
-
for (let i = 0; i <
|
|
6358
|
-
switch (
|
|
6356
|
+
function findNonEmptyIndex(list2) {
|
|
6357
|
+
for (let i = 0; i < list2.length; ++i) {
|
|
6358
|
+
switch (list2[i].type) {
|
|
6359
6359
|
case "space":
|
|
6360
6360
|
case "comment":
|
|
6361
6361
|
case "newline":
|
|
@@ -7406,10 +7406,10 @@ ${SHOW_CURSOR}`);
|
|
|
7406
7406
|
reject(outcome.error);
|
|
7407
7407
|
}
|
|
7408
7408
|
};
|
|
7409
|
-
const onKeypress = (
|
|
7410
|
-
const name = key?.name ??
|
|
7409
|
+
const onKeypress = (text2, key) => {
|
|
7410
|
+
const name = key?.name ?? text2;
|
|
7411
7411
|
if (key?.ctrl && (name === "c" || name === "d")) return finish({ error: new PromptCancelled() });
|
|
7412
|
-
const result = onKey(
|
|
7412
|
+
const result = onKey(text2, name);
|
|
7413
7413
|
if (result === "redraw") output.write(`${up(height + 1)}${draw()}`);
|
|
7414
7414
|
else if (result) finish(result);
|
|
7415
7415
|
};
|
|
@@ -7432,19 +7432,19 @@ ${draw()}`);
|
|
|
7432
7432
|
function marker(options) {
|
|
7433
7433
|
return options.color ? options.trueColor ? "\x1B[1;38;2;253;75;3m" : "\x1B[1;38;5;202m" : "\x1B[1m";
|
|
7434
7434
|
}
|
|
7435
|
-
function move(current, count,
|
|
7435
|
+
function move(current, count, text2, name) {
|
|
7436
7436
|
if (name === "up" || name === "k") return (current - 1 + count) % count;
|
|
7437
7437
|
if (name === "down" || name === "j") return (current + 1) % count;
|
|
7438
|
-
if (
|
|
7438
|
+
if (text2 && /^[1-9]$/.test(text2) && Number(text2) <= count) return Number(text2) - 1;
|
|
7439
7439
|
return null;
|
|
7440
7440
|
}
|
|
7441
7441
|
function selectMenu(input, output, question, choices, options = {}) {
|
|
7442
7442
|
let current = Math.min(Math.max(options.initial ?? 0, 0), choices.length - 1);
|
|
7443
7443
|
const on = marker(options);
|
|
7444
7444
|
const rows = () => choices.map((c, i) => i === current ? `${on}> ${c}${OFF}` : ` ${c}`);
|
|
7445
|
-
return runMenu(input, output, question, HINT, rows, (
|
|
7445
|
+
return runMenu(input, output, question, HINT, rows, (text2, name) => {
|
|
7446
7446
|
if (name === "return" || name === "enter") return { pick: current, summary: choices[current] ?? "" };
|
|
7447
|
-
const next = move(current, choices.length,
|
|
7447
|
+
const next = move(current, choices.length, text2, name);
|
|
7448
7448
|
if (next === null || next === current) return null;
|
|
7449
7449
|
current = next;
|
|
7450
7450
|
return "redraw";
|
|
@@ -7458,7 +7458,7 @@ function multiSelectMenu(input, output, question, choices, options = {}) {
|
|
|
7458
7458
|
const row = `[${ticked[i] ? "x" : " "}] ${c}`;
|
|
7459
7459
|
return i === current ? `${on}> ${row}${OFF}` : ` ${row}`;
|
|
7460
7460
|
});
|
|
7461
|
-
return runMenu(input, output, question, MULTI_HINT, rows, (
|
|
7461
|
+
return runMenu(input, output, question, MULTI_HINT, rows, (text2, name) => {
|
|
7462
7462
|
if (name === "return" || name === "enter") {
|
|
7463
7463
|
const picks = choices.flatMap((_, i) => ticked[i] ? [i] : []);
|
|
7464
7464
|
return { pick: picks, summary: picks.map((i) => choices[i]).join(", ") || "none" };
|
|
@@ -7467,17 +7467,53 @@ function multiSelectMenu(input, output, question, choices, options = {}) {
|
|
|
7467
7467
|
ticked[current] = !ticked[current];
|
|
7468
7468
|
return "redraw";
|
|
7469
7469
|
}
|
|
7470
|
-
if (
|
|
7471
|
-
current = Number(
|
|
7470
|
+
if (text2 && /^[1-9]$/.test(text2) && Number(text2) <= choices.length) {
|
|
7471
|
+
current = Number(text2) - 1;
|
|
7472
7472
|
ticked[current] = !ticked[current];
|
|
7473
7473
|
return "redraw";
|
|
7474
7474
|
}
|
|
7475
|
-
const next = move(current, choices.length,
|
|
7475
|
+
const next = move(current, choices.length, text2, name);
|
|
7476
7476
|
if (next === null || next === current) return null;
|
|
7477
7477
|
current = next;
|
|
7478
7478
|
return "redraw";
|
|
7479
7479
|
});
|
|
7480
7480
|
}
|
|
7481
|
+
function listenForEnter(input, onEnter, onCancel) {
|
|
7482
|
+
const wasRaw = input.isRaw === true;
|
|
7483
|
+
let done = false;
|
|
7484
|
+
const stop = () => {
|
|
7485
|
+
if (done) return;
|
|
7486
|
+
done = true;
|
|
7487
|
+
input.removeListener("keypress", onKeypress);
|
|
7488
|
+
input.removeListener("error", stop);
|
|
7489
|
+
process.removeListener("SIGINT", cancel);
|
|
7490
|
+
try {
|
|
7491
|
+
input.setRawMode?.(wasRaw);
|
|
7492
|
+
} catch {
|
|
7493
|
+
}
|
|
7494
|
+
input.pause();
|
|
7495
|
+
};
|
|
7496
|
+
const cancel = () => {
|
|
7497
|
+
if (done) return;
|
|
7498
|
+
stop();
|
|
7499
|
+
onCancel();
|
|
7500
|
+
};
|
|
7501
|
+
const onKeypress = (_text, key) => {
|
|
7502
|
+
if (key?.ctrl && key.name === "c") cancel();
|
|
7503
|
+
else if (key?.name === "return" || key?.name === "enter") onEnter();
|
|
7504
|
+
};
|
|
7505
|
+
try {
|
|
7506
|
+
emitKeypressEvents(input);
|
|
7507
|
+
input.setRawMode?.(true);
|
|
7508
|
+
input.on("keypress", onKeypress);
|
|
7509
|
+
input.on("error", stop);
|
|
7510
|
+
process.on("SIGINT", cancel);
|
|
7511
|
+
input.resume();
|
|
7512
|
+
} catch {
|
|
7513
|
+
stop();
|
|
7514
|
+
}
|
|
7515
|
+
return stop;
|
|
7516
|
+
}
|
|
7481
7517
|
|
|
7482
7518
|
// src/io.ts
|
|
7483
7519
|
var PromptCancelled = class extends Error {
|
|
@@ -7548,8 +7584,8 @@ function openerFor(platform, url) {
|
|
|
7548
7584
|
function realIo() {
|
|
7549
7585
|
return {
|
|
7550
7586
|
env: process.env,
|
|
7551
|
-
stdout: (
|
|
7552
|
-
stderr: (
|
|
7587
|
+
stdout: (text2) => process.stdout.write(text2),
|
|
7588
|
+
stderr: (text2) => process.stderr.write(text2),
|
|
7553
7589
|
stdinIsTTY: Boolean(process.stdin.isTTY),
|
|
7554
7590
|
stdoutIsTTY: Boolean(process.stdout.isTTY),
|
|
7555
7591
|
stderrIsTTY: Boolean(process.stderr.isTTY),
|
|
@@ -7563,6 +7599,7 @@ function realIo() {
|
|
|
7563
7599
|
...options,
|
|
7564
7600
|
trueColor: /^(truecolor|24bit)$/i.test(process.env.COLORTERM ?? "")
|
|
7565
7601
|
}),
|
|
7602
|
+
listenForEnter: (onEnter, onCancel) => listenForEnter(process.stdin, onEnter, onCancel),
|
|
7566
7603
|
uninterruptible,
|
|
7567
7604
|
run: runProcess,
|
|
7568
7605
|
openUrl: async (url) => {
|
|
@@ -7576,7 +7613,6 @@ function realIo() {
|
|
|
7576
7613
|
now: () => Date.now(),
|
|
7577
7614
|
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
7578
7615
|
loginTimeoutMs: 9e5,
|
|
7579
|
-
browserGraceMs: 5e3,
|
|
7580
7616
|
fetchTimeoutMs: 15e3
|
|
7581
7617
|
};
|
|
7582
7618
|
}
|
|
@@ -8131,8 +8167,8 @@ function signInAgainUrl(authorize) {
|
|
|
8131
8167
|
const url = new URL(authorize);
|
|
8132
8168
|
return `${url.origin}/login?redirect=${encodeURIComponent(`${url.pathname}${url.search}`)}`;
|
|
8133
8169
|
}
|
|
8134
|
-
function html(
|
|
8135
|
-
return
|
|
8170
|
+
function html(text2) {
|
|
8171
|
+
return text2.replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);
|
|
8136
8172
|
}
|
|
8137
8173
|
function page(body) {
|
|
8138
8174
|
return `<!doctype html><html><head><meta charset="utf-8"><title>Amdahl CLI</title></head><body style="font-family:system-ui,sans-serif;max-width:32rem;margin:4rem auto;line-height:1.5">${body}</body></html>`;
|
|
@@ -8542,8 +8578,20 @@ async function call(fn) {
|
|
|
8542
8578
|
|
|
8543
8579
|
// src/output.ts
|
|
8544
8580
|
var CONTROL_RE = /[\u0000-\u001f\u007f-\u009f]/g;
|
|
8545
|
-
function printable(
|
|
8546
|
-
return
|
|
8581
|
+
function printable(text2) {
|
|
8582
|
+
return text2.replace(CONTROL_RE, "");
|
|
8583
|
+
}
|
|
8584
|
+
var HYPERLINK_TERMINALS = /* @__PURE__ */ new Set(["iTerm.app", "vscode", "WarpTerminal", "Apple_Terminal", "WezTerm", "ghostty"]);
|
|
8585
|
+
function supportsHyperlinks(env, color) {
|
|
8586
|
+
if (env.FORCE_HYPERLINK === "0") return false;
|
|
8587
|
+
if (env.FORCE_HYPERLINK === "1") return true;
|
|
8588
|
+
if (!color) return false;
|
|
8589
|
+
if (HYPERLINK_TERMINALS.has(env.TERM_PROGRAM ?? "")) return true;
|
|
8590
|
+
if (Number(env.VTE_VERSION) >= 5e3) return true;
|
|
8591
|
+
return Boolean(env.WT_SESSION);
|
|
8592
|
+
}
|
|
8593
|
+
function hyperlink(text2, url) {
|
|
8594
|
+
return `\x1B]8;;${printable(url)}\x1B\\${text2}\x1B]8;;\x1B\\`;
|
|
8547
8595
|
}
|
|
8548
8596
|
function createOutput(io, json, noColor) {
|
|
8549
8597
|
const color = !noColor && !io.env.NO_COLOR && io.env.TERM !== "dumb" && io.stderrIsTTY && !json;
|
|
@@ -8559,16 +8607,16 @@ function createOutput(io, json, noColor) {
|
|
|
8559
8607
|
`);
|
|
8560
8608
|
}
|
|
8561
8609
|
},
|
|
8562
|
-
info(
|
|
8563
|
-
io.stderr(
|
|
8610
|
+
info(text2) {
|
|
8611
|
+
io.stderr(text2.endsWith("\n") ? text2 : `${text2}
|
|
8564
8612
|
`);
|
|
8565
8613
|
},
|
|
8566
8614
|
event(data) {
|
|
8567
8615
|
if (json) io.stderr(`${JSON.stringify(data)}
|
|
8568
8616
|
`);
|
|
8569
8617
|
},
|
|
8570
|
-
bold(
|
|
8571
|
-
return color ? `\x1B[1m${
|
|
8618
|
+
bold(text2) {
|
|
8619
|
+
return color ? `\x1B[1m${text2}\x1B[22m` : text2;
|
|
8572
8620
|
}
|
|
8573
8621
|
};
|
|
8574
8622
|
}
|
|
@@ -8593,7 +8641,8 @@ async function browserSignIn(ctx) {
|
|
|
8593
8641
|
const endpoints = await discover(ctx.apiUrl);
|
|
8594
8642
|
const pkce = createPkce();
|
|
8595
8643
|
const consoleUrl = consoleUrlFor(io, ctx.apiUrl);
|
|
8596
|
-
let
|
|
8644
|
+
let stopKeys = () => {
|
|
8645
|
+
};
|
|
8597
8646
|
let linkShown = false;
|
|
8598
8647
|
const loopback = await startLoopback(io, {
|
|
8599
8648
|
port,
|
|
@@ -8602,7 +8651,6 @@ async function browserSignIn(ctx) {
|
|
|
8602
8651
|
timeoutMs: io.loginTimeoutMs,
|
|
8603
8652
|
// The page carries the way on; the authorize link would only sign in as the same address again.
|
|
8604
8653
|
onSignInAgain: (reason, retry) => {
|
|
8605
|
-
clearTimeout(timer);
|
|
8606
8654
|
linkShown = true;
|
|
8607
8655
|
out.info(signInAgainLine(reason, retry));
|
|
8608
8656
|
}
|
|
@@ -8619,18 +8667,27 @@ async function browserSignIn(ctx) {
|
|
|
8619
8667
|
${url}
|
|
8620
8668
|
`);
|
|
8621
8669
|
};
|
|
8670
|
+
let cancelled;
|
|
8622
8671
|
if (flags["no-browser"]) {
|
|
8623
8672
|
showLink("Open this URL in a browser to sign in:");
|
|
8624
8673
|
} else {
|
|
8625
8674
|
out.info("Opening your browser\u2026");
|
|
8675
|
+
if (!ctx.nonInteractive && io.stderrIsTTY) {
|
|
8676
|
+
const fallback = supportsHyperlinks(io.env, out.color) ? hyperlink("Open the sign-in page", url) : "Press Enter for the link.";
|
|
8677
|
+
out.info(`Browser didn't open? ${fallback}`);
|
|
8678
|
+
cancelled = new Promise((_, reject) => {
|
|
8679
|
+
stopKeys = io.listenForEnter(
|
|
8680
|
+
() => showLink("Open this link to sign in:"),
|
|
8681
|
+
() => reject(new PromptCancelled())
|
|
8682
|
+
);
|
|
8683
|
+
});
|
|
8684
|
+
}
|
|
8626
8685
|
void io.openUrl(url).then((opened) => {
|
|
8627
8686
|
if (!opened) showLink("Your browser did not open. Open this link to sign in:");
|
|
8628
8687
|
});
|
|
8629
|
-
timer = setTimeout(() => showLink("Finish in your browser, or open this link:"), io.browserGraceMs);
|
|
8630
|
-
timer.unref?.();
|
|
8631
8688
|
}
|
|
8632
|
-
const callback = await loopback.result;
|
|
8633
|
-
|
|
8689
|
+
const callback = await (cancelled ? Promise.race([loopback.result, cancelled]) : loopback.result);
|
|
8690
|
+
stopKeys();
|
|
8634
8691
|
linkShown = true;
|
|
8635
8692
|
if (callback.kind === "no_business") {
|
|
8636
8693
|
throw new CliError("no_business", noBusinessMessage(consoleUrl, callback.mayCreate, callback.reason), EXIT.noWorkspace);
|
|
@@ -8664,7 +8721,7 @@ async function browserSignIn(ctx) {
|
|
|
8664
8721
|
ctx.saveConfig();
|
|
8665
8722
|
return { profile: name, me, workspace: ws };
|
|
8666
8723
|
} finally {
|
|
8667
|
-
|
|
8724
|
+
stopKeys();
|
|
8668
8725
|
loopback.close();
|
|
8669
8726
|
}
|
|
8670
8727
|
}
|
|
@@ -8790,8 +8847,8 @@ var shipped_default = [
|
|
|
8790
8847
|
var SKILL_URL = "https://docs.amdahl.ai/skills/amdahl/SKILL.md";
|
|
8791
8848
|
var SKILL_TEXT = SKILL_default;
|
|
8792
8849
|
var SHIPPED_SKILL_SHA256 = shipped_default;
|
|
8793
|
-
function isShippedSkill(
|
|
8794
|
-
return SHIPPED_SKILL_SHA256.includes(createHash2("sha256").update(
|
|
8850
|
+
function isShippedSkill(text2) {
|
|
8851
|
+
return SHIPPED_SKILL_SHA256.includes(createHash2("sha256").update(text2).digest("hex"));
|
|
8795
8852
|
}
|
|
8796
8853
|
var SKILL_DIRS = {
|
|
8797
8854
|
"claude-code": [".claude", "skills"],
|
|
@@ -9178,6 +9235,119 @@ function withTimeout(promise, ms, file) {
|
|
|
9178
9235
|
});
|
|
9179
9236
|
return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
|
|
9180
9237
|
}
|
|
9238
|
+
var WEAKEST = {
|
|
9239
|
+
rules: "how it follows your rules",
|
|
9240
|
+
ask: "the ask",
|
|
9241
|
+
opener: "the opener",
|
|
9242
|
+
fit: "how it fits the recipient",
|
|
9243
|
+
proof: "its proof points",
|
|
9244
|
+
length: "the length",
|
|
9245
|
+
style: "the tone",
|
|
9246
|
+
preference: "how it matches your preferences",
|
|
9247
|
+
voice: "how much it sounds like you"
|
|
9248
|
+
};
|
|
9249
|
+
var CONCERNS = {
|
|
9250
|
+
conflicts_with_callers_ask: "it asks for a different length or time than your ask",
|
|
9251
|
+
drops_ask: "it leaves out your ask",
|
|
9252
|
+
adds_claim: "it states something neither your draft nor your facts support",
|
|
9253
|
+
drops_entity: "it drops a name, link or placeholder you had",
|
|
9254
|
+
inflates: "it is longer than you asked for",
|
|
9255
|
+
no_gain: "it changed little beyond the wording",
|
|
9256
|
+
breaks_rules: "it breaks one of your rules"
|
|
9257
|
+
};
|
|
9258
|
+
var EVIDENCE_MISSED = {
|
|
9259
|
+
corpus_empty: "the workspace has none yet",
|
|
9260
|
+
evidence_unavailable: "this environment does not read them",
|
|
9261
|
+
evidence_read_failed: "the read failed, so a retry may work"
|
|
9262
|
+
};
|
|
9263
|
+
var MAX_LINES = 3;
|
|
9264
|
+
function list(value) {
|
|
9265
|
+
return Array.isArray(value) ? value.filter((v) => !!v && typeof v === "object") : null;
|
|
9266
|
+
}
|
|
9267
|
+
function record(value) {
|
|
9268
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
9269
|
+
}
|
|
9270
|
+
function text(value) {
|
|
9271
|
+
return typeof value === "string" ? printable(value).trim() : "";
|
|
9272
|
+
}
|
|
9273
|
+
function sentence(value) {
|
|
9274
|
+
return /[.!?]$/.test(value) ? value : `${value}.`;
|
|
9275
|
+
}
|
|
9276
|
+
function plural(n, one, many = `${one}s`) {
|
|
9277
|
+
return `${n} ${n === 1 ? one : many}`;
|
|
9278
|
+
}
|
|
9279
|
+
function readSteps(steps) {
|
|
9280
|
+
const reasonOf = (node) => text(steps.find((s) => s.node === node)?.reason);
|
|
9281
|
+
const changed = (node) => steps.some((s) => s.node === node && s.changed === true);
|
|
9282
|
+
const counts = new Map(
|
|
9283
|
+
reasonOf("w3").split(",").map((part) => part.split(":")).filter(([, n]) => /^\d+$/.test(n ?? "")).map(([code, n]) => [code, Number(n)])
|
|
9284
|
+
);
|
|
9285
|
+
const did = [];
|
|
9286
|
+
const repaired = counts.get("repaired") ?? 0;
|
|
9287
|
+
const deleted = counts.get("deleted") ?? 0;
|
|
9288
|
+
if (repaired && deleted) did.push(`Rewrote ${plural(repaired, "sentence")} and cut ${deleted} that nothing backed.`);
|
|
9289
|
+
else if (repaired) did.push(`Rewrote ${plural(repaired, "sentence")} that did not hold up.`);
|
|
9290
|
+
else if (deleted) did.push(`Cut ${plural(deleted, "sentence")} that nothing backed.`);
|
|
9291
|
+
const repair = reasonOf("w5");
|
|
9292
|
+
if (changed("w5") && repair.startsWith("repaired:")) {
|
|
9293
|
+
const weakest = WEAKEST[repair.slice("repaired:".length)];
|
|
9294
|
+
did.push(weakest ? `Reworked ${weakest}.` : "Reworked its weakest part.");
|
|
9295
|
+
}
|
|
9296
|
+
const flagged = [];
|
|
9297
|
+
const open = counts.get("open");
|
|
9298
|
+
if (open) flagged.push(`${plural(open, "sentence problem")} it could not fix`);
|
|
9299
|
+
const second = reasonOf("w6");
|
|
9300
|
+
if (changed("w6") && !second.startsWith("kept_before_repair")) {
|
|
9301
|
+
const concern = CONCERNS[second];
|
|
9302
|
+
flagged.push(concern ? `a second-check concern (${concern})` : "a second-check concern");
|
|
9303
|
+
}
|
|
9304
|
+
return { did: did.join(" "), flagged };
|
|
9305
|
+
}
|
|
9306
|
+
function and(parts) {
|
|
9307
|
+
return parts.length < 2 ? parts[0] ?? "" : `${parts.slice(0, -1).join(", ")} and ${parts[parts.length - 1]}`;
|
|
9308
|
+
}
|
|
9309
|
+
function whatAmdahlDid(result) {
|
|
9310
|
+
const steps = result.unchanged === true ? { did: "", flagged: [] } : readSteps(list(result.steps) ?? []);
|
|
9311
|
+
const flagged = [...steps.flagged];
|
|
9312
|
+
let checked = "";
|
|
9313
|
+
let removed = "";
|
|
9314
|
+
const evidence = record(result.evidence);
|
|
9315
|
+
const claims = list(result.unsupported_claims);
|
|
9316
|
+
if (evidence?.used === true) {
|
|
9317
|
+
const quotes = record(result.lift)?.quotes;
|
|
9318
|
+
const read = typeof quotes === "number" && quotes > 0 ? ` (${plural(quotes, "quote")})` : "";
|
|
9319
|
+
if (claims) {
|
|
9320
|
+
const still = claims.filter((c) => c.status !== "removed").length;
|
|
9321
|
+
const cut = claims.length - still;
|
|
9322
|
+
if (cut) removed = `Removed ${plural(cut, "claim")} your calls don't back.`;
|
|
9323
|
+
if (still) flagged.unshift(`${plural(still, "claim")} your calls don't back`);
|
|
9324
|
+
checked = `Checked every claim against your calls${read}${claims.length ? "" : " and found none they don't back"}.`;
|
|
9325
|
+
} else checked = `Checked the message against your calls${read}.`;
|
|
9326
|
+
} else if (evidence?.requested === "workspace" && EVIDENCE_MISSED[text(evidence.reason)]) {
|
|
9327
|
+
checked = `Skipped checking claims against your calls: ${EVIDENCE_MISSED[text(evidence.reason)]}.`;
|
|
9328
|
+
}
|
|
9329
|
+
const used = (list(record(result.context_use)?.rows) ?? []).filter((r) => r.verdict === "pass");
|
|
9330
|
+
const sources = [
|
|
9331
|
+
used.some((r) => r.bucket === "internal") ? "Amdahl's own records" : "",
|
|
9332
|
+
used.some((r) => r.bucket === "external") ? "what their company or market published" : ""
|
|
9333
|
+
].filter(Boolean);
|
|
9334
|
+
const usedLine = sources.length ? `Used ${plural(sources.length, "source")}: ${and(sources)}.` : "";
|
|
9335
|
+
const omitted = list(result.omitted) ?? [];
|
|
9336
|
+
const whys = [...new Set(omitted.map((o) => text(o.why)).filter(Boolean))];
|
|
9337
|
+
const more = whys.length > 1 ? ` (${plural(whys.length - 1, "more reason")} in --json)` : "";
|
|
9338
|
+
const leftOut = omitted.length ? `Left out ${plural(omitted.length, "thing")}${whys[0] ? `: ${sentence(whys[0])}` : "."}${more}` : "";
|
|
9339
|
+
const lines = [
|
|
9340
|
+
{ rank: 2, line: sentence(text(result.what_changed)) },
|
|
9341
|
+
{ rank: 5, line: checked },
|
|
9342
|
+
{ rank: 3, line: removed },
|
|
9343
|
+
{ rank: 6, line: usedLine },
|
|
9344
|
+
{ rank: 7, line: steps.did },
|
|
9345
|
+
{ rank: 4, line: leftOut },
|
|
9346
|
+
{ rank: 1, line: flagged.length ? `Flagged ${and(flagged)}; check before sending.` : "" }
|
|
9347
|
+
].filter((l) => l.line && l.line !== ".");
|
|
9348
|
+
const kept = new Set([...lines].sort((a, b) => a.rank - b.rank).slice(0, MAX_LINES));
|
|
9349
|
+
return lines.filter((l) => kept.has(l)).map((l) => l.line);
|
|
9350
|
+
}
|
|
9181
9351
|
async function optimize(ctx, args) {
|
|
9182
9352
|
const { io, out, flags } = ctx;
|
|
9183
9353
|
let files = args;
|
|
@@ -9242,6 +9412,8 @@ async function optimize(ctx, args) {
|
|
|
9242
9412
|
if (result.unchanged === true) out.info("No rewrite beat your draft; it is returned unchanged.");
|
|
9243
9413
|
else if (typeof result.summary === "string") out.info(result.summary);
|
|
9244
9414
|
out.result({}, String(result.message ?? ""));
|
|
9415
|
+
const did = whatAmdahlDid(result);
|
|
9416
|
+
if (did.length) out.info(did.join("\n"));
|
|
9245
9417
|
}
|
|
9246
9418
|
}
|
|
9247
9419
|
if (out.json) out.result(results.length === 1 ? results[0] : results);
|
|
@@ -9564,8 +9736,8 @@ async function setup(ctx) {
|
|
|
9564
9736
|
const verbose = ctx.flags.verbose === true;
|
|
9565
9737
|
const say = (line) => io.stdout(`${line}
|
|
9566
9738
|
`);
|
|
9567
|
-
const detail = (
|
|
9568
|
-
if (verbose &&
|
|
9739
|
+
const detail = (text2) => {
|
|
9740
|
+
if (verbose && text2) say(text2.replace(/^/gm, " "));
|
|
9569
9741
|
};
|
|
9570
9742
|
say(`${out.bold("Amdahl")} \xB7 predictive ML for GTM`);
|
|
9571
9743
|
const found = await detectClients(ctx);
|
|
@@ -9716,8 +9888,8 @@ function field(header, start, length) {
|
|
|
9716
9888
|
}
|
|
9717
9889
|
}
|
|
9718
9890
|
function octal(header, start, length) {
|
|
9719
|
-
const
|
|
9720
|
-
return /^[0-7]{1,12}$/.test(
|
|
9891
|
+
const text2 = header.toString("latin1", start, start + length).replace(/[\0 ]+$/, "").replace(/^ +/, "");
|
|
9892
|
+
return /^[0-7]{1,12}$/.test(text2) ? parseInt(text2, 8) : null;
|
|
9721
9893
|
}
|
|
9722
9894
|
function checkPath(path) {
|
|
9723
9895
|
const shown = JSON.stringify(path);
|
|
@@ -9843,15 +10015,15 @@ var UNREADABLE_WARNING = Object.freeze({
|
|
|
9843
10015
|
function readWarning(raw) {
|
|
9844
10016
|
if (raw === void 0 || raw === null) return void 0;
|
|
9845
10017
|
if (typeof raw !== "object" || Array.isArray(raw)) return { ...UNREADABLE_WARNING };
|
|
9846
|
-
const { result, flagged, line, text } = raw;
|
|
10018
|
+
const { result, flagged, line, text: text2 } = raw;
|
|
9847
10019
|
if (result !== "warn" && result !== "fail") return { ...UNREADABLE_WARNING };
|
|
9848
|
-
const
|
|
9849
|
-
if (!
|
|
10020
|
+
const sentence2 = typeof text2 === "string" ? warningText(text2) : "";
|
|
10021
|
+
if (!sentence2) return { ...UNREADABLE_WARNING };
|
|
9850
10022
|
return {
|
|
9851
10023
|
result,
|
|
9852
10024
|
flagged: typeof flagged === "string" && CHECK_ID_RE.test(flagged) ? flagged : null,
|
|
9853
10025
|
line: typeof line === "number" && Number.isSafeInteger(line) && line > 0 ? line : null,
|
|
9854
|
-
text:
|
|
10026
|
+
text: sentence2
|
|
9855
10027
|
};
|
|
9856
10028
|
}
|
|
9857
10029
|
function skillPage(site, ref) {
|
|
@@ -10047,13 +10219,13 @@ function checkDigest(body, fileUrl, sha256) {
|
|
|
10047
10219
|
}
|
|
10048
10220
|
function checkSkillMd(body, what, ref) {
|
|
10049
10221
|
const bad = (why) => new CliError("invalid_skill", `${what} is not a valid skill: ${why}.`, EXIT.general);
|
|
10050
|
-
let
|
|
10222
|
+
let text2;
|
|
10051
10223
|
try {
|
|
10052
|
-
|
|
10224
|
+
text2 = new TextDecoder("utf-8", { fatal: true }).decode(body);
|
|
10053
10225
|
} catch {
|
|
10054
10226
|
throw bad("it is not UTF-8 text");
|
|
10055
10227
|
}
|
|
10056
|
-
const fm = FRONT_MATTER_RE.exec(
|
|
10228
|
+
const fm = FRONT_MATTER_RE.exec(text2);
|
|
10057
10229
|
if (!fm) throw bad("it has no front matter");
|
|
10058
10230
|
const doc = (0, import_yaml.parseDocument)(fm[1] ?? "", { uniqueKeys: true });
|
|
10059
10231
|
const yamlError = doc.errors[0];
|
|
@@ -10248,7 +10420,7 @@ async function workspaceUse(ctx, args) {
|
|
|
10248
10420
|
}
|
|
10249
10421
|
|
|
10250
10422
|
// src/version.ts
|
|
10251
|
-
var VERSION = "0.3.
|
|
10423
|
+
var VERSION = "0.3.3";
|
|
10252
10424
|
|
|
10253
10425
|
// src/main.ts
|
|
10254
10426
|
var COMMANDS = {
|
package/package.json
CHANGED