@oharness/engine 0.1.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/dist/agent/agent.d.ts +196 -0
- package/dist/agent/agent.js +758 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/compaction.d.ts +68 -0
- package/dist/agent/compaction.js +179 -0
- package/dist/agent/compaction.js.map +1 -0
- package/dist/agent/hooks.d.ts +77 -0
- package/dist/agent/hooks.js +152 -0
- package/dist/agent/hooks.js.map +1 -0
- package/dist/agent/memory.d.ts +45 -0
- package/dist/agent/memory.js +147 -0
- package/dist/agent/memory.js.map +1 -0
- package/dist/agent/overflow.d.ts +35 -0
- package/dist/agent/overflow.js +69 -0
- package/dist/agent/overflow.js.map +1 -0
- package/dist/agent/permissions.d.ts +181 -0
- package/dist/agent/permissions.js +289 -0
- package/dist/agent/permissions.js.map +1 -0
- package/dist/agent/prompt.d.ts +25 -0
- package/dist/agent/prompt.js +63 -0
- package/dist/agent/prompt.js.map +1 -0
- package/dist/agent/session.d.ts +108 -0
- package/dist/agent/session.js +231 -0
- package/dist/agent/session.js.map +1 -0
- package/dist/agent/settings.d.ts +37 -0
- package/dist/agent/settings.js +113 -0
- package/dist/agent/settings.js.map +1 -0
- package/dist/agent/skills.d.ts +58 -0
- package/dist/agent/skills.js +225 -0
- package/dist/agent/skills.js.map +1 -0
- package/dist/agent/store.d.ts +308 -0
- package/dist/agent/store.js +596 -0
- package/dist/agent/store.js.map +1 -0
- package/dist/agent/subagent.d.ts +44 -0
- package/dist/agent/subagent.js +138 -0
- package/dist/agent/subagent.js.map +1 -0
- package/dist/agent/titles.d.ts +8 -0
- package/dist/agent/titles.js +23 -0
- package/dist/agent/titles.js.map +1 -0
- package/dist/agent/workspace.d.ts +60 -0
- package/dist/agent/workspace.js +156 -0
- package/dist/agent/workspace.js.map +1 -0
- package/dist/artifacts/publish.d.ts +94 -0
- package/dist/artifacts/publish.js +104 -0
- package/dist/artifacts/publish.js.map +1 -0
- package/dist/artifacts/store.d.ts +324 -0
- package/dist/artifacts/store.js +500 -0
- package/dist/artifacts/store.js.map +1 -0
- package/dist/auth/index.d.ts +13 -0
- package/dist/auth/index.js +10 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/manager.d.ts +83 -0
- package/dist/auth/manager.js +266 -0
- package/dist/auth/manager.js.map +1 -0
- package/dist/auth/oauth.d.ts +83 -0
- package/dist/auth/oauth.js +327 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/providers/account.d.ts +59 -0
- package/dist/auth/providers/account.js +282 -0
- package/dist/auth/providers/account.js.map +1 -0
- package/dist/auth/providers/anthropic.d.ts +24 -0
- package/dist/auth/providers/anthropic.js +209 -0
- package/dist/auth/providers/anthropic.js.map +1 -0
- package/dist/auth/providers/generic.d.ts +57 -0
- package/dist/auth/providers/generic.js +155 -0
- package/dist/auth/providers/generic.js.map +1 -0
- package/dist/auth/providers/official.d.ts +3 -0
- package/dist/auth/providers/official.js +90 -0
- package/dist/auth/providers/official.js.map +1 -0
- package/dist/auth/providers/ottoport.d.ts +3 -0
- package/dist/auth/providers/ottoport.js +60 -0
- package/dist/auth/providers/ottoport.js.map +1 -0
- package/dist/auth/store.d.ts +22 -0
- package/dist/auth/store.js +138 -0
- package/dist/auth/store.js.map +1 -0
- package/dist/auth/types.d.ts +167 -0
- package/dist/auth/types.js +16 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/config.d.ts +197 -0
- package/dist/config.js +195 -0
- package/dist/config.js.map +1 -0
- package/dist/core/errors.d.ts +46 -0
- package/dist/core/errors.js +83 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/tokens.d.ts +12 -0
- package/dist/core/tokens.js +56 -0
- package/dist/core/tokens.js.map +1 -0
- package/dist/core/types.d.ts +91 -0
- package/dist/core/types.js +49 -0
- package/dist/core/types.js.map +1 -0
- package/dist/harness.d.ts +302 -0
- package/dist/harness.js +695 -0
- package/dist/harness.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +55 -0
- package/dist/mcp/client.js +199 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/index.d.ts +13 -0
- package/dist/mcp/index.js +8 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/manager.d.ts +77 -0
- package/dist/mcp/manager.js +325 -0
- package/dist/mcp/manager.js.map +1 -0
- package/dist/mcp/oauth.d.ts +63 -0
- package/dist/mcp/oauth.js +302 -0
- package/dist/mcp/oauth.js.map +1 -0
- package/dist/mcp/protocol.d.ts +130 -0
- package/dist/mcp/protocol.js +14 -0
- package/dist/mcp/protocol.js.map +1 -0
- package/dist/mcp/registry.d.ts +52 -0
- package/dist/mcp/registry.js +100 -0
- package/dist/mcp/registry.js.map +1 -0
- package/dist/mcp/registry.json +293 -0
- package/dist/mcp/secrets.d.ts +20 -0
- package/dist/mcp/secrets.js +75 -0
- package/dist/mcp/secrets.js.map +1 -0
- package/dist/mcp/transport.d.ts +51 -0
- package/dist/mcp/transport.js +158 -0
- package/dist/mcp/transport.js.map +1 -0
- package/dist/paths.d.ts +37 -0
- package/dist/paths.js +63 -0
- package/dist/paths.js.map +1 -0
- package/dist/plugins.d.ts +55 -0
- package/dist/plugins.js +201 -0
- package/dist/plugins.js.map +1 -0
- package/dist/providers/builtin.d.ts +23 -0
- package/dist/providers/builtin.js +141 -0
- package/dist/providers/builtin.js.map +1 -0
- package/dist/providers/catalog.d.ts +129 -0
- package/dist/providers/catalog.js +254 -0
- package/dist/providers/catalog.js.map +1 -0
- package/dist/providers/catalog.json +472 -0
- package/dist/providers/discovery.d.ts +16 -0
- package/dist/providers/discovery.js +161 -0
- package/dist/providers/discovery.js.map +1 -0
- package/dist/providers/http.d.ts +24 -0
- package/dist/providers/http.js +139 -0
- package/dist/providers/http.js.map +1 -0
- package/dist/providers/index.d.ts +10 -0
- package/dist/providers/index.js +8 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/piai.d.ts +124 -0
- package/dist/providers/piai.js +551 -0
- package/dist/providers/piai.js.map +1 -0
- package/dist/providers/registry.d.ts +65 -0
- package/dist/providers/registry.js +195 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/resilient.d.ts +46 -0
- package/dist/providers/resilient.js +117 -0
- package/dist/providers/resilient.js.map +1 -0
- package/dist/providers/types.d.ts +182 -0
- package/dist/providers/types.js +50 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/schedule/cron.d.ts +35 -0
- package/dist/schedule/cron.js +125 -0
- package/dist/schedule/cron.js.map +1 -0
- package/dist/schedule/scheduler.d.ts +87 -0
- package/dist/schedule/scheduler.js +237 -0
- package/dist/schedule/scheduler.js.map +1 -0
- package/dist/storage/kv.d.ts +56 -0
- package/dist/storage/kv.js +173 -0
- package/dist/storage/kv.js.map +1 -0
- package/dist/storage/migrate.d.ts +11 -0
- package/dist/storage/migrate.js +93 -0
- package/dist/storage/migrate.js.map +1 -0
- package/dist/storage/project.d.ts +9 -0
- package/dist/storage/project.js +57 -0
- package/dist/storage/project.js.map +1 -0
- package/dist/storage/records.d.ts +32 -0
- package/dist/storage/records.js +48 -0
- package/dist/storage/records.js.map +1 -0
- package/dist/sync/client.d.ts +79 -0
- package/dist/sync/client.js +118 -0
- package/dist/sync/client.js.map +1 -0
- package/dist/sync/mirror.d.ts +85 -0
- package/dist/sync/mirror.js +389 -0
- package/dist/sync/mirror.js.map +1 -0
- package/dist/sync/protocol.d.ts +67 -0
- package/dist/sync/protocol.js +16 -0
- package/dist/sync/protocol.js.map +1 -0
- package/dist/sync/settings.d.ts +56 -0
- package/dist/sync/settings.js +60 -0
- package/dist/sync/settings.js.map +1 -0
- package/dist/tools/builtin/artifact.d.ts +16 -0
- package/dist/tools/builtin/artifact.js +134 -0
- package/dist/tools/builtin/artifact.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts +3 -0
- package/dist/tools/builtin/bash.js +142 -0
- package/dist/tools/builtin/bash.js.map +1 -0
- package/dist/tools/builtin/fs.d.ts +19 -0
- package/dist/tools/builtin/fs.js +280 -0
- package/dist/tools/builtin/fs.js.map +1 -0
- package/dist/tools/builtin/index.d.ts +22 -0
- package/dist/tools/builtin/index.js +42 -0
- package/dist/tools/builtin/index.js.map +1 -0
- package/dist/tools/builtin/mcp-resource.d.ts +3 -0
- package/dist/tools/builtin/mcp-resource.js +220 -0
- package/dist/tools/builtin/mcp-resource.js.map +1 -0
- package/dist/tools/builtin/memory.d.ts +10 -0
- package/dist/tools/builtin/memory.js +76 -0
- package/dist/tools/builtin/memory.js.map +1 -0
- package/dist/tools/builtin/recall.d.ts +13 -0
- package/dist/tools/builtin/recall.js +163 -0
- package/dist/tools/builtin/recall.js.map +1 -0
- package/dist/tools/builtin/search.d.ts +3 -0
- package/dist/tools/builtin/search.js +240 -0
- package/dist/tools/builtin/search.js.map +1 -0
- package/dist/tools/builtin/skill.d.ts +10 -0
- package/dist/tools/builtin/skill.js +46 -0
- package/dist/tools/builtin/skill.js.map +1 -0
- package/dist/tools/builtin/task.d.ts +9 -0
- package/dist/tools/builtin/task.js +68 -0
- package/dist/tools/builtin/task.js.map +1 -0
- package/dist/tools/builtin/todo.d.ts +20 -0
- package/dist/tools/builtin/todo.js +63 -0
- package/dist/tools/builtin/todo.js.map +1 -0
- package/dist/tools/define.d.ts +19 -0
- package/dist/tools/define.js +39 -0
- package/dist/tools/define.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/registry.d.ts +39 -0
- package/dist/tools/registry.js +101 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/types.d.ts +112 -0
- package/dist/tools/types.js +22 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/util/id.d.ts +9 -0
- package/dist/util/id.js +19 -0
- package/dist/util/id.js.map +1 -0
- package/dist/util/json.d.ts +25 -0
- package/dist/util/json.js +100 -0
- package/dist/util/json.js.map +1 -0
- package/dist/util/jwt.d.ts +74 -0
- package/dist/util/jwt.js +177 -0
- package/dist/util/jwt.js.map +1 -0
- package/dist/util/logger.d.ts +13 -0
- package/dist/util/logger.js +59 -0
- package/dist/util/logger.js.map +1 -0
- package/dist/util/queue.d.ts +26 -0
- package/dist/util/queue.js +106 -0
- package/dist/util/queue.js.map +1 -0
- package/dist/util/schema.d.ts +17 -0
- package/dist/util/schema.js +98 -0
- package/dist/util/schema.js.map +1 -0
- package/dist/util/shell.d.ts +20 -0
- package/dist/util/shell.js +24 -0
- package/dist/util/shell.js.map +1 -0
- package/official.json +4 -0
- package/package.json +38 -0
- package/skills/artifact-authoring/SKILL.md +81 -0
- package/skills/canvas/SKILL.md +85 -0
- package/skills/skill-authoring/SKILL.md +85 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { errorMessage } from "../../core/errors.js";
|
|
5
|
+
import { userPath } from "../../paths.js";
|
|
6
|
+
import { parseJson } from "../../util/json.js";
|
|
7
|
+
/**
|
|
8
|
+
* Read once, and lazily: most runs of the CLI never sign in, and a synchronous
|
|
9
|
+
* read at module load would put a stat on the start-up path of all of them.
|
|
10
|
+
*
|
|
11
|
+
* `..` three times from either `src/auth/providers` or `dist/auth/providers`
|
|
12
|
+
* lands on the package root, which is why the file sits there — the same trick
|
|
13
|
+
* agent/skills.ts uses to find the skills directory.
|
|
14
|
+
*/
|
|
15
|
+
let packaged;
|
|
16
|
+
let configured;
|
|
17
|
+
function readJsonFile(file) {
|
|
18
|
+
try {
|
|
19
|
+
const parsed = parseJson(readFileSync(file, "utf8"));
|
|
20
|
+
return parsed.ok ? parsed.value : {};
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Absent or unreadable. Both are ordinary, and neither is this layer's
|
|
24
|
+
// business to complain about.
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** The ids this build was packaged with, if it was packaged with any. */
|
|
29
|
+
function fromPackage() {
|
|
30
|
+
if (packaged)
|
|
31
|
+
return packaged;
|
|
32
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
33
|
+
packaged = readJsonFile(path.resolve(here, "..", "..", "..", "official.json"));
|
|
34
|
+
return packaged;
|
|
35
|
+
}
|
|
36
|
+
/** The `account` section of the user's own config file. */
|
|
37
|
+
function fromUserConfig() {
|
|
38
|
+
if (configured)
|
|
39
|
+
return configured;
|
|
40
|
+
const file = readJsonFile(userPath("config.json"));
|
|
41
|
+
configured = file.account ?? {};
|
|
42
|
+
return configured;
|
|
43
|
+
}
|
|
44
|
+
function configuredUrl() {
|
|
45
|
+
const value = process.env["OHARNESS_SUPABASE_URL"] ||
|
|
46
|
+
fromUserConfig().supabaseUrl ||
|
|
47
|
+
fromPackage().supabaseUrl ||
|
|
48
|
+
"";
|
|
49
|
+
return value.replace(/\/+$/, "");
|
|
50
|
+
}
|
|
51
|
+
function configuredKey() {
|
|
52
|
+
return (process.env["OHARNESS_SUPABASE_ANON_KEY"] ||
|
|
53
|
+
fromUserConfig().supabaseAnonKey ||
|
|
54
|
+
fromPackage().supabaseAnonKey ||
|
|
55
|
+
"");
|
|
56
|
+
}
|
|
57
|
+
/** Whether this build knows an account project to talk to at all. */
|
|
58
|
+
export function accountsConfigured() {
|
|
59
|
+
return Boolean(configuredUrl() && configuredKey());
|
|
60
|
+
}
|
|
61
|
+
// Names the config file first, because for anyone running their own fork that
|
|
62
|
+
// is the answer, and an error that only mentions environment variables sends
|
|
63
|
+
// them off to arrange an export that will not survive their next shell.
|
|
64
|
+
const NO_ACCOUNTS = 'no account project is configured. Add {"account":{"supabaseUrl":"…","supabaseAnonKey":"…"}} to ~/.oharness/config.json, or set OHARNESS_SUPABASE_URL and OHARNESS_SUPABASE_ANON_KEY.';
|
|
65
|
+
export function supabaseUrl() {
|
|
66
|
+
const url = configuredUrl();
|
|
67
|
+
if (!url)
|
|
68
|
+
throw new Error(NO_ACCOUNTS);
|
|
69
|
+
return url;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The OHarness site — where accounts are made, paid for, and signed into.
|
|
73
|
+
*
|
|
74
|
+
* A deployment moves it the same way it moves the gateway, and a local `next
|
|
75
|
+
* dev` on port 4000 is the reason this is not a constant.
|
|
76
|
+
*/
|
|
77
|
+
const DEFAULT_SITE_URL = "https://oharness.ai";
|
|
78
|
+
export function siteUrl() {
|
|
79
|
+
// Same order as the project ids above, and it has to be: the browser sign-in
|
|
80
|
+
// hands a session back from whichever site owns those accounts, so a fork
|
|
81
|
+
// that moved the project and not the site would send people to ours to sign
|
|
82
|
+
// in to theirs.
|
|
83
|
+
const value = process.env["OHARNESS_SITE_URL"] ||
|
|
84
|
+
fromUserConfig().siteUrl ||
|
|
85
|
+
fromPackage().siteUrl ||
|
|
86
|
+
DEFAULT_SITE_URL;
|
|
87
|
+
return value.replace(/\/+$/, "");
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Signing in by sending the user to the site, in their own browser.
|
|
91
|
+
*
|
|
92
|
+
* The emailed code below works from anywhere, which is why it is still here —
|
|
93
|
+
* a terminal over SSH has no browser to open. But on a machine that does have
|
|
94
|
+
* one, sending them to the site's own login is strictly better: it is the page
|
|
95
|
+
* that offers a password and Google, it is the page that knows how to sign
|
|
96
|
+
* someone *up*, and neither of those has to be reimplemented here to stay
|
|
97
|
+
* working.
|
|
98
|
+
*
|
|
99
|
+
* What comes back is a sealed code on a loopback redirect, traded for the
|
|
100
|
+
* session over HTTPS. The frontend owns the loopback listener because it is
|
|
101
|
+
* the one already running a local server; this pair of functions is the part
|
|
102
|
+
* that belongs to the account rather than to any one frontend.
|
|
103
|
+
*/
|
|
104
|
+
export function browserSignInUrl(opts) {
|
|
105
|
+
const url = new URL("/auth/desktop", `${siteUrl()}/`);
|
|
106
|
+
url.searchParams.set("state", opts.state);
|
|
107
|
+
url.searchParams.set("redirect_uri", opts.redirectUri);
|
|
108
|
+
if (opts.locale)
|
|
109
|
+
url.searchParams.set("locale", opts.locale);
|
|
110
|
+
return url.toString();
|
|
111
|
+
}
|
|
112
|
+
/** Trade a sealed handoff code for the session it stands for. */
|
|
113
|
+
export async function exchangeHandoff(code, state) {
|
|
114
|
+
let response;
|
|
115
|
+
try {
|
|
116
|
+
response = await fetch(`${siteUrl()}/api/desktop/exchange`, {
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
119
|
+
body: JSON.stringify({ code, state }),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
// A site that cannot be reached is the common failure here — offline, or
|
|
124
|
+
// OHARNESS_SITE_URL pointing at a dev server that is not running — and it
|
|
125
|
+
// deserves better than "sign-in failed".
|
|
126
|
+
return { type: "failed", error: `could not reach ${siteUrl()}: ${errorMessage(err)}` };
|
|
127
|
+
}
|
|
128
|
+
const body = parseJson(await response.text());
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
return {
|
|
131
|
+
type: "failed",
|
|
132
|
+
error: (body.ok && body.value.error) || `the site refused the sign-in (HTTP ${response.status})`,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (!body.ok || !body.value.access_token || !body.value.refresh_token) {
|
|
136
|
+
return { type: "failed", error: "the site returned no session" };
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
type: "success",
|
|
140
|
+
access: body.value.access_token,
|
|
141
|
+
refresh: body.value.refresh_token,
|
|
142
|
+
expires: body.value.expires_at ?? 0,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function supabaseKey() {
|
|
146
|
+
const key = configuredKey();
|
|
147
|
+
if (!key)
|
|
148
|
+
throw new Error(NO_ACCOUNTS);
|
|
149
|
+
return key;
|
|
150
|
+
}
|
|
151
|
+
/** Every Supabase auth call carries the anon key as well as any bearer token. */
|
|
152
|
+
export function supabaseHeaders() {
|
|
153
|
+
return {
|
|
154
|
+
apikey: supabaseKey(),
|
|
155
|
+
"content-type": "application/json",
|
|
156
|
+
accept: "application/json",
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/** The emailed-code sign-in, as an OAuth method a provider can declare. */
|
|
160
|
+
export function accountSignIn(label) {
|
|
161
|
+
return {
|
|
162
|
+
type: "oauth",
|
|
163
|
+
label,
|
|
164
|
+
prompts: [
|
|
165
|
+
{
|
|
166
|
+
type: "text",
|
|
167
|
+
key: "email",
|
|
168
|
+
message: "Email on your OHarness account",
|
|
169
|
+
placeholder: "you@example.com",
|
|
170
|
+
validate: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) ? undefined : "that does not look like an email",
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
async authorize(inputs) {
|
|
174
|
+
const email = (inputs["email"] ?? "").trim();
|
|
175
|
+
const response = await fetch(`${supabaseUrl()}/auth/v1/otp`, {
|
|
176
|
+
method: "POST",
|
|
177
|
+
headers: supabaseHeaders(),
|
|
178
|
+
// Signing up is the website's job: a subscription has to be paid for
|
|
179
|
+
// before it can be signed into, and silently creating an account
|
|
180
|
+
// here would hand out a login that cannot call anything.
|
|
181
|
+
body: JSON.stringify({ email, create_user: false }),
|
|
182
|
+
});
|
|
183
|
+
if (!response.ok) {
|
|
184
|
+
const detail = await failureDetail(response);
|
|
185
|
+
// GoTrue phrases "this address has no account" as a signup refusal,
|
|
186
|
+
// which reads as a bug in the client to anyone who does have one.
|
|
187
|
+
const noAccount = /signups? not allowed/i.test(detail);
|
|
188
|
+
throw new Error(noAccount
|
|
189
|
+
? `no OHarness account for ${email}. Sign up on the OHarness site first, then sign in here.`
|
|
190
|
+
: `could not send the sign-in code to ${email}: ${detail}`);
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
method: "code",
|
|
194
|
+
instructions: `We emailed a sign-in code to ${email}. Paste it here — the code, not the link.`,
|
|
195
|
+
// No page to open: the code arrives by email, and sending a browser
|
|
196
|
+
// to the login form would only invite a second, competing session.
|
|
197
|
+
async callback(code) {
|
|
198
|
+
try {
|
|
199
|
+
return await verifyOtp(email, code);
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
return { type: "failed", error: errorMessage(err) };
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/** Exchange the emailed code for a session. */
|
|
210
|
+
export async function verifyOtp(email, code) {
|
|
211
|
+
const response = await fetch(`${supabaseUrl()}/auth/v1/verify`, {
|
|
212
|
+
method: "POST",
|
|
213
|
+
headers: supabaseHeaders(),
|
|
214
|
+
body: JSON.stringify({ email, token: code.trim(), type: "email" }),
|
|
215
|
+
});
|
|
216
|
+
if (!response.ok) {
|
|
217
|
+
return { type: "failed", error: await failureDetail(response) };
|
|
218
|
+
}
|
|
219
|
+
const session = parseJson(await response.text());
|
|
220
|
+
if (!session.ok || !session.value.access_token) {
|
|
221
|
+
return { type: "failed", error: "the sign-in returned no access token" };
|
|
222
|
+
}
|
|
223
|
+
const credential = toCredential(session.value);
|
|
224
|
+
return {
|
|
225
|
+
type: "success",
|
|
226
|
+
access: credential.access,
|
|
227
|
+
refresh: credential.refresh,
|
|
228
|
+
expires: credential.expires,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/** Trade a refresh token for a fresh session, or nothing if it is still good. */
|
|
232
|
+
export async function refreshSession(credential) {
|
|
233
|
+
if (!credential.refresh)
|
|
234
|
+
return undefined;
|
|
235
|
+
// GoTrue takes the grant type in the query string and the body as JSON,
|
|
236
|
+
// so the generic form-encoded OAuth refresh does not fit.
|
|
237
|
+
const response = await fetch(`${supabaseUrl()}/auth/v1/token?grant_type=refresh_token`, {
|
|
238
|
+
method: "POST",
|
|
239
|
+
headers: supabaseHeaders(),
|
|
240
|
+
body: JSON.stringify({ refresh_token: credential.refresh }),
|
|
241
|
+
});
|
|
242
|
+
if (!response.ok) {
|
|
243
|
+
throw new Error(`subscription refresh failed: ${await failureDetail(response)}`);
|
|
244
|
+
}
|
|
245
|
+
const session = parseJson(await response.text());
|
|
246
|
+
if (!session.ok || !session.value.access_token) {
|
|
247
|
+
throw new Error("subscription refresh returned no access token");
|
|
248
|
+
}
|
|
249
|
+
return toCredential(session.value, credential);
|
|
250
|
+
}
|
|
251
|
+
export function toCredential(session, previous) {
|
|
252
|
+
return {
|
|
253
|
+
type: "oauth",
|
|
254
|
+
access: session.access_token,
|
|
255
|
+
// GoTrue rotates the refresh token on every use, but keep the previous one
|
|
256
|
+
// if a response ever omits it — dropping it ends the session at expiry.
|
|
257
|
+
refresh: session.refresh_token ?? previous?.refresh ?? "",
|
|
258
|
+
expires: session.expires_in ? Date.now() + session.expires_in * 1_000 : 0,
|
|
259
|
+
...(previous?.baseUrl ? { baseUrl: previous.baseUrl } : {}),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* GoTrue reports failures under several field names depending on the version
|
|
264
|
+
* and the error class. Probing them beats showing a bare status code, which is
|
|
265
|
+
* what "sign-in failed (400)" leaves the user debugging.
|
|
266
|
+
*/
|
|
267
|
+
export async function failureDetail(response) {
|
|
268
|
+
const text = await response.text();
|
|
269
|
+
const parsed = parseJson(text);
|
|
270
|
+
const detail = parsed.ok
|
|
271
|
+
? (parsed.value.error_description ??
|
|
272
|
+
parsed.value.msg ??
|
|
273
|
+
parsed.value.message ??
|
|
274
|
+
parsed.value.error)
|
|
275
|
+
: undefined;
|
|
276
|
+
return `HTTP ${response.status}${detail ? `: ${detail}` : ` ${text.slice(0, 200)}`}`;
|
|
277
|
+
}
|
|
278
|
+
/** The bearer shape both account-backed providers resolve to. */
|
|
279
|
+
export function bearer(token, source) {
|
|
280
|
+
return { headers: { authorization: `Bearer ${token}` }, source };
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=account.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account.js","sourceRoot":"","sources":["../../../src/auth/providers/account.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AuthProvider } from "../types.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Anthropic authentication.
|
|
4
|
+
*
|
|
5
|
+
* Subscription/OAuth support here deliberately piggybacks on the official
|
|
6
|
+
* `ant` CLI rather than reimplementing a login flow: `ant auth login` already
|
|
7
|
+
* runs the browser flow, stores a profile under the Anthropic config
|
|
8
|
+
* directory, and refreshes tokens. Re-deriving that with a hardcoded client id
|
|
9
|
+
* would mean impersonating another application's OAuth registration.
|
|
10
|
+
*
|
|
11
|
+
* Credential precedence matches the documented SDK chain, first match wins:
|
|
12
|
+
* ANTHROPIC_API_KEY → ANTHROPIC_AUTH_TOKEN → ant profile → stored API key
|
|
13
|
+
*/
|
|
14
|
+
export declare const anthropicAuth: AuthProvider;
|
|
15
|
+
/** Sentinel meaning "the credential lives in the ant profile, go ask it". */
|
|
16
|
+
export declare const ANT_PROFILE_MARKER = "__ant_cli_profile__";
|
|
17
|
+
/**
|
|
18
|
+
* Ask the `ant` CLI for a short-lived access token.
|
|
19
|
+
*
|
|
20
|
+
* `print-credentials --access-token` prints a bare token and refreshes it if
|
|
21
|
+
* needed. Without the flag it prints the whole credentials JSON, which is a
|
|
22
|
+
* common way to end up sending a JSON blob as an Authorization header.
|
|
23
|
+
*/
|
|
24
|
+
export declare function antAccessToken(): Promise<string | undefined>;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { parseJson } from "../../util/json.js";
|
|
7
|
+
import { isExpired } from "../types.js";
|
|
8
|
+
const run = promisify(execFile);
|
|
9
|
+
/**
|
|
10
|
+
* The beta flag the API requires when authenticating with an OAuth bearer
|
|
11
|
+
* token instead of an API key. Without it `/v1/messages` rejects the request.
|
|
12
|
+
*/
|
|
13
|
+
const OAUTH_BETA = "oauth-2025-04-20";
|
|
14
|
+
/**
|
|
15
|
+
* Anthropic authentication.
|
|
16
|
+
*
|
|
17
|
+
* Subscription/OAuth support here deliberately piggybacks on the official
|
|
18
|
+
* `ant` CLI rather than reimplementing a login flow: `ant auth login` already
|
|
19
|
+
* runs the browser flow, stores a profile under the Anthropic config
|
|
20
|
+
* directory, and refreshes tokens. Re-deriving that with a hardcoded client id
|
|
21
|
+
* would mean impersonating another application's OAuth registration.
|
|
22
|
+
*
|
|
23
|
+
* Credential precedence matches the documented SDK chain, first match wins:
|
|
24
|
+
* ANTHROPIC_API_KEY → ANTHROPIC_AUTH_TOKEN → ant profile → stored API key
|
|
25
|
+
*/
|
|
26
|
+
export const anthropicAuth = {
|
|
27
|
+
id: "anthropic",
|
|
28
|
+
label: "Anthropic",
|
|
29
|
+
methods: [
|
|
30
|
+
{
|
|
31
|
+
type: "api",
|
|
32
|
+
label: "API key",
|
|
33
|
+
prompts: [
|
|
34
|
+
{
|
|
35
|
+
type: "text",
|
|
36
|
+
key: "key",
|
|
37
|
+
message: "Anthropic API key",
|
|
38
|
+
placeholder: "sk-ant-…",
|
|
39
|
+
secret: true,
|
|
40
|
+
validate: (value) => value.startsWith("sk-ant-") ? undefined : "expected a key starting with sk-ant-",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: "api",
|
|
46
|
+
label: "Subscription via the `ant` CLI (run `ant auth login` first)",
|
|
47
|
+
// No prompts: the credential lives in the ant profile, we just verify it.
|
|
48
|
+
async authorize() {
|
|
49
|
+
const token = await antAccessToken();
|
|
50
|
+
if (!token) {
|
|
51
|
+
return {
|
|
52
|
+
type: "failed",
|
|
53
|
+
error: "no active `ant` credential found. Install the Anthropic CLI and run `ant auth login`, then retry.",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Store a marker rather than the token: `ant` owns refresh, and a copy
|
|
57
|
+
// here would go stale within the hour.
|
|
58
|
+
return { type: "success", key: ANT_PROFILE_MARKER, metadata: { source: "ant-cli" } };
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
async loader(credential, ctx) {
|
|
63
|
+
void ctx;
|
|
64
|
+
// 1. An explicit API key in the environment outranks everything.
|
|
65
|
+
const envKey = process.env["ANTHROPIC_API_KEY"];
|
|
66
|
+
if (envKey)
|
|
67
|
+
return apiKeyAuth(envKey, "env:ANTHROPIC_API_KEY");
|
|
68
|
+
// 2. A bearer token in the environment. Never send both — the API rejects
|
|
69
|
+
// a request carrying an API key and a bearer token together.
|
|
70
|
+
const envToken = process.env["ANTHROPIC_AUTH_TOKEN"];
|
|
71
|
+
if (envToken)
|
|
72
|
+
return bearerAuth(envToken, "env:ANTHROPIC_AUTH_TOKEN");
|
|
73
|
+
// 3. A credential we stored ourselves.
|
|
74
|
+
if (credential?.type === "oauth" && !isExpired(credential)) {
|
|
75
|
+
return bearerAuth(credential.access, "stored:oauth");
|
|
76
|
+
}
|
|
77
|
+
if (credential?.type === "api" && credential.key !== ANT_PROFILE_MARKER) {
|
|
78
|
+
return apiKeyAuth(credential.key, "stored:api");
|
|
79
|
+
}
|
|
80
|
+
// 4. The `ant` CLI profile. Asked last because the env vars shadow it, and
|
|
81
|
+
// it costs a subprocess.
|
|
82
|
+
const token = await antAccessToken();
|
|
83
|
+
if (token)
|
|
84
|
+
return bearerAuth(token, "ant-cli");
|
|
85
|
+
return undefined;
|
|
86
|
+
},
|
|
87
|
+
async refresh(credential) {
|
|
88
|
+
// Tokens sourced from the ant profile are refreshed by ant itself; the
|
|
89
|
+
// loader re-reads them on every request, so there is nothing to do here.
|
|
90
|
+
void credential;
|
|
91
|
+
return undefined;
|
|
92
|
+
},
|
|
93
|
+
async discover() {
|
|
94
|
+
const envKey = process.env["ANTHROPIC_API_KEY"];
|
|
95
|
+
if (envKey)
|
|
96
|
+
return { credential: { type: "api", key: envKey }, source: "env:ANTHROPIC_API_KEY" };
|
|
97
|
+
const token = await antAccessToken();
|
|
98
|
+
if (token) {
|
|
99
|
+
return {
|
|
100
|
+
credential: { type: "api", key: ANT_PROFILE_MARKER, metadata: { source: "ant-cli" } },
|
|
101
|
+
source: "ant-cli",
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return undefined;
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
/** Sentinel meaning "the credential lives in the ant profile, go ask it". */
|
|
108
|
+
export const ANT_PROFILE_MARKER = "__ant_cli_profile__";
|
|
109
|
+
function apiKeyAuth(key, source) {
|
|
110
|
+
return {
|
|
111
|
+
headers: { "x-api-key": key },
|
|
112
|
+
// Strip any bearer header a previous resolution may have set.
|
|
113
|
+
removeHeaders: ["authorization"],
|
|
114
|
+
source,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function bearerAuth(token, source) {
|
|
118
|
+
return {
|
|
119
|
+
headers: {
|
|
120
|
+
authorization: `Bearer ${token}`,
|
|
121
|
+
// OAuth bearer auth is gated behind this beta flag.
|
|
122
|
+
"anthropic-beta": OAUTH_BETA,
|
|
123
|
+
},
|
|
124
|
+
// Sending x-api-key alongside a bearer token is rejected.
|
|
125
|
+
removeHeaders: ["x-api-key"],
|
|
126
|
+
source,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Ask the `ant` CLI for a short-lived access token.
|
|
131
|
+
*
|
|
132
|
+
* `print-credentials --access-token` prints a bare token and refreshes it if
|
|
133
|
+
* needed. Without the flag it prints the whole credentials JSON, which is a
|
|
134
|
+
* common way to end up sending a JSON blob as an Authorization header.
|
|
135
|
+
*/
|
|
136
|
+
export async function antAccessToken() {
|
|
137
|
+
const args = ["auth", "print-credentials", "--access-token"];
|
|
138
|
+
const profile = process.env["ANTHROPIC_PROFILE"];
|
|
139
|
+
if (profile)
|
|
140
|
+
args.push("--profile", profile);
|
|
141
|
+
try {
|
|
142
|
+
const { stdout } = await run("ant", args, { timeout: 10_000, encoding: "utf8" });
|
|
143
|
+
const token = stdout.trim();
|
|
144
|
+
// Guard against the no-flag JSON output sneaking through.
|
|
145
|
+
return token && !token.startsWith("{") ? token : undefined;
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// ant not installed, or no active credential — fall back to the file.
|
|
149
|
+
return antTokenFromDisk();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Best-effort read of the credential file the `ant` CLI writes, for hosts
|
|
154
|
+
* where the binary is unavailable but the profile exists. Field names are
|
|
155
|
+
* probed rather than assumed, and an expired token is treated as absent since
|
|
156
|
+
* we cannot refresh it without the CLI.
|
|
157
|
+
*/
|
|
158
|
+
async function antTokenFromDisk() {
|
|
159
|
+
const dir = antConfigDir();
|
|
160
|
+
const profile = process.env["ANTHROPIC_PROFILE"];
|
|
161
|
+
const candidates = [];
|
|
162
|
+
if (profile)
|
|
163
|
+
candidates.push(path.join(dir, "credentials", `${profile}.json`));
|
|
164
|
+
candidates.push(path.join(dir, "credentials", "default.json"));
|
|
165
|
+
try {
|
|
166
|
+
for (const name of await readdir(path.join(dir, "credentials"))) {
|
|
167
|
+
if (name.endsWith(".json"))
|
|
168
|
+
candidates.push(path.join(dir, "credentials", name));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// No credentials directory: nothing to read.
|
|
173
|
+
}
|
|
174
|
+
for (const file of candidates) {
|
|
175
|
+
let raw;
|
|
176
|
+
try {
|
|
177
|
+
raw = await readFile(file, "utf8");
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const parsed = parseJson(raw);
|
|
183
|
+
if (!parsed.ok)
|
|
184
|
+
continue;
|
|
185
|
+
const token = parsed.value.access_token ?? parsed.value.accessToken;
|
|
186
|
+
if (typeof token !== "string" || token === "")
|
|
187
|
+
continue;
|
|
188
|
+
const expiry = parsed.value.expires_at ?? parsed.value.expiresAt;
|
|
189
|
+
if (expiry !== undefined) {
|
|
190
|
+
const at = typeof expiry === "number" ? expiry : Date.parse(String(expiry));
|
|
191
|
+
// Values may be seconds or milliseconds; normalize before comparing.
|
|
192
|
+
const ms = Number.isFinite(at) ? (at < 1e12 ? at * 1_000 : at) : undefined;
|
|
193
|
+
if (ms !== undefined && ms <= Date.now())
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
return token;
|
|
197
|
+
}
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
function antConfigDir() {
|
|
201
|
+
const explicit = process.env["ANTHROPIC_CONFIG_DIR"];
|
|
202
|
+
if (explicit)
|
|
203
|
+
return explicit;
|
|
204
|
+
if (process.platform === "win32") {
|
|
205
|
+
return path.join(process.env["APPDATA"] ?? homedir(), "Anthropic");
|
|
206
|
+
}
|
|
207
|
+
return path.join(homedir(), ".config", "anthropic");
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/auth/providers/anthropic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { AuthProvider } from "../types.ts";
|
|
2
|
+
/** Build a plain API-key auth provider. */
|
|
3
|
+
export declare function apiKeyProvider(opts: {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
/** Env vars consulted in order before falling back to stored credentials. */
|
|
7
|
+
envVars?: string[];
|
|
8
|
+
/** Header carrying the key. Defaults to `authorization: Bearer <key>`. */
|
|
9
|
+
header?: string;
|
|
10
|
+
/** Format the header value. Defaults to `Bearer <key>`. */
|
|
11
|
+
format?: (key: string) => string;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
validate?(value: string): string | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Where this vendor's API lives, when the environment has moved it.
|
|
16
|
+
*
|
|
17
|
+
* Returning `undefined` is the normal answer and leaves the catalog's own
|
|
18
|
+
* `baseUrl` in place — which matters, because a user catalog is the other
|
|
19
|
+
* way to move an endpoint and an override that fired unconditionally would
|
|
20
|
+
* quietly outrank it.
|
|
21
|
+
*/
|
|
22
|
+
baseUrl?: () => string | undefined;
|
|
23
|
+
}): AuthProvider;
|
|
24
|
+
export interface OAuthProviderOptions {
|
|
25
|
+
id: string;
|
|
26
|
+
label: string;
|
|
27
|
+
/**
|
|
28
|
+
* OAuth client id. Deliberately required rather than bundled: shipping
|
|
29
|
+
* another application's registered client id would mean authenticating as
|
|
30
|
+
* that application. Register your own, or supply one your vendor gave you.
|
|
31
|
+
*/
|
|
32
|
+
clientId: string;
|
|
33
|
+
clientSecret?: string;
|
|
34
|
+
scope?: string;
|
|
35
|
+
/** Device authorization grant (RFC 8628). */
|
|
36
|
+
deviceCodeUrl?: string;
|
|
37
|
+
/** Authorization-code endpoints. */
|
|
38
|
+
authorizeUrl?: string;
|
|
39
|
+
tokenUrl: string;
|
|
40
|
+
/** Force the paste-the-code flow instead of a loopback listener. */
|
|
41
|
+
preferPasteCode?: boolean;
|
|
42
|
+
extraParams?: Record<string, string>;
|
|
43
|
+
headers?: Record<string, string>;
|
|
44
|
+
/** Header carrying the access token. Defaults to `authorization`. */
|
|
45
|
+
header?: string;
|
|
46
|
+
format?: (token: string) => string;
|
|
47
|
+
/** Headers to strip once the bearer token is applied. */
|
|
48
|
+
removeHeaders?: string[];
|
|
49
|
+
/** Extra headers every authenticated request needs. */
|
|
50
|
+
extraHeaders?: Record<string, string>;
|
|
51
|
+
envVars?: string[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build an OAuth auth provider covering the flows a terminal app can actually
|
|
55
|
+
* complete: device code, loopback redirect, or paste-the-code.
|
|
56
|
+
*/
|
|
57
|
+
export declare function oauthProvider(opts: OAuthProviderOptions): AuthProvider;
|