humanish 0.115.0 → 0.117.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/CHANGELOG.md +41 -0
- package/README.md +7 -6
- package/TELEMETRY.md +6 -0
- package/dist/actors/codex/app-server-ui.js +11 -4
- package/dist/actors/codex/restricted-participant-policy.d.ts +0 -2
- package/dist/actors/codex/restricted-participant-policy.js +4 -32
- package/dist/actors/codex/restricted-participant.d.ts +5 -0
- package/dist/actors/codex/restricted-participant.js +3 -2
- package/dist/actors/computer-use/actor.d.ts +4 -0
- package/dist/actors/computer-use/actor.js +2 -0
- package/dist/actors/computer-use/loop/actions.d.ts +4 -4
- package/dist/actors/computer-use/loop/actions.js +25 -18
- package/dist/actors/computer-use/loop/debrief.js +61 -27
- package/dist/actors/computer-use/loop/session.d.ts +3 -0
- package/dist/actors/computer-use/loop/session.js +9 -1
- package/dist/actors/computer-use/loop/trace.js +1 -0
- package/dist/actors/computer-use/loop/types.d.ts +16 -14
- package/dist/actors/computer-use/loop.d.ts +1 -1
- package/dist/actors/computer-use/loop.js +1 -1
- package/dist/actors/computer-use/wait.d.ts +74 -0
- package/dist/actors/computer-use/wait.js +100 -0
- package/dist/actors/contract.d.ts +14 -0
- package/dist/actors/scripted-browser/steps.js +6 -5
- package/dist/analysis/analysis-limits.d.ts +35 -0
- package/dist/analysis/analysis-limits.js +41 -0
- package/dist/analysis/validation.js +14 -21
- package/dist/browser-control/protocol.d.ts +86 -6
- package/dist/browser-control/protocol.js +13 -6
- package/dist/cli/commands/analyze.js +2 -1
- package/dist/cli/commands/notes.js +2 -1
- package/dist/cli/commands/run-signals.js +5 -1
- package/dist/cli/commands/runs.js +2 -1
- package/dist/cli/commands/setup.js +3 -3
- package/dist/cli/commands/study-format.d.ts +5 -2
- package/dist/cli/commands/study-format.js +29 -9
- package/dist/cli/commands/study-route-computer-use.js +2 -2
- package/dist/cli/commands/study-route-scripted.js +1 -1
- package/dist/cli/commands/tui.js +59 -17
- package/dist/cli/doctor.js +9 -2
- package/dist/cli/findings-text.d.ts +5 -0
- package/dist/cli/findings-text.js +169 -0
- package/dist/cli/findings.d.ts +0 -4
- package/dist/cli/findings.js +5 -167
- package/dist/cli/io.js +6 -1
- package/dist/cli/update-check.js +4 -1
- package/dist/comms/connections.js +4 -3
- package/dist/comms/setup.js +18 -12
- package/dist/evidence/redaction.js +9 -1
- package/dist/evidence/secret-scrub.d.ts +15 -5
- package/dist/evidence/secret-scrub.js +67 -9
- package/dist/feedback/draft.js +1 -1
- package/dist/feedback/export-bundle.js +18 -14
- package/dist/feedback/feedback.js +25 -7
- package/dist/guest/desktop-executor.js +3 -1
- package/dist/guest/desktop-keys.js +59 -5
- package/dist/keys/key-resolution.d.ts +9 -0
- package/dist/keys/key-resolution.js +60 -48
- package/dist/keys/key-status.d.ts +2 -0
- package/dist/keys/key-status.js +9 -16
- package/dist/observer/pinned-files.js +1 -1
- package/dist/observer/render.js +3 -2
- package/dist/observer-app.html +5 -5
- package/dist/routes/computer-use/bundle-parts.d.ts +4 -4
- package/dist/routes/computer-use/bundle-parts.js +2 -2
- package/dist/routes/computer-use/bundle.d.ts +4 -5
- package/dist/routes/computer-use/bundle.js +1 -3
- package/dist/routes/computer-use/e2b-desktop/prepare.js +40 -31
- package/dist/routes/computer-use/fanout-records.js +10 -11
- package/dist/routes/computer-use/live-phase.d.ts +1 -1
- package/dist/routes/computer-use/live-phase.js +0 -1
- package/dist/routes/computer-use/local-vm.js +5 -2
- package/dist/routes/computer-use/participant-execution.d.ts +3 -2
- package/dist/routes/computer-use/participant-model.js +9 -0
- package/dist/routes/computer-use/participant-runs.d.ts +6 -2
- package/dist/routes/computer-use/participant-runs.js +9 -5
- package/dist/routes/computer-use/plan.d.ts +3 -0
- package/dist/routes/computer-use/plan.js +18 -13
- package/dist/routes/computer-use/rerun-selection.js +2 -2
- package/dist/routes/computer-use/result.js +3 -6
- package/dist/routes/computer-use/setup.d.ts +4 -6
- package/dist/routes/computer-use/setup.js +2 -6
- package/dist/routes/computer-use/single-bundle.d.ts +4 -5
- package/dist/routes/computer-use/single-bundle.js +22 -25
- package/dist/routes/computer-use/subject-projection.d.ts +4 -8
- package/dist/routes/computer-use/subject-projection.js +9 -31
- package/dist/routes/computer-use/types.d.ts +5 -42
- package/dist/routes/scripted/scenario.js +28 -12
- package/dist/routes/scripted/session-result.js +6 -3
- package/dist/routes/shared-world/bundle-records.js +2 -8
- package/dist/routes/shared-world/participant-specs.d.ts +0 -2
- package/dist/routes/shared-world/participant-specs.js +1 -20
- package/dist/routes/shared-world/plan.d.ts +3 -0
- package/dist/routes/shared-world/plan.js +25 -4
- package/dist/routes/shared-world/setup.js +2 -2
- package/dist/routes/terminal/ledger.d.ts +9 -9
- package/dist/routes/terminal/ledger.js +63 -40
- package/dist/routes/terminal/live-finish.js +7 -10
- package/dist/routes/terminal/live-sandbox.d.ts +1 -1
- package/dist/routes/terminal/live-sandbox.js +14 -11
- package/dist/routes/terminal/plan.d.ts +3 -0
- package/dist/routes/terminal/plan.js +8 -5
- package/dist/routes/terminal/sandbox.d.ts +4 -3
- package/dist/routes/terminal/sandbox.js +5 -5
- package/dist/routes/terminal/token-usage.d.ts +1 -2
- package/dist/routes/terminal/token-usage.js +4 -6
- package/dist/routes/terminal/types.d.ts +9 -1
- package/dist/run/bundle-shape.js +6 -1
- package/dist/run/bundle.d.ts +5 -3
- package/dist/run/contained-output.d.ts +53 -5
- package/dist/run/contained-output.js +141 -42
- package/dist/run/detail.d.ts +2 -1
- package/dist/run/detail.js +12 -7
- package/dist/run/escape-sequences.d.ts +11 -0
- package/dist/run/escape-sequences.js +93 -0
- package/dist/run/evidence-files.d.ts +8 -8
- package/dist/run/evidence-files.js +19 -23
- package/dist/run/locate.d.ts +32 -3
- package/dist/run/locate.js +45 -40
- package/dist/run/notes.d.ts +0 -8
- package/dist/run/notes.js +5 -51
- package/dist/run/outcomes.d.ts +24 -0
- package/dist/run/outcomes.js +19 -0
- package/dist/run/paths.d.ts +2 -0
- package/dist/run/paths.js +5 -1
- package/dist/run/preflight-receipts.js +13 -8
- package/dist/run/project.js +7 -4
- package/dist/run/reclaim-outcomes.d.ts +8 -6
- package/dist/run/reclaim-outcomes.js +10 -6
- package/dist/run/reclaim.d.ts +5 -0
- package/dist/run/reclaim.js +43 -16
- package/dist/run/run-clock.d.ts +50 -0
- package/dist/run/run-clock.js +66 -0
- package/dist/run/run.js +5 -2
- package/dist/run/sandbox-ids.d.ts +7 -2
- package/dist/run/sandbox-ids.js +27 -11
- package/dist/run/secrets.d.ts +2 -1
- package/dist/run/secrets.js +18 -22
- package/dist/run/stored-runs.js +14 -7
- package/dist/run/transient-comms-secrets.js +6 -17
- package/dist/run-study.js +22 -13
- package/dist/study/adapter-scorer-loader.js +6 -4
- package/dist/study/config.js +4 -1
- package/dist/study/discover.js +9 -6
- package/dist/study/init-paths.js +7 -5
- package/dist/study/keys.d.ts +2 -0
- package/dist/study/keys.js +2 -0
- package/dist/study/migrate/v2.js +2 -1
- package/dist/study/parse/actors.js +8 -0
- package/dist/study/persona-resolve.d.ts +2 -2
- package/dist/study/persona-resolve.js +9 -5
- package/dist/study/plan-participants.d.ts +4 -0
- package/dist/study/plan-participants.js +4 -0
- package/dist/study/plan-types.d.ts +2 -2
- package/dist/study/plan.d.ts +5 -3
- package/dist/study/plan.js +18 -9
- package/dist/study/preflight-probes.js +11 -3
- package/dist/study/preflight.js +9 -5
- package/dist/study/summary.d.ts +8 -2
- package/dist/study/summary.js +20 -22
- package/dist/study/types.d.ts +14 -0
- package/dist/study/validation.d.ts +5 -0
- package/dist/study/validation.js +8 -0
- package/dist/study/warnings.d.ts +19 -12
- package/dist/study/warnings.js +50 -17
- package/dist/subject/serve.d.ts +3 -0
- package/dist/subject/serve.js +4 -1
- package/dist/substrates/detached.js +14 -7
- package/dist/substrates/e2b/connection.d.ts +12 -0
- package/dist/substrates/e2b/connection.js +35 -0
- package/dist/substrates/e2b/desktop-executor.d.ts +1 -5
- package/dist/substrates/e2b/desktop-executor.js +45 -12
- package/dist/substrates/e2b/lifetime.d.ts +24 -4
- package/dist/substrates/e2b/lifetime.js +41 -4
- package/dist/substrates/e2b/sandbox.d.ts +4 -3
- package/dist/substrates/e2b/sandbox.js +13 -18
- package/dist/substrates/e2b/sdk.d.ts +20 -9
- package/dist/substrates/local/capacity.d.ts +18 -2
- package/dist/substrates/local/capacity.js +21 -2
- package/dist/substrates/local/runtime-host.js +21 -14
- package/dist/substrates/local/runtime.js +3 -11
- package/dist/tui/contract.d.ts +30 -5
- package/dist/tui/contract.js +4 -1
- package/dist/tui-app.js +150 -147
- package/dist/verify/artifacts.d.ts +9 -2
- package/dist/verify/artifacts.js +37 -13
- package/dist/verify/liveness.js +19 -5
- package/dist/verify/verify.js +54 -27
- package/docs/architecture/browser-control.md +10 -4
- package/docs/architecture/guest-desktop.md +7 -2
- package/docs/architecture/state-driven-executor.md +4 -2
- package/docs/contracts/run-bundle.md +18 -10
- package/docs/contracts/schemas.md +46 -29
- package/docs/contracts/study-analysis.md +10 -1
- package/docs/product/automatic-analysis.md +7 -1
- package/package.json +2 -2
|
@@ -3,18 +3,35 @@ import { ComputerUseExecutorError } from "../actors/computer-use/executor-error.
|
|
|
3
3
|
// hand these strings to xdotool, which has a command language, so only names from these tables
|
|
4
4
|
// ever reach it. The guest runtime ships this module, so it lives in src/guest/, which CI's
|
|
5
5
|
// guest-desktop job and scripts/guest-desktop-proof.mjs key on.
|
|
6
|
+
//
|
|
7
|
+
// The tables take the names in OpenAI's computer-use key map, the names @e2b/desktop's press()
|
|
8
|
+
// mapped (the hosted desktop sent keys through it before), and every printable ASCII
|
|
9
|
+
// punctuation character. xdotool finds the key and the Shift level for a keysym itself, so `?`
|
|
10
|
+
// arrives as `question` with Shift held on an American English keymap.
|
|
6
11
|
/** The modifiers a pointer action may hold, keyed by the upper-cased provider name. */
|
|
7
12
|
const modifierNames = Object.freeze({
|
|
8
13
|
CTRL: "ctrl",
|
|
9
14
|
CONTROL: "ctrl",
|
|
10
15
|
ALT: "alt",
|
|
16
|
+
OPTION: "alt",
|
|
11
17
|
SHIFT: "shift",
|
|
12
18
|
META: "super",
|
|
13
19
|
SUPER: "super",
|
|
14
20
|
CMD: "super",
|
|
21
|
+
COMMAND: "super",
|
|
22
|
+
WIN: "super",
|
|
23
|
+
WINDOWS: "super",
|
|
15
24
|
});
|
|
16
25
|
const keyNames = Object.freeze({
|
|
17
26
|
...modifierNames,
|
|
27
|
+
CONTROL_LEFT: "Control_L",
|
|
28
|
+
CONTROL_RIGHT: "Control_R",
|
|
29
|
+
ALT_LEFT: "Alt_L",
|
|
30
|
+
ALT_RIGHT: "Alt_R",
|
|
31
|
+
SHIFT_LEFT: "Shift_L",
|
|
32
|
+
SHIFT_RIGHT: "Shift_R",
|
|
33
|
+
SUPER_LEFT: "Super_L",
|
|
34
|
+
SUPER_RIGHT: "Super_R",
|
|
18
35
|
ENTER: "Return",
|
|
19
36
|
RETURN: "Return",
|
|
20
37
|
TAB: "Tab",
|
|
@@ -24,11 +41,14 @@ const keyNames = Object.freeze({
|
|
|
24
41
|
" ": "space",
|
|
25
42
|
BACKSPACE: "BackSpace",
|
|
26
43
|
DELETE: "Delete",
|
|
44
|
+
DEL: "Delete",
|
|
27
45
|
INSERT: "Insert",
|
|
28
46
|
HOME: "Home",
|
|
29
47
|
END: "End",
|
|
30
48
|
PAGEUP: "Prior",
|
|
31
49
|
PAGEDOWN: "Next",
|
|
50
|
+
PAGE_UP: "Prior",
|
|
51
|
+
PAGE_DOWN: "Next",
|
|
32
52
|
ARROWUP: "Up",
|
|
33
53
|
ARROWDOWN: "Down",
|
|
34
54
|
ARROWLEFT: "Left",
|
|
@@ -37,18 +57,45 @@ const keyNames = Object.freeze({
|
|
|
37
57
|
DOWN: "Down",
|
|
38
58
|
LEFT: "Left",
|
|
39
59
|
RIGHT: "Right",
|
|
60
|
+
CAPS_LOCK: "Caps_Lock",
|
|
61
|
+
NUM_LOCK: "Num_Lock",
|
|
62
|
+
SCROLL_LOCK: "Scroll_Lock",
|
|
63
|
+
PAUSE: "Pause",
|
|
64
|
+
BREAK: "Pause",
|
|
65
|
+
PRINT: "Print",
|
|
66
|
+
MENU: "Menu",
|
|
67
|
+
"!": "exclam",
|
|
68
|
+
'"': "quotedbl",
|
|
69
|
+
"#": "numbersign",
|
|
70
|
+
$: "dollar",
|
|
71
|
+
"%": "percent",
|
|
72
|
+
"&": "ampersand",
|
|
73
|
+
"'": "apostrophe",
|
|
74
|
+
"(": "parenleft",
|
|
75
|
+
")": "parenright",
|
|
76
|
+
"*": "asterisk",
|
|
40
77
|
"+": "plus",
|
|
41
|
-
"-": "minus",
|
|
42
|
-
"=": "equal",
|
|
43
78
|
",": "comma",
|
|
79
|
+
"-": "minus",
|
|
44
80
|
".": "period",
|
|
45
81
|
"/": "slash",
|
|
46
|
-
"
|
|
82
|
+
":": "colon",
|
|
47
83
|
";": "semicolon",
|
|
48
|
-
"
|
|
84
|
+
"<": "less",
|
|
85
|
+
"=": "equal",
|
|
86
|
+
">": "greater",
|
|
87
|
+
"?": "question",
|
|
88
|
+
"@": "at",
|
|
49
89
|
"[": "bracketleft",
|
|
90
|
+
"\\": "backslash",
|
|
50
91
|
"]": "bracketright",
|
|
92
|
+
"^": "asciicircum",
|
|
93
|
+
_: "underscore",
|
|
51
94
|
"`": "grave",
|
|
95
|
+
"{": "braceleft",
|
|
96
|
+
"|": "bar",
|
|
97
|
+
"}": "braceright",
|
|
98
|
+
"~": "asciitilde",
|
|
52
99
|
});
|
|
53
100
|
function lookup(table, key) {
|
|
54
101
|
const upper = key.toUpperCase();
|
|
@@ -59,9 +106,16 @@ function chord(names) {
|
|
|
59
106
|
throw new ComputerUseExecutorError("action_rejected", "not_dispatched");
|
|
60
107
|
return names.join("+");
|
|
61
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* A name that is itself a chord (`Control+a`, `ctrl++`) split at each plus sign that joins two
|
|
111
|
+
* names. A lone `+` and a trailing `+` after a joining one are the plus key.
|
|
112
|
+
*/
|
|
113
|
+
function chordParts(key) {
|
|
114
|
+
return key.length > 1 ? key.split(/\+(?!$)/) : [key];
|
|
115
|
+
}
|
|
62
116
|
/** A keypress chord in xdotool syntax. Unknown or repeated keys are refused before dispatch. */
|
|
63
117
|
export function xdotoolChord(keys) {
|
|
64
|
-
return chord(keys.map((key) => {
|
|
118
|
+
return chord(keys.flatMap(chordParts).map((key) => {
|
|
65
119
|
if (/^[a-z0-9]$/i.test(key))
|
|
66
120
|
return key.toLowerCase();
|
|
67
121
|
if (/^F(?:[1-9]|1[0-2])$/i.test(key))
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/** The vendor aliases `humanish keys set` accepts. A raw ENV_NAME is also accepted. */
|
|
2
|
+
export declare const KEY_VENDORS: string[];
|
|
3
|
+
/** The keys `humanish keys` lists, in its order, each with what humanish uses it for. */
|
|
4
|
+
export declare const LISTED_KEYS: {
|
|
5
|
+
name: string;
|
|
6
|
+
use: string;
|
|
7
|
+
}[];
|
|
8
|
+
/** The keys `humanish doctor` reports on every run, in its row order. */
|
|
9
|
+
export declare const DOCTOR_KEYS: string[];
|
|
1
10
|
export interface ResolvedKeyFill {
|
|
2
11
|
name: string;
|
|
3
12
|
/** Human-readable source label (a path or command name), never a value. */
|
|
@@ -24,33 +24,56 @@ import { loadEnvFile } from "./env-file.js";
|
|
|
24
24
|
import { cli } from "../cli/invocation.js";
|
|
25
25
|
import { humanishConfigFile } from "../cli/user-config.js";
|
|
26
26
|
import { OPENAI_EGRESS_PLACEHOLDER } from "../routes/terminal/runtime-auth.js";
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
/**
|
|
28
|
+
* The provider keys, in the order `humanish keys set` names their vendors. Implicit discovery fills
|
|
29
|
+
* only these names and the user store holds only these. Everything else in an overlay or store file
|
|
30
|
+
* is ignored and named: a repo-planted NODE_OPTIONS/LD_PRELOAD must never enter process env off a
|
|
31
|
+
* file the operator did not explicitly pass (an explicit --dotenv remains the operator's own
|
|
32
|
+
* full-file load). ANTHROPIC_API_KEY is not listed, and doctor does not report it: a Claude Code
|
|
33
|
+
* participant runs on its own login and never receives it. CODEX_API_KEY is an alternative spelling
|
|
34
|
+
* of the OpenAI key for terminal studies. Doctor reports AGENTMAIL_API_KEY only under `--study`, for
|
|
35
|
+
* a study whose email connection names it, since a connection may name another variable.
|
|
36
|
+
*/
|
|
37
|
+
const PROVIDER_KEYS = [
|
|
38
|
+
{
|
|
39
|
+
name: "OPENAI_API_KEY",
|
|
40
|
+
vendor: "openai",
|
|
41
|
+
listed: { order: 2, use: "participant model and analysis" },
|
|
42
|
+
doctor: true,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "E2B_API_KEY",
|
|
46
|
+
vendor: "e2b",
|
|
47
|
+
login: "e2b auth login",
|
|
48
|
+
listed: { order: 1, use: "hosted desktops" },
|
|
49
|
+
doctor: true,
|
|
50
|
+
},
|
|
51
|
+
{ name: "ANTHROPIC_API_KEY", vendor: "anthropic" },
|
|
52
|
+
{
|
|
53
|
+
name: "GH_TOKEN",
|
|
54
|
+
vendor: "github",
|
|
55
|
+
login: "gh auth login",
|
|
56
|
+
listed: { order: 3, use: "private repository subjects" },
|
|
57
|
+
doctor: true,
|
|
58
|
+
},
|
|
59
|
+
{ name: "GITHUB_TOKEN", spellingOf: "GH_TOKEN" },
|
|
60
|
+
{ name: "CODEX_API_KEY", doctor: true },
|
|
61
|
+
{ name: "AGENTMAIL_API_KEY", vendor: "agentmail", listed: { order: 4, use: "email in studies" } },
|
|
39
62
|
];
|
|
40
|
-
const PROVIDER_KEY_SET = new Set(
|
|
63
|
+
const PROVIDER_KEY_SET = new Set(PROVIDER_KEYS.map((key) => key.name));
|
|
64
|
+
const providerKey = (name) => PROVIDER_KEYS.find((key) => key.name === name);
|
|
65
|
+
/** The vendor aliases `humanish keys set` accepts. A raw ENV_NAME is also accepted. */
|
|
66
|
+
export const KEY_VENDORS = PROVIDER_KEYS.flatMap((key) => key.vendor === undefined ? [] : [key.vendor]);
|
|
67
|
+
/** The keys `humanish keys` lists, in its order, each with what humanish uses it for. */
|
|
68
|
+
export const LISTED_KEYS = PROVIDER_KEYS.flatMap(({ name, listed }) => listed === undefined ? [] : [{ name, ...listed }])
|
|
69
|
+
.sort((a, b) => a.order - b.order)
|
|
70
|
+
.map(({ name, use }) => ({ name, use }));
|
|
71
|
+
/** The keys `humanish doctor` reports on every run, in its row order. */
|
|
72
|
+
export const DOCTOR_KEYS = PROVIDER_KEYS.flatMap(({ name, doctor }) => (doctor ? [name] : []));
|
|
41
73
|
/** An env for a vendor CLI that discovery runs: the caller's, without any provider key name. */
|
|
42
74
|
function withoutProviderKeys(env) {
|
|
43
75
|
return Object.fromEntries(Object.entries(env).filter(([name]) => !PROVIDER_KEY_SET.has(name)));
|
|
44
76
|
}
|
|
45
|
-
/** `humanish keys set <vendor>` aliases; a raw ENV_NAME is also accepted. A Map, so a name such as
|
|
46
|
-
* `constructor` is no alias. */
|
|
47
|
-
const KEY_VENDOR_ALIASES = new Map([
|
|
48
|
-
["openai", "OPENAI_API_KEY"],
|
|
49
|
-
["e2b", "E2B_API_KEY"],
|
|
50
|
-
["anthropic", "ANTHROPIC_API_KEY"],
|
|
51
|
-
["github", "GH_TOKEN"],
|
|
52
|
-
["agentmail", "AGENTMAIL_API_KEY"],
|
|
53
|
-
]);
|
|
54
77
|
const PROJECT_OVERLAY_RELATIVE = path.join(".humanish", "local", "provider.env");
|
|
55
78
|
export function userKeyStorePath(env, deps = {}) {
|
|
56
79
|
return humanishConfigFile(env, "keys.env", deps.homeDir);
|
|
@@ -230,21 +253,10 @@ function storeLabel(env, deps) {
|
|
|
230
253
|
/** The nearest fill instruction for a missing key. Doctor rows use it, and it is appended to
|
|
231
254
|
* *_KEYS_MISSING errors so the failure names the fix. */
|
|
232
255
|
export function missingKeyHint(name) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
case "GITHUB_TOKEN":
|
|
238
|
-
return `run \`gh auth login\`, or \`${cli("keys set github")}\``;
|
|
239
|
-
case "OPENAI_API_KEY":
|
|
240
|
-
return `run \`${cli("keys set openai")}\``;
|
|
241
|
-
case "ANTHROPIC_API_KEY":
|
|
242
|
-
return `run \`${cli("keys set anthropic")}\``;
|
|
243
|
-
case "AGENTMAIL_API_KEY":
|
|
244
|
-
return `run \`${cli("keys set agentmail")}\``;
|
|
245
|
-
default:
|
|
246
|
-
return `run \`${cli(`keys set ${name}`)}\``;
|
|
247
|
-
}
|
|
256
|
+
const named = providerKey(name);
|
|
257
|
+
const key = named?.spellingOf === undefined ? named : providerKey(named.spellingOf);
|
|
258
|
+
const set = `\`${cli(`keys set ${key?.vendor ?? name}`)}\``;
|
|
259
|
+
return key?.login === undefined ? `run ${set}` : `run \`${key.login}\`, or ${set}`;
|
|
248
260
|
}
|
|
249
261
|
/** One shared suffix for *_KEYS_MISSING messages: where discovery looked, and what fills each
|
|
250
262
|
* missing key. Pure text; never values. */
|
|
@@ -276,19 +288,18 @@ export async function probeKeySources(names, args) {
|
|
|
276
288
|
...(args.deps === undefined ? {} : { deps: args.deps }),
|
|
277
289
|
});
|
|
278
290
|
const bySource = new Map(fills.map((fill) => [fill.name, fill.source]));
|
|
291
|
+
const setInEnv = (name) => args.env[name] !== undefined && args.env[name]?.trim() !== "";
|
|
279
292
|
return names.map((name) => {
|
|
280
|
-
const inEnv =
|
|
281
|
-
//
|
|
282
|
-
// "missing" while
|
|
283
|
-
const
|
|
284
|
-
args.env.GITHUB_TOKEN !== undefined &&
|
|
285
|
-
args.env.GITHUB_TOKEN.trim() !== "";
|
|
293
|
+
const inEnv = setInEnv(name) && !placeholder(name);
|
|
294
|
+
// A second spelling of the key in the env, such as GITHUB_TOKEN for GH_TOKEN, is the same
|
|
295
|
+
// credential; a doctor row that says "missing" while it sits in the env would be wrong.
|
|
296
|
+
const spelling = PROVIDER_KEYS.find((key) => key.spellingOf === name && setInEnv(key.name))?.name;
|
|
286
297
|
const source = inEnv
|
|
287
298
|
? args.dotenv?.names.includes(name)
|
|
288
299
|
? `--dotenv ${args.dotenv.path}`
|
|
289
300
|
: "process env"
|
|
290
|
-
:
|
|
291
|
-
?
|
|
301
|
+
: spelling !== undefined
|
|
302
|
+
? `process env (${spelling})`
|
|
292
303
|
: (bySource.get(name) ?? null);
|
|
293
304
|
return {
|
|
294
305
|
name,
|
|
@@ -301,9 +312,10 @@ export async function probeKeySources(names, args) {
|
|
|
301
312
|
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
302
313
|
/** Resolve a `humanish keys set` target: a vendor alias or a raw env name. Null = invalid. */
|
|
303
314
|
export function resolveKeyName(vendorOrName) {
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
315
|
+
const vendor = vendorOrName.toLowerCase();
|
|
316
|
+
const key = PROVIDER_KEYS.find((candidate) => candidate.vendor === vendor);
|
|
317
|
+
if (key !== undefined)
|
|
318
|
+
return key.name;
|
|
307
319
|
return ENV_NAME.test(vendorOrName) ? vendorOrName : null;
|
|
308
320
|
}
|
|
309
321
|
/** Write one key into the user store (0700 dir, 0600 file). Only allowlisted provider names
|
|
@@ -10,6 +10,8 @@ export declare function keyStatus(args: {
|
|
|
10
10
|
}): Promise<KeyStatusRow[]>;
|
|
11
11
|
/** Names in the user store that the status does not list, such as ANTHROPIC_API_KEY. */
|
|
12
12
|
export declare function otherStoredKeys(env: NodeJS.ProcessEnv, deps?: KeyResolutionDeps): string[];
|
|
13
|
+
/** The line `humanish keys` prints for one key: what it is for, and its source or how to add it. */
|
|
14
|
+
export declare function keyStatusLine(row: KeyStatusRow): string;
|
|
13
15
|
export declare function formatKeyStatus(rows: readonly KeyStatusRow[], otherStored?: readonly string[]): string;
|
|
14
16
|
interface MissingKeysOutcome {
|
|
15
17
|
stored: string[];
|
package/dist/keys/key-status.js
CHANGED
|
@@ -1,33 +1,26 @@
|
|
|
1
1
|
// `humanish keys`: which provider keys are set and where each comes from, through the same chain a
|
|
2
2
|
// live command resolves. Never a value.
|
|
3
3
|
import { cli } from "../cli/invocation.js";
|
|
4
|
-
import { listUserKeys, probeKeySources, setUserKey, } from "./key-resolution.js";
|
|
5
|
-
/**
|
|
6
|
-
* The keys a person sets for humanish, in the order the status lists them and `keys set` asks for
|
|
7
|
-
* them. ANTHROPIC_API_KEY is left out: a Claude Code participant runs on its own login and never
|
|
8
|
-
* receives it. CODEX_API_KEY is an alternative spelling of the OpenAI key for terminal studies.
|
|
9
|
-
*/
|
|
10
|
-
const STATUS_KEYS = [
|
|
11
|
-
{ name: "E2B_API_KEY", use: "hosted desktops" },
|
|
12
|
-
{ name: "OPENAI_API_KEY", use: "participant model and analysis" },
|
|
13
|
-
{ name: "GH_TOKEN", use: "private repository subjects" },
|
|
14
|
-
{ name: "AGENTMAIL_API_KEY", use: "email in studies" },
|
|
15
|
-
];
|
|
4
|
+
import { LISTED_KEYS, listUserKeys, probeKeySources, setUserKey, } from "./key-resolution.js";
|
|
16
5
|
export async function keyStatus(args) {
|
|
17
|
-
const probes = await probeKeySources(
|
|
6
|
+
const probes = await probeKeySources(LISTED_KEYS.map((key) => key.name), {
|
|
18
7
|
cwd: args.cwd,
|
|
19
8
|
env: args.env,
|
|
20
9
|
...(args.deps === undefined ? {} : { deps: args.deps }),
|
|
21
10
|
});
|
|
22
|
-
return probes.map((probe, index) => ({ ...probe, use:
|
|
11
|
+
return probes.map((probe, index) => ({ ...probe, use: LISTED_KEYS[index].use }));
|
|
23
12
|
}
|
|
24
13
|
/** Names in the user store that the status does not list, such as ANTHROPIC_API_KEY. */
|
|
25
14
|
export function otherStoredKeys(env, deps = {}) {
|
|
26
|
-
const listed = new Set(
|
|
15
|
+
const listed = new Set(LISTED_KEYS.map((key) => key.name));
|
|
27
16
|
return listUserKeys(env, deps).filter((name) => !listed.has(name));
|
|
28
17
|
}
|
|
18
|
+
/** The line `humanish keys` prints for one key: what it is for, and its source or how to add it. */
|
|
19
|
+
export function keyStatusLine(row) {
|
|
20
|
+
return `${row.name} (${row.use}): ${row.source === null ? `missing; ${row.hint}` : `set, from ${row.source}`}`;
|
|
21
|
+
}
|
|
29
22
|
export function formatKeyStatus(rows, otherStored = []) {
|
|
30
|
-
const lines = rows.map(
|
|
23
|
+
const lines = rows.map(keyStatusLine);
|
|
31
24
|
if (otherStored.length > 0)
|
|
32
25
|
lines.push(`Also in the user store: ${otherStored.join(", ")}. humanish does not use ${otherStored.length === 1 ? "it" : "them"} today.`);
|
|
33
26
|
const missing = rows.some((row) => row.source === null);
|
|
@@ -5,7 +5,7 @@ import { createHash } from "node:crypto";
|
|
|
5
5
|
import { constants as fsConstants } from "node:fs";
|
|
6
6
|
import { lstat, open, realpath } from "node:fs/promises";
|
|
7
7
|
import path from "node:path";
|
|
8
|
-
import { readOpenedAtMost } from "../run/
|
|
8
|
+
import { readOpenedAtMost } from "../run/contained-output.js";
|
|
9
9
|
import { isPathInside, isSafeRunIdSegment } from "../run/paths.js";
|
|
10
10
|
/**
|
|
11
11
|
* The file's bytes, or null when it cannot be read under the root's checks. With `maxBytes`, a
|
package/dist/observer/render.js
CHANGED
|
@@ -11,7 +11,7 @@ import { projectShareCheckedAnalysis } from "../analysis/sharing.js";
|
|
|
11
11
|
import { loadAnalysis } from "../analysis/load.js";
|
|
12
12
|
import { physicalCwdOf, runIdOf, bindExistingRunArtifactPaths, isSafeRunIdSegment, resolveLatestRunDirectory, validatePreparedRunArtifactPaths, } from "../run/paths.js";
|
|
13
13
|
import { writeContainedOutputFile } from "../run/contained-output.js";
|
|
14
|
-
import { loadRunBundlePrepared, readRunJsonIfExists } from "../run/locate.js";
|
|
14
|
+
import { loadRunBundlePrepared, readRunJsonIfExists, runJsonValue } from "../run/locate.js";
|
|
15
15
|
import { readRunNotes } from "../run/note-files.js";
|
|
16
16
|
import { RUN_STATUS_FILE } from "../run/status.js";
|
|
17
17
|
import { verifyRunPrepared } from "../verify/verify.js";
|
|
@@ -106,8 +106,9 @@ export async function renderObserver(cwdInput, runInput, options = {}) {
|
|
|
106
106
|
};
|
|
107
107
|
// A run.json without an outcome is in progress, interrupted, or older than the field: its
|
|
108
108
|
// status.json says which, and holds an older run's ok.
|
|
109
|
+
// A status.json it refuses says nothing, as a missing one does: the bundle's own facts show.
|
|
109
110
|
const statusRecord = loaded.bundle.outcome === undefined
|
|
110
|
-
? await readRunJsonIfExists(preparedRunPaths, RUN_STATUS_FILE)
|
|
111
|
+
? runJsonValue(await readRunJsonIfExists(preparedRunPaths, RUN_STATUS_FILE))
|
|
111
112
|
: undefined;
|
|
112
113
|
const observerData = buildObserverData(loaded.bundle, undefined, statusRecord);
|
|
113
114
|
observerData.publicSafety.share = {
|