@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,155 @@
|
|
|
1
|
+
import { refreshCredential, startAuthCodeFlow, startDeviceFlow, startLoopbackFlow, } from "../oauth.js";
|
|
2
|
+
import { isExpired } from "../types.js";
|
|
3
|
+
/** Build a plain API-key auth provider. */
|
|
4
|
+
export function apiKeyProvider(opts) {
|
|
5
|
+
const header = opts.header ?? "authorization";
|
|
6
|
+
const format = opts.format ?? ((key) => `Bearer ${key}`);
|
|
7
|
+
const endpoint = () => {
|
|
8
|
+
const moved = opts.baseUrl?.();
|
|
9
|
+
return moved ? { baseUrl: moved } : {};
|
|
10
|
+
};
|
|
11
|
+
return {
|
|
12
|
+
id: opts.id,
|
|
13
|
+
label: opts.label,
|
|
14
|
+
methods: [
|
|
15
|
+
{
|
|
16
|
+
type: "api",
|
|
17
|
+
label: "API key",
|
|
18
|
+
prompts: [
|
|
19
|
+
{
|
|
20
|
+
type: "text",
|
|
21
|
+
key: "key",
|
|
22
|
+
message: `${opts.label} API key`,
|
|
23
|
+
placeholder: opts.placeholder,
|
|
24
|
+
secret: true,
|
|
25
|
+
validate: opts.validate,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
async loader(credential) {
|
|
31
|
+
for (const name of opts.envVars ?? []) {
|
|
32
|
+
const value = process.env[name];
|
|
33
|
+
if (value) {
|
|
34
|
+
return { headers: { [header]: format(value) }, source: `env:${name}`, ...endpoint() };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (credential?.type === "api") {
|
|
38
|
+
return { headers: { [header]: format(credential.key) }, source: "stored:api", ...endpoint() };
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
},
|
|
42
|
+
async discover() {
|
|
43
|
+
for (const name of opts.envVars ?? []) {
|
|
44
|
+
const value = process.env[name];
|
|
45
|
+
if (value)
|
|
46
|
+
return { credential: { type: "api", key: value }, source: `env:${name}` };
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Build an OAuth auth provider covering the flows a terminal app can actually
|
|
54
|
+
* complete: device code, loopback redirect, or paste-the-code.
|
|
55
|
+
*/
|
|
56
|
+
export function oauthProvider(opts) {
|
|
57
|
+
const header = opts.header ?? "authorization";
|
|
58
|
+
const format = opts.format ?? ((token) => `Bearer ${token}`);
|
|
59
|
+
const methods = [];
|
|
60
|
+
if (opts.deviceCodeUrl) {
|
|
61
|
+
methods.push({
|
|
62
|
+
type: "oauth",
|
|
63
|
+
label: `Sign in to ${opts.label} (device code)`,
|
|
64
|
+
authorize: async () => startDeviceFlow({
|
|
65
|
+
deviceCodeUrl: opts.deviceCodeUrl,
|
|
66
|
+
tokenUrl: opts.tokenUrl,
|
|
67
|
+
clientId: opts.clientId,
|
|
68
|
+
scope: opts.scope,
|
|
69
|
+
headers: opts.headers,
|
|
70
|
+
}),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (opts.authorizeUrl) {
|
|
74
|
+
methods.push({
|
|
75
|
+
type: "oauth",
|
|
76
|
+
label: `Sign in to ${opts.label} (browser)`,
|
|
77
|
+
authorize: async () => {
|
|
78
|
+
const shared = {
|
|
79
|
+
authorizeUrl: opts.authorizeUrl,
|
|
80
|
+
tokenUrl: opts.tokenUrl,
|
|
81
|
+
clientId: opts.clientId,
|
|
82
|
+
clientSecret: opts.clientSecret,
|
|
83
|
+
scope: opts.scope,
|
|
84
|
+
extraParams: opts.extraParams,
|
|
85
|
+
headers: opts.headers,
|
|
86
|
+
};
|
|
87
|
+
// A loopback listener is nicer, but is useless over SSH or in a
|
|
88
|
+
// container where the browser cannot reach 127.0.0.1.
|
|
89
|
+
return opts.preferPasteCode
|
|
90
|
+
? startAuthCodeFlow({ ...shared, redirectUri: "urn:ietf:wg:oauth:2.0:oob" })
|
|
91
|
+
: startLoopbackFlow(shared);
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (opts.envVars?.length) {
|
|
96
|
+
methods.push({
|
|
97
|
+
type: "api",
|
|
98
|
+
label: "API key",
|
|
99
|
+
prompts: [{ type: "text", key: "key", message: `${opts.label} API key`, secret: true }],
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
id: opts.id,
|
|
104
|
+
label: opts.label,
|
|
105
|
+
methods,
|
|
106
|
+
async loader(credential) {
|
|
107
|
+
for (const name of opts.envVars ?? []) {
|
|
108
|
+
const value = process.env[name];
|
|
109
|
+
if (value) {
|
|
110
|
+
return {
|
|
111
|
+
headers: { [header]: format(value), ...opts.extraHeaders },
|
|
112
|
+
removeHeaders: opts.removeHeaders,
|
|
113
|
+
source: `env:${name}`,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (credential?.type === "oauth") {
|
|
118
|
+
return {
|
|
119
|
+
headers: { [header]: format(credential.access), ...opts.extraHeaders },
|
|
120
|
+
removeHeaders: opts.removeHeaders,
|
|
121
|
+
...(credential.baseUrl ? { baseUrl: credential.baseUrl } : {}),
|
|
122
|
+
source: "stored:oauth",
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (credential?.type === "api") {
|
|
126
|
+
return {
|
|
127
|
+
headers: { [header]: format(credential.key), ...opts.extraHeaders },
|
|
128
|
+
removeHeaders: opts.removeHeaders,
|
|
129
|
+
source: "stored:api",
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return undefined;
|
|
133
|
+
},
|
|
134
|
+
async refresh(credential) {
|
|
135
|
+
if (!isExpired(credential))
|
|
136
|
+
return undefined;
|
|
137
|
+
return refreshCredential(credential, {
|
|
138
|
+
tokenUrl: opts.tokenUrl,
|
|
139
|
+
clientId: opts.clientId,
|
|
140
|
+
clientSecret: opts.clientSecret,
|
|
141
|
+
headers: opts.headers,
|
|
142
|
+
scope: opts.scope,
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
async discover() {
|
|
146
|
+
for (const name of opts.envVars ?? []) {
|
|
147
|
+
const value = process.env[name];
|
|
148
|
+
if (value)
|
|
149
|
+
return { credential: { type: "api", key: value }, source: `env:${name}` };
|
|
150
|
+
}
|
|
151
|
+
return undefined;
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=generic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic.js","sourceRoot":"","sources":["../../../src/auth/providers/generic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { isExpired } from "../types.js";
|
|
2
|
+
import { accountSignIn, bearer, refreshSession } from "./account.js";
|
|
3
|
+
/**
|
|
4
|
+
* The official plan — an OHarness account and nothing else asked for.
|
|
5
|
+
*
|
|
6
|
+
* Two credentials reach it, and they are the same account either way:
|
|
7
|
+
*
|
|
8
|
+
* - The session from signing in, held here and refreshed like any OAuth token.
|
|
9
|
+
* - An `oh-` key the account holder created on the OHarness site. It is not a
|
|
10
|
+
* second wallet, only a second key to the same one — CI and SDKs need
|
|
11
|
+
* something that does not expire, and `OHARNESS_API_KEY` is how that key is
|
|
12
|
+
* carried into a process, not a separate thing issued to a machine.
|
|
13
|
+
*
|
|
14
|
+
* What is deliberately absent is any upstream credential. The models are
|
|
15
|
+
* served by a gateway that holds the OpenAI, Anthropic and Google keys; usage
|
|
16
|
+
* is metered against the account's balance on the way through. Which gateway
|
|
17
|
+
* that is stays an implementation detail — the subscriber never learns it, and
|
|
18
|
+
* moving it is a change to `DEFAULT_BASE_URL` rather than to anyone's setup.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Where official-plan requests go.
|
|
22
|
+
*
|
|
23
|
+
* This is the metering endpoint, not the upstream gateway: it is what reads
|
|
24
|
+
* the account, checks the balance and writes the ledger entry, and only then
|
|
25
|
+
* forwards. Pointing it at the upstream instead skips the half of the request
|
|
26
|
+
* that knows who is asking — the upstream sees an account token where it wants
|
|
27
|
+
* its own key and answers `invalid_api_key`, which is a confusing way to be
|
|
28
|
+
* told the meter is not in the path. `OHARNESS_BASE_URL` moves it for a
|
|
29
|
+
* staging or self-hosted deployment.
|
|
30
|
+
*
|
|
31
|
+
* A domain of ours rather than the host's generated one, because this string
|
|
32
|
+
* is compiled into every desktop build and the desktop reads no environment:
|
|
33
|
+
* whatever is written here is where installed copies go until they are
|
|
34
|
+
* replaced. A hosting subdomain would make "move the gateway" and "abandon
|
|
35
|
+
* everyone who has not updated" the same act.
|
|
36
|
+
*/
|
|
37
|
+
const DEFAULT_BASE_URL = "https://api.oharness.ai";
|
|
38
|
+
export function officialBaseUrl() {
|
|
39
|
+
return (process.env["OHARNESS_BASE_URL"] ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
40
|
+
}
|
|
41
|
+
export const officialAuth = {
|
|
42
|
+
id: "official",
|
|
43
|
+
label: "OHarness",
|
|
44
|
+
methods: [
|
|
45
|
+
accountSignIn("Sign in to your OHarness account"),
|
|
46
|
+
{
|
|
47
|
+
type: "api",
|
|
48
|
+
label: "OHarness API key",
|
|
49
|
+
prompts: [
|
|
50
|
+
{
|
|
51
|
+
type: "text",
|
|
52
|
+
key: "key",
|
|
53
|
+
message: "OHarness API key",
|
|
54
|
+
placeholder: "oh-…",
|
|
55
|
+
secret: true,
|
|
56
|
+
validate: (value) => /^\S+$/.test(value) && !/^["']|["']$/.test(value)
|
|
57
|
+
? undefined
|
|
58
|
+
: "paste the key alone — no quotes or spaces",
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
async loader(credential) {
|
|
64
|
+
const envKey = process.env["OHARNESS_API_KEY"];
|
|
65
|
+
if (envKey)
|
|
66
|
+
return bearer(envKey, "env:OHARNESS_API_KEY");
|
|
67
|
+
if (credential?.type === "oauth" && !isExpired(credential)) {
|
|
68
|
+
return {
|
|
69
|
+
...bearer(credential.access, "stored:account"),
|
|
70
|
+
// The gateway may pin an account to a regional host at login.
|
|
71
|
+
...(credential.baseUrl ? { baseUrl: credential.baseUrl } : {}),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (credential?.type === "api")
|
|
75
|
+
return bearer(credential.key, "stored:api");
|
|
76
|
+
return undefined;
|
|
77
|
+
},
|
|
78
|
+
async refresh(credential) {
|
|
79
|
+
if (!isExpired(credential))
|
|
80
|
+
return undefined;
|
|
81
|
+
return refreshSession(credential);
|
|
82
|
+
},
|
|
83
|
+
async discover() {
|
|
84
|
+
const envKey = process.env["OHARNESS_API_KEY"];
|
|
85
|
+
if (!envKey)
|
|
86
|
+
return undefined;
|
|
87
|
+
return { credential: { type: "api", key: envKey }, source: "env:OHARNESS_API_KEY" };
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=official.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"official.js","sourceRoot":"","sources":["../../../src/auth/providers/official.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAErE;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAEnD,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACpF,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAiB;IACxC,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,UAAU;IAEjB,OAAO,EAAE;QACP,aAAa,CAAC,kCAAkC,CAAC;QACjD;YACE,IAAI,EAAE,KAAK;YACX,KAAK,EAAE,kBAAkB;YACzB,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,GAAG,EAAE,KAAK;oBACV,OAAO,EAAE,kBAAkB;oBAC3B,WAAW,EAAE,MAAM;oBACnB,MAAM,EAAE,IAAI;oBACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;wBAC/C,CAAC,CAAC,SAAS;wBACX,CAAC,CAAC,2CAA2C;iBAClD;aACF;SACF;KACF;IAED,KAAK,CAAC,MAAM,CAAC,UAAU;QACrB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAC/C,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;QAE1D,IAAI,UAAU,EAAE,IAAI,KAAK,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3D,OAAO;gBACL,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,gBAAgB,CAAC;gBAC9C,8DAA8D;gBAC9D,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/D,CAAC;QACJ,CAAC;QAED,IAAI,UAAU,EAAE,IAAI,KAAK,KAAK;YAAE,OAAO,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QAE5E,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,UAA2B;QACvC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;YAAE,OAAO,SAAS,CAAC;QAC7C,OAAO,cAAc,CAAC,UAAU,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAC9B,OAAO,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IACtF,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { apiKeyProvider } from "./generic.js";
|
|
2
|
+
/**
|
|
3
|
+
* OttoPort — an OpenAI-compatible gateway, brought by the user.
|
|
4
|
+
*
|
|
5
|
+
* This entry is for someone who has their own OttoPort account: they create a
|
|
6
|
+
* key in OttoPort's console and paste it here, and their usage is billed
|
|
7
|
+
* against their own credit balance there. It is an ordinary vendor entry, no
|
|
8
|
+
* different in kind from OpenAI or OpenRouter.
|
|
9
|
+
*
|
|
10
|
+
* It is *not* the official OHarness plan. That plan happens to route through
|
|
11
|
+
* this gateway today, but the subscriber never holds an OttoPort key and never
|
|
12
|
+
* sees an OttoPort account — see `official.ts`. Keeping the two apart is what
|
|
13
|
+
* lets the plan's billing, quota and upstream be ours to change.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* The gateway. Per-deployment, so staging and self-hosted work unchanged:
|
|
17
|
+
* `OTTOPORT_BASE_URL` moves it without a release.
|
|
18
|
+
*/
|
|
19
|
+
const DEFAULT_BASE_URL = "https://ottoport.ai";
|
|
20
|
+
/** Where the API sits under the host. Stated once; two things below need it. */
|
|
21
|
+
const API_PATH = "/api/v1";
|
|
22
|
+
export function ottoportBaseUrl() {
|
|
23
|
+
return (process.env["OTTOPORT_BASE_URL"] ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The endpoint to call, when the environment has moved it — and nothing at
|
|
27
|
+
* all when it has not.
|
|
28
|
+
*
|
|
29
|
+
* The variable names a *host*, which is how it is documented and how anyone
|
|
30
|
+
* would think to set it, while what the wire needs is the API root. Appending
|
|
31
|
+
* the path here is what makes `OTTOPORT_BASE_URL=https://staging.ottoport.ai`
|
|
32
|
+
* do what it says instead of sending every completion to a 404 one level up.
|
|
33
|
+
* A value that already carries the path is left alone, since typing the whole
|
|
34
|
+
* root is the other obvious reading.
|
|
35
|
+
*
|
|
36
|
+
* Silent when unset, deliberately: the catalog's `baseUrl` is the default, and
|
|
37
|
+
* a user catalog is the other way to move this endpoint. An override that
|
|
38
|
+
* returned the default anyway would outrank that file for no reason.
|
|
39
|
+
*/
|
|
40
|
+
function movedEndpoint() {
|
|
41
|
+
const moved = process.env["OTTOPORT_BASE_URL"];
|
|
42
|
+
if (!moved)
|
|
43
|
+
return undefined;
|
|
44
|
+
const host = moved.replace(/\/+$/, "");
|
|
45
|
+
return host.endsWith(API_PATH) ? host : `${host}${API_PATH}`;
|
|
46
|
+
}
|
|
47
|
+
export const ottoportAuth = apiKeyProvider({
|
|
48
|
+
id: "ottoport",
|
|
49
|
+
label: "OttoPort",
|
|
50
|
+
envVars: ["OTTOPORT_API_KEY"],
|
|
51
|
+
placeholder: "op-…",
|
|
52
|
+
baseUrl: movedEndpoint,
|
|
53
|
+
// Deliberately loose about the prefix: rejecting a key the gateway would
|
|
54
|
+
// have accepted is worse than passing a typo through to a 401. Quotes and
|
|
55
|
+
// spaces are the real failure — they come from pasting `KEY="op-…"`.
|
|
56
|
+
validate: (value) => /^\S+$/.test(value) && !/^["']|["']$/.test(value)
|
|
57
|
+
? undefined
|
|
58
|
+
: "paste the key alone — no quotes or spaces",
|
|
59
|
+
});
|
|
60
|
+
//# sourceMappingURL=ottoport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ottoport.js","sourceRoot":"","sources":["../../../src/auth/providers/ottoport.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;;;;;;;;GAYG;AAEH;;;GAGG;AACH,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AAE/C,gFAAgF;AAChF,MAAM,QAAQ,GAAG,SAAS,CAAC;AAE3B,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACpF,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAS,aAAa;IACpB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,QAAQ,EAAE,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAiB,cAAc,CAAC;IACvD,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,UAAU;IACjB,OAAO,EAAE,CAAC,kBAAkB,CAAC;IAC7B,WAAW,EAAE,MAAM;IACnB,OAAO,EAAE,aAAa;IACtB,yEAAyE;IACzE,0EAA0E;IAC1E,qEAAqE;IACrE,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;QAC/C,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,2CAA2C;CAClD,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Credential } from "./types.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Credential storage.
|
|
4
|
+
*
|
|
5
|
+
* Written 0600 in a 0700 directory: these are live access tokens, and on a
|
|
6
|
+
* shared machine a world-readable auth file is the whole security story.
|
|
7
|
+
* Writes go through a temp file + rename so a crash mid-write cannot leave a
|
|
8
|
+
* truncated credential set behind.
|
|
9
|
+
*/
|
|
10
|
+
export declare class AuthStore {
|
|
11
|
+
private readonly file;
|
|
12
|
+
private cache?;
|
|
13
|
+
constructor(file?: string);
|
|
14
|
+
get location(): string;
|
|
15
|
+
all(): Promise<Record<string, Credential>>;
|
|
16
|
+
get(providerId: string): Promise<Credential | undefined>;
|
|
17
|
+
set(providerId: string, credential: Credential): Promise<void>;
|
|
18
|
+
remove(providerId: string): Promise<boolean>;
|
|
19
|
+
/** Drop the in-memory copy so the next read comes from disk. */
|
|
20
|
+
invalidate(): void;
|
|
21
|
+
private persist;
|
|
22
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { userPath } from "../paths.js";
|
|
2
|
+
import { chmod, mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { parseJson } from "../util/json.js";
|
|
5
|
+
const FILE_MODE = 0o600;
|
|
6
|
+
const DIR_MODE = 0o700;
|
|
7
|
+
/**
|
|
8
|
+
* Credential storage.
|
|
9
|
+
*
|
|
10
|
+
* Written 0600 in a 0700 directory: these are live access tokens, and on a
|
|
11
|
+
* shared machine a world-readable auth file is the whole security story.
|
|
12
|
+
* Writes go through a temp file + rename so a crash mid-write cannot leave a
|
|
13
|
+
* truncated credential set behind.
|
|
14
|
+
*/
|
|
15
|
+
export class AuthStore {
|
|
16
|
+
file;
|
|
17
|
+
cache;
|
|
18
|
+
constructor(file) {
|
|
19
|
+
this.file =
|
|
20
|
+
file ??
|
|
21
|
+
process.env["OHARNESS_AUTH_FILE"] ??
|
|
22
|
+
userPath("auth.json");
|
|
23
|
+
}
|
|
24
|
+
get location() {
|
|
25
|
+
return this.file;
|
|
26
|
+
}
|
|
27
|
+
async all() {
|
|
28
|
+
if (this.cache)
|
|
29
|
+
return this.cache;
|
|
30
|
+
// An env override lets CI inject credentials without touching disk.
|
|
31
|
+
const inline = process.env["OHARNESS_AUTH_CONTENT"];
|
|
32
|
+
if (inline) {
|
|
33
|
+
const parsed = parseJson(inline);
|
|
34
|
+
if (parsed.ok) {
|
|
35
|
+
this.cache = parsed.value;
|
|
36
|
+
return this.cache;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
let raw;
|
|
40
|
+
try {
|
|
41
|
+
raw = await readFile(this.file, "utf8");
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
this.cache = {};
|
|
45
|
+
return this.cache;
|
|
46
|
+
}
|
|
47
|
+
const parsed = parseJson(raw);
|
|
48
|
+
if (!parsed.ok) {
|
|
49
|
+
// A corrupt auth file should not be fatal — treat it as empty and let
|
|
50
|
+
// the user log in again rather than blocking every request.
|
|
51
|
+
this.cache = {};
|
|
52
|
+
return this.cache;
|
|
53
|
+
}
|
|
54
|
+
const out = {};
|
|
55
|
+
for (const [key, value] of Object.entries(parsed.value)) {
|
|
56
|
+
const credential = validate(value);
|
|
57
|
+
if (credential)
|
|
58
|
+
out[normalizeKey(key)] = credential;
|
|
59
|
+
}
|
|
60
|
+
this.cache = out;
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
async get(providerId) {
|
|
64
|
+
return (await this.all())[normalizeKey(providerId)];
|
|
65
|
+
}
|
|
66
|
+
async set(providerId, credential) {
|
|
67
|
+
const all = { ...(await this.all()), [normalizeKey(providerId)]: credential };
|
|
68
|
+
await this.persist(all);
|
|
69
|
+
}
|
|
70
|
+
async remove(providerId) {
|
|
71
|
+
const all = { ...(await this.all()) };
|
|
72
|
+
const key = normalizeKey(providerId);
|
|
73
|
+
if (!(key in all))
|
|
74
|
+
return false;
|
|
75
|
+
delete all[key];
|
|
76
|
+
await this.persist(all);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
/** Drop the in-memory copy so the next read comes from disk. */
|
|
80
|
+
invalidate() {
|
|
81
|
+
this.cache = undefined;
|
|
82
|
+
}
|
|
83
|
+
async persist(all) {
|
|
84
|
+
await mkdir(path.dirname(this.file), { recursive: true, mode: DIR_MODE });
|
|
85
|
+
const temp = `${this.file}.${process.pid}.tmp`;
|
|
86
|
+
await writeFile(temp, JSON.stringify(all, null, 2), { encoding: "utf8", mode: FILE_MODE });
|
|
87
|
+
await rename(temp, this.file);
|
|
88
|
+
// rename preserves the temp file's mode, but be explicit in case the file
|
|
89
|
+
// already existed with looser permissions.
|
|
90
|
+
await chmod(this.file, FILE_MODE).catch(() => { });
|
|
91
|
+
this.cache = all;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** Trailing slashes are easy to introduce via config and break lookups. */
|
|
95
|
+
function normalizeKey(key) {
|
|
96
|
+
return key.replace(/\/+$/, "");
|
|
97
|
+
}
|
|
98
|
+
function validate(value) {
|
|
99
|
+
if (!value || typeof value !== "object")
|
|
100
|
+
return undefined;
|
|
101
|
+
const v = value;
|
|
102
|
+
switch (v["type"]) {
|
|
103
|
+
case "api":
|
|
104
|
+
return typeof v["key"] === "string"
|
|
105
|
+
? {
|
|
106
|
+
type: "api",
|
|
107
|
+
key: v["key"],
|
|
108
|
+
...(isStringRecord(v["metadata"]) ? { metadata: v["metadata"] } : {}),
|
|
109
|
+
}
|
|
110
|
+
: undefined;
|
|
111
|
+
case "oauth":
|
|
112
|
+
return typeof v["access"] === "string" &&
|
|
113
|
+
typeof v["refresh"] === "string" &&
|
|
114
|
+
typeof v["expires"] === "number"
|
|
115
|
+
? {
|
|
116
|
+
type: "oauth",
|
|
117
|
+
access: v["access"],
|
|
118
|
+
refresh: v["refresh"],
|
|
119
|
+
expires: v["expires"],
|
|
120
|
+
...(typeof v["accountId"] === "string" ? { accountId: v["accountId"] } : {}),
|
|
121
|
+
...(typeof v["baseUrl"] === "string" ? { baseUrl: v["baseUrl"] } : {}),
|
|
122
|
+
...(isStringRecord(v["metadata"]) ? { metadata: v["metadata"] } : {}),
|
|
123
|
+
}
|
|
124
|
+
: undefined;
|
|
125
|
+
case "wellknown":
|
|
126
|
+
return typeof v["key"] === "string" && typeof v["token"] === "string"
|
|
127
|
+
? { type: "wellknown", key: v["key"], token: v["token"] }
|
|
128
|
+
: undefined;
|
|
129
|
+
default:
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function isStringRecord(value) {
|
|
134
|
+
return (!!value &&
|
|
135
|
+
typeof value === "object" &&
|
|
136
|
+
Object.values(value).every((v) => typeof v === "string"));
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/auth/store.ts"],"names":[],"mappings":"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"}
|