@kynver-app/runtime 0.1.123 → 0.1.128
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/chat/chat-claim-loop.d.ts +11 -0
- package/dist/chat/command-allowlist.d.ts +8 -0
- package/dist/chat/command-executor.d.ts +13 -0
- package/dist/cli.js +54 -17782
- package/dist/cron/cron-cli-bin.d.ts +7 -0
- package/dist/cron/cron-readiness.d.ts +35 -0
- package/dist/disk-gate.d.ts +7 -0
- package/dist/index.js +71 -19281
- package/dist/mesh-liveness/mesh-cron-lease-store.d.ts +9 -0
- package/dist/server/cleanup.js +16 -4054
- package/dist/server/default-repo.js +1 -458
- package/dist/server/harness-notice.js +15 -287
- package/dist/server/heavy-verification.js +1 -223
- package/dist/server/landing.js +1 -44
- package/dist/server/memory-cost-enforce.js +2 -480
- package/dist/server/memory-cost.js +2 -184
- package/dist/server/monitor.js +8 -1805
- package/dist/server/orchestration.js +1 -444
- package/dist/server/pr-evidence.js +1 -163
- package/dist/server/repo-search.js +1 -224
- package/dist/server/worker-policy.js +1 -432
- package/dist/worker-persona-catalog.js +1 -138
- package/package.json +3 -2
- package/dist/cli.js.map +0 -7
- package/dist/index.js.map +0 -7
- package/dist/server/cleanup.js.map +0 -7
- package/dist/server/default-repo.js.map +0 -7
- package/dist/server/harness-notice.js.map +0 -7
- package/dist/server/heavy-verification.js.map +0 -7
- package/dist/server/landing.js.map +0 -7
- package/dist/server/memory-cost-enforce.js.map +0 -7
- package/dist/server/memory-cost.js.map +0 -7
- package/dist/server/monitor.js.map +0 -7
- package/dist/server/orchestration.js.map +0 -7
- package/dist/server/pr-evidence.js.map +0 -7
- package/dist/server/repo-search.js.map +0 -7
- package/dist/server/worker-policy.js.map +0 -7
- package/dist/worker-persona-catalog.js.map +0 -7
|
@@ -1,444 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
|
|
6
|
-
// src/orchestration-providers/oauth-binding-utils.ts
|
|
7
|
-
import { createHash } from "node:crypto";
|
|
8
|
-
import { statSync } from "node:fs";
|
|
9
|
-
import { spawnSync } from "node:child_process";
|
|
10
|
-
function fingerprintAuthStore(filePath) {
|
|
11
|
-
try {
|
|
12
|
-
const st = statSync(filePath);
|
|
13
|
-
const material = `${filePath}|${st.size}|${st.mtimeMs}`;
|
|
14
|
-
return createHash("sha256").update(material).digest("hex").slice(0, 16);
|
|
15
|
-
} catch {
|
|
16
|
-
return void 0;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
function envKeyFingerprint(envKey) {
|
|
20
|
-
return createHash("sha256").update(`env:${envKey}`).digest("hex").slice(0, 16);
|
|
21
|
-
}
|
|
22
|
-
function resolveCliBin(defaultBin, envKeys) {
|
|
23
|
-
for (const key of envKeys) {
|
|
24
|
-
const value = process.env[key]?.trim();
|
|
25
|
-
if (value) return value;
|
|
26
|
-
}
|
|
27
|
-
return defaultBin;
|
|
28
|
-
}
|
|
29
|
-
function probeCliCommand(bin, args, options = {}) {
|
|
30
|
-
const timeoutMs = options.timeoutMs ?? 8e3;
|
|
31
|
-
try {
|
|
32
|
-
const result = spawnSync(bin, args, {
|
|
33
|
-
encoding: "utf8",
|
|
34
|
-
timeout: timeoutMs,
|
|
35
|
-
env: { ...process.env, CI: "1", NO_COLOR: "1" }
|
|
36
|
-
});
|
|
37
|
-
if (result.status === 0) {
|
|
38
|
-
return { ok: true, note: options.okNote ?? `${bin} ${args.join(" ")}: ok` };
|
|
39
|
-
}
|
|
40
|
-
const stderr = (result.stderr || result.stdout || "").trim();
|
|
41
|
-
const prefix = options.failPrefix ?? `${bin} ${args.join(" ")} failed`;
|
|
42
|
-
return {
|
|
43
|
-
ok: false,
|
|
44
|
-
note: stderr ? `${prefix}: ${stderr.slice(0, 200)}` : prefix
|
|
45
|
-
};
|
|
46
|
-
} catch (err) {
|
|
47
|
-
return {
|
|
48
|
-
ok: false,
|
|
49
|
-
note: err instanceof Error ? err.message : `${bin} probe failed`
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
function probeCliExitCodeOnly(bin, args, options = {}) {
|
|
54
|
-
const timeoutMs = options.timeoutMs ?? 8e3;
|
|
55
|
-
try {
|
|
56
|
-
const result = spawnSync(bin, args, {
|
|
57
|
-
stdio: "ignore",
|
|
58
|
-
timeout: timeoutMs,
|
|
59
|
-
env: { ...process.env, CI: "1", NO_COLOR: "1" }
|
|
60
|
-
});
|
|
61
|
-
if (result.status === 0) {
|
|
62
|
-
return { ok: true, note: options.okNote ?? `${bin} authenticated` };
|
|
63
|
-
}
|
|
64
|
-
return { ok: false, note: options.failNote ?? `${bin} not authenticated` };
|
|
65
|
-
} catch (err) {
|
|
66
|
-
return {
|
|
67
|
-
ok: false,
|
|
68
|
-
note: err instanceof Error ? err.message : `${bin} auth probe failed`
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// src/orchestration-providers/claude-oauth-binding.ts
|
|
74
|
-
var DEFAULT_CLAUDE_BIN = "claude";
|
|
75
|
-
function claudeAuthStoreCandidates() {
|
|
76
|
-
const home = homedir();
|
|
77
|
-
return [path.join(home, ".claude", ".credentials.json")];
|
|
78
|
-
}
|
|
79
|
-
function probeClaudeOAuthBinding(nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
80
|
-
const bin = resolveCliBin(DEFAULT_CLAUDE_BIN, ["KYNVER_CLAUDE_BIN", "CLAUDE_BIN"]);
|
|
81
|
-
if (process.env.ANTHROPIC_API_KEY?.trim()) {
|
|
82
|
-
return {
|
|
83
|
-
providerId: "claude",
|
|
84
|
-
ready: true,
|
|
85
|
-
authSource: "api_key_env",
|
|
86
|
-
sessionFingerprint: envKeyFingerprint("ANTHROPIC_API_KEY"),
|
|
87
|
-
checkedAt: nowIso,
|
|
88
|
-
note: "ANTHROPIC_API_KEY present (env binding \u2014 cloud credits path, no token stored in Kynver)"
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
const cli = probeCliCommand(bin, ["--version"], {
|
|
92
|
-
okNote: `${bin} CLI available`,
|
|
93
|
-
failPrefix: `${bin} CLI not available`
|
|
94
|
-
});
|
|
95
|
-
const authPath = claudeAuthStoreCandidates().find((p) => existsSync(p));
|
|
96
|
-
const login = probeCliExitCodeOnly(bin, ["auth", "status"], {
|
|
97
|
-
okNote: "claude auth status: authenticated",
|
|
98
|
-
failNote: "claude auth status: not authenticated"
|
|
99
|
-
});
|
|
100
|
-
const ready = cli.ok && (login.ok || Boolean(authPath));
|
|
101
|
-
return {
|
|
102
|
-
providerId: "claude",
|
|
103
|
-
ready,
|
|
104
|
-
authSource: "oauth_local",
|
|
105
|
-
sessionFingerprint: authPath ? fingerprintAuthStore(authPath) : void 0,
|
|
106
|
-
checkedAt: nowIso,
|
|
107
|
-
note: ready ? "Local Claude Code OAuth session bound on runner" : [cli.note, login.note, authPath ? void 0 : "no ~/.claude/.credentials.json"].filter(Boolean).join("; ")
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// src/orchestration-providers/codex-oauth-binding.ts
|
|
112
|
-
import { existsSync as existsSync2 } from "node:fs";
|
|
113
|
-
import { homedir as homedir2 } from "node:os";
|
|
114
|
-
import path2 from "node:path";
|
|
115
|
-
var DEFAULT_CODEX_BIN = "codex";
|
|
116
|
-
function authStoreCandidates() {
|
|
117
|
-
const home = homedir2();
|
|
118
|
-
return [
|
|
119
|
-
path2.join(home, ".codex", "auth.json"),
|
|
120
|
-
path2.join(home, ".config", "codex", "auth.json")
|
|
121
|
-
];
|
|
122
|
-
}
|
|
123
|
-
function probeCodexOAuthBinding(nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
124
|
-
const bin = resolveCliBin(DEFAULT_CODEX_BIN, ["KYNVER_CODEX_BIN", "CODEX_BIN"]);
|
|
125
|
-
if (process.env.CODEX_API_KEY?.trim()) {
|
|
126
|
-
return {
|
|
127
|
-
providerId: "codex",
|
|
128
|
-
ready: true,
|
|
129
|
-
authSource: "api_key_env",
|
|
130
|
-
sessionFingerprint: envKeyFingerprint("CODEX_API_KEY"),
|
|
131
|
-
checkedAt: nowIso,
|
|
132
|
-
note: "CODEX_API_KEY present (env binding \u2014 cloud credits path, no token stored in Kynver)"
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
const authPath = authStoreCandidates().find((p) => existsSync2(p));
|
|
136
|
-
const login = probeCliCommand(bin, ["login", "status"], {
|
|
137
|
-
okNote: "codex login status: authenticated",
|
|
138
|
-
failPrefix: "codex login status"
|
|
139
|
-
});
|
|
140
|
-
const ready = Boolean(authPath) && login.ok;
|
|
141
|
-
return {
|
|
142
|
-
providerId: "codex",
|
|
143
|
-
ready,
|
|
144
|
-
authSource: "oauth_local",
|
|
145
|
-
sessionFingerprint: authPath ? fingerprintAuthStore(authPath) : void 0,
|
|
146
|
-
checkedAt: nowIso,
|
|
147
|
-
note: ready ? "Local Codex OAuth session bound on runner" : [login.note, authPath ? void 0 : "no ~/.codex/auth.json"].filter(Boolean).join("; ")
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// src/orchestration-providers/hermes-openai-codex-binding.ts
|
|
152
|
-
import { existsSync as existsSync3 } from "node:fs";
|
|
153
|
-
import { homedir as homedir3 } from "node:os";
|
|
154
|
-
import path3 from "node:path";
|
|
155
|
-
function hermesAuthStorePath() {
|
|
156
|
-
const configured = process.env.HERMES_HOME?.trim();
|
|
157
|
-
const home = configured ? path3.resolve(configured) : path3.join(homedir3(), ".hermes");
|
|
158
|
-
return path3.join(home, "auth.json");
|
|
159
|
-
}
|
|
160
|
-
function probeHermesOpenAiCodexBinding(nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
161
|
-
const bin = resolveCliBin("hermes", ["KYNVER_HERMES_BIN", "HERMES_BIN"]);
|
|
162
|
-
const cli = probeCliCommand(bin, ["--version"], {
|
|
163
|
-
okNote: `${bin} CLI available`,
|
|
164
|
-
failPrefix: `${bin} CLI not available`
|
|
165
|
-
});
|
|
166
|
-
const authPath = hermesAuthStorePath();
|
|
167
|
-
const authStorePresent = existsSync3(authPath);
|
|
168
|
-
const auth = probeCliExitCodeOnly(bin, ["auth", "status", "openai-codex"], {
|
|
169
|
-
okNote: "hermes openai-codex: logged in",
|
|
170
|
-
failNote: "hermes openai-codex: not logged in"
|
|
171
|
-
});
|
|
172
|
-
const ready = cli.ok && auth.ok;
|
|
173
|
-
const authSource = ready ? "subscription_hermes" : "none";
|
|
174
|
-
return {
|
|
175
|
-
path: "hermes_openai_codex",
|
|
176
|
-
ready,
|
|
177
|
-
authSource,
|
|
178
|
-
sessionFingerprint: authStorePresent ? fingerprintAuthStore(authPath) : void 0,
|
|
179
|
-
checkedAt: nowIso,
|
|
180
|
-
note: ready ? "Hermes openai-codex subscription session bound (ChatGPT Codex OAuth)" : [cli.note, auth.note, authStorePresent ? void 0 : "no ~/.hermes/auth.json"].filter(Boolean).join("; ")
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// src/orchestration-providers/codex-orchestration-adapter.ts
|
|
185
|
-
function resolveCodexOrchestrationAdapter(nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
186
|
-
const cliBinding = probeCodexOAuthBinding(nowIso);
|
|
187
|
-
if (cliBinding.ready) {
|
|
188
|
-
return { ...cliBinding, path: "codex_cli" };
|
|
189
|
-
}
|
|
190
|
-
const hermes = probeHermesOpenAiCodexBinding(nowIso);
|
|
191
|
-
if (hermes.ready) {
|
|
192
|
-
return {
|
|
193
|
-
providerId: "codex",
|
|
194
|
-
ready: true,
|
|
195
|
-
authSource: hermes.authSource,
|
|
196
|
-
sessionFingerprint: hermes.sessionFingerprint,
|
|
197
|
-
checkedAt: hermes.checkedAt,
|
|
198
|
-
note: hermes.note,
|
|
199
|
-
path: "hermes_openai_codex",
|
|
200
|
-
hermesOpenAiCodex: hermes
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
return {
|
|
204
|
-
providerId: "codex",
|
|
205
|
-
ready: false,
|
|
206
|
-
authSource: "none",
|
|
207
|
-
checkedAt: nowIso,
|
|
208
|
-
path: "none",
|
|
209
|
-
hermesOpenAiCodex: hermes,
|
|
210
|
-
note: [cliBinding.note, hermes.note].filter(Boolean).join("; ") || "Codex CLI and Hermes openai-codex unavailable"
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// src/orchestration-providers/cursor-oauth-binding.ts
|
|
215
|
-
import { existsSync as existsSync4 } from "node:fs";
|
|
216
|
-
import { homedir as homedir4 } from "node:os";
|
|
217
|
-
import path4 from "node:path";
|
|
218
|
-
var DEFAULT_AGENT_BIN = "agent";
|
|
219
|
-
function cursorAuthStoreCandidates() {
|
|
220
|
-
const home = homedir4();
|
|
221
|
-
return [path4.join(home, ".config", "cursor", "auth.json")];
|
|
222
|
-
}
|
|
223
|
-
function probeCursorOAuthBinding(nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
224
|
-
const bin = resolveCliBin(DEFAULT_AGENT_BIN, [
|
|
225
|
-
"KYNVER_CURSOR_AGENT_BIN",
|
|
226
|
-
"CURSOR_AGENT_BIN"
|
|
227
|
-
]);
|
|
228
|
-
if (process.env.CURSOR_API_KEY?.trim()) {
|
|
229
|
-
return {
|
|
230
|
-
providerId: "cursor",
|
|
231
|
-
ready: true,
|
|
232
|
-
authSource: "api_key_env",
|
|
233
|
-
sessionFingerprint: envKeyFingerprint("CURSOR_API_KEY"),
|
|
234
|
-
checkedAt: nowIso,
|
|
235
|
-
note: "CURSOR_API_KEY present (env binding \u2014 cloud credits path, no token stored in Kynver)"
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
const cli = probeCliCommand(bin, ["-v"], {
|
|
239
|
-
okNote: `${bin} CLI available`,
|
|
240
|
-
failPrefix: `${bin} CLI not available`
|
|
241
|
-
});
|
|
242
|
-
const authPath = cursorAuthStoreCandidates().find((p) => existsSync4(p));
|
|
243
|
-
const ready = Boolean(authPath) && cli.ok;
|
|
244
|
-
return {
|
|
245
|
-
providerId: "cursor",
|
|
246
|
-
ready,
|
|
247
|
-
authSource: "oauth_local",
|
|
248
|
-
sessionFingerprint: authPath ? fingerprintAuthStore(authPath) : void 0,
|
|
249
|
-
checkedAt: nowIso,
|
|
250
|
-
note: ready ? "Local Cursor/Composer OAuth session bound on runner" : [cli.note, authPath ? void 0 : "no ~/.config/cursor/auth.json"].filter(Boolean).join("; ")
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// src/orchestration-providers/hermes-cli-adapter.ts
|
|
255
|
-
import { existsSync as existsSync5, readFileSync } from "node:fs";
|
|
256
|
-
import { homedir as homedir5 } from "node:os";
|
|
257
|
-
import path5 from "node:path";
|
|
258
|
-
var PROFILE_ENV_KEYS = [
|
|
259
|
-
"OPENAI_API_KEY",
|
|
260
|
-
"ANTHROPIC_API_KEY",
|
|
261
|
-
"KYNVER_API_KEY",
|
|
262
|
-
"KYNVER_BASE_URL"
|
|
263
|
-
];
|
|
264
|
-
function hermesProfileEnvPath() {
|
|
265
|
-
const configured = process.env.HERMES_HOME?.trim();
|
|
266
|
-
const home = configured ? path5.resolve(configured) : path5.join(homedir5(), ".hermes");
|
|
267
|
-
return path5.join(home, ".env");
|
|
268
|
-
}
|
|
269
|
-
function profileEnvKeyPresence(envPath) {
|
|
270
|
-
try {
|
|
271
|
-
const text = readFileSync(envPath, "utf8");
|
|
272
|
-
const present = [];
|
|
273
|
-
for (const key of PROFILE_ENV_KEYS) {
|
|
274
|
-
const re = new RegExp(`^${key}=`, "m");
|
|
275
|
-
if (re.test(text)) present.push(key);
|
|
276
|
-
}
|
|
277
|
-
return present;
|
|
278
|
-
} catch {
|
|
279
|
-
return [];
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
function probeHermesCliAdapter(nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
283
|
-
const bin = resolveCliBin("hermes", ["KYNVER_HERMES_BIN", "HERMES_BIN"]);
|
|
284
|
-
const cli = probeCliCommand(bin, ["--version"], {
|
|
285
|
-
okNote: `${bin} CLI available`,
|
|
286
|
-
failPrefix: `${bin} CLI not available`
|
|
287
|
-
});
|
|
288
|
-
const profilePath = hermesProfileEnvPath();
|
|
289
|
-
const profileBound = existsSync5(profilePath);
|
|
290
|
-
const envKeys = profileBound ? profileEnvKeyPresence(profilePath) : [];
|
|
291
|
-
const hasApiKeys = envKeys.some((k) => k.endsWith("_API_KEY"));
|
|
292
|
-
const authSource = hasApiKeys ? "api_key_env" : profileBound ? "oauth_local" : "none";
|
|
293
|
-
const ready = cli.ok && profileBound;
|
|
294
|
-
return {
|
|
295
|
-
adapterId: "hermes",
|
|
296
|
-
cliAvailable: cli.ok,
|
|
297
|
-
profileBound,
|
|
298
|
-
authSource,
|
|
299
|
-
sessionFingerprint: profileBound ? fingerprintAuthStore(profilePath) : void 0,
|
|
300
|
-
checkedAt: nowIso,
|
|
301
|
-
note: ready ? `Hermes profile bound (${envKeys.length ? `keys: ${envKeys.join(", ")}` : "no API keys detected"})` : [cli.note, profileBound ? void 0 : "no ~/.hermes/.env"].filter(Boolean).join("; ")
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// src/orchestration-providers/inventory.ts
|
|
306
|
-
function buildOrchestrationProviderInventory(options = {}) {
|
|
307
|
-
const generatedAt = options.nowIso?.() ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
308
|
-
const codexAdapter = resolveCodexOrchestrationAdapter(generatedAt);
|
|
309
|
-
const bindings = {
|
|
310
|
-
codex: codexAdapter,
|
|
311
|
-
cursor: probeCursorOAuthBinding(generatedAt),
|
|
312
|
-
claude: probeClaudeOAuthBinding(generatedAt)
|
|
313
|
-
};
|
|
314
|
-
const readyCount = Object.values(bindings).filter((b) => b.ready).length;
|
|
315
|
-
return {
|
|
316
|
-
generatedAt,
|
|
317
|
-
bindings,
|
|
318
|
-
cloudApiCredits: {
|
|
319
|
-
anthropicApiKey: Boolean(process.env.ANTHROPIC_API_KEY?.trim()),
|
|
320
|
-
openaiApiKey: Boolean(process.env.OPENAI_API_KEY?.trim()),
|
|
321
|
-
codexApiKey: Boolean(process.env.CODEX_API_KEY?.trim())
|
|
322
|
-
},
|
|
323
|
-
hermes: probeHermesCliAdapter(generatedAt),
|
|
324
|
-
hermesOpenAiCodex: probeHermesOpenAiCodexBinding(generatedAt),
|
|
325
|
-
codexAdapterPath: codexAdapter.path,
|
|
326
|
-
readyCount
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// src/orchestration-providers/capabilities.ts
|
|
331
|
-
var CAPABILITIES = {
|
|
332
|
-
codex: {
|
|
333
|
-
id: "codex",
|
|
334
|
-
displayName: "Codex (BYO OAuth / Hermes openai-codex)",
|
|
335
|
-
costTier: "low",
|
|
336
|
-
authSources: ["oauth_local", "api_key_env", "subscription_hermes"],
|
|
337
|
-
supportsLowRiskOrchestration: true,
|
|
338
|
-
supportsPrivilegedPlatformActions: false
|
|
339
|
-
},
|
|
340
|
-
cursor: {
|
|
341
|
-
id: "cursor",
|
|
342
|
-
displayName: "Cursor / Composer",
|
|
343
|
-
costTier: "medium",
|
|
344
|
-
authSources: ["oauth_local", "api_key_env"],
|
|
345
|
-
supportsLowRiskOrchestration: true,
|
|
346
|
-
supportsPrivilegedPlatformActions: true
|
|
347
|
-
},
|
|
348
|
-
claude: {
|
|
349
|
-
id: "claude",
|
|
350
|
-
displayName: "Claude Code",
|
|
351
|
-
costTier: "high",
|
|
352
|
-
authSources: ["oauth_local"],
|
|
353
|
-
supportsLowRiskOrchestration: true,
|
|
354
|
-
supportsPrivilegedPlatformActions: true
|
|
355
|
-
}
|
|
356
|
-
};
|
|
357
|
-
function listOrchestrationProviderCapabilities() {
|
|
358
|
-
return Object.values(CAPABILITIES);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// src/orchestration-enforcement/types.ts
|
|
362
|
-
var ORCHESTRATION_POLICY_MODES = ["off", "observe", "enforce"];
|
|
363
|
-
|
|
364
|
-
// src/orchestration-enforcement/config.ts
|
|
365
|
-
function normalizeMode(raw) {
|
|
366
|
-
const value = (raw ?? "off").trim().toLowerCase();
|
|
367
|
-
if (ORCHESTRATION_POLICY_MODES.includes(value)) {
|
|
368
|
-
return value;
|
|
369
|
-
}
|
|
370
|
-
return "off";
|
|
371
|
-
}
|
|
372
|
-
function resolveOrchestrationPolicyMode(env = process.env) {
|
|
373
|
-
return normalizeMode(env.KYNVER_ORCHESTRATION_POLICY_MODE);
|
|
374
|
-
}
|
|
375
|
-
function isOrchestrationEnforceTasksEnabled(env = process.env) {
|
|
376
|
-
const raw = env.KYNVER_ORCHESTRATION_ENFORCE_TASKS?.trim().toLowerCase();
|
|
377
|
-
if (!raw) return resolveOrchestrationPolicyMode(env) === "enforce";
|
|
378
|
-
return raw === "1" || raw === "true" || raw === "yes" || raw === "on";
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// src/orchestration-enforcement/idempotency.ts
|
|
382
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
383
|
-
function trimOrNull(value) {
|
|
384
|
-
if (value == null) return null;
|
|
385
|
-
const t = value.trim();
|
|
386
|
-
return t.length ? t : null;
|
|
387
|
-
}
|
|
388
|
-
function buildForegroundHarnessIdempotencyKey(input) {
|
|
389
|
-
const session = trimOrNull(input.sessionId) ?? "anonymous";
|
|
390
|
-
const title = trimOrNull(input.title) ?? trimOrNull(input.action) ?? "foreground";
|
|
391
|
-
const digest = createHash2("sha256").update(
|
|
392
|
-
[
|
|
393
|
-
trimOrNull(input.planId) ?? "",
|
|
394
|
-
trimOrNull(input.parentTaskId) ?? "",
|
|
395
|
-
title.toLowerCase()
|
|
396
|
-
].join("|")
|
|
397
|
-
).digest("hex").slice(0, 16);
|
|
398
|
-
return `hermes-foreground:${session}:${digest}`;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// src/orchestration-enforcement/evaluator.ts
|
|
402
|
-
function decisionForMode(mode, enforceEnabled) {
|
|
403
|
-
if (mode === "enforce" && enforceEnabled) return "enforce_harness_task";
|
|
404
|
-
if (mode === "observe") return "observe_bypass";
|
|
405
|
-
return "allow_local";
|
|
406
|
-
}
|
|
407
|
-
function evaluateOrchestrationPolicy(input, env = process.env) {
|
|
408
|
-
const mode = resolveOrchestrationPolicyMode(env);
|
|
409
|
-
const enforceEnabled = isOrchestrationEnforceTasksEnabled(env);
|
|
410
|
-
const decision = decisionForMode(mode, enforceEnabled);
|
|
411
|
-
const idempotencyKey = decision === "enforce_harness_task" ? buildForegroundHarnessIdempotencyKey({
|
|
412
|
-
sessionId: input.sessionId,
|
|
413
|
-
planId: input.planId,
|
|
414
|
-
parentTaskId: input.parentTaskId,
|
|
415
|
-
title: input.title,
|
|
416
|
-
action: input.action
|
|
417
|
-
}) : null;
|
|
418
|
-
let reason;
|
|
419
|
-
if (mode === "off") {
|
|
420
|
-
reason = "Orchestration policy off \u2014 local foreground path allowed.";
|
|
421
|
-
} else if (decision === "observe_bypass") {
|
|
422
|
-
reason = `Observe mode: ${input.action} bypass logged; local fallback preserved.`;
|
|
423
|
-
} else if (decision === "enforce_harness_task") {
|
|
424
|
-
reason = `Enforce mode: ${input.action} must create linked harness AgentTask (${idempotencyKey}).`;
|
|
425
|
-
} else {
|
|
426
|
-
reason = "Local foreground path allowed.";
|
|
427
|
-
}
|
|
428
|
-
return {
|
|
429
|
-
mode,
|
|
430
|
-
decision,
|
|
431
|
-
idempotencyKey,
|
|
432
|
-
bypassLogged: decision === "observe_bypass",
|
|
433
|
-
reason
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
export {
|
|
437
|
-
buildForegroundHarnessIdempotencyKey,
|
|
438
|
-
buildOrchestrationProviderInventory,
|
|
439
|
-
evaluateOrchestrationPolicy,
|
|
440
|
-
isOrchestrationEnforceTasksEnabled,
|
|
441
|
-
listOrchestrationProviderCapabilities,
|
|
442
|
-
resolveOrchestrationPolicyMode
|
|
443
|
-
};
|
|
444
|
-
//# sourceMappingURL=orchestration.js.map
|
|
1
|
+
import{existsSync as R}from"node:fs";import{homedir as K}from"node:os";import H from"node:path";import{createHash as v}from"node:crypto";import{statSync as B}from"node:fs";import{spawnSync as A}from"node:child_process";function a(e){try{let t=B(e),r=`${e}|${t.size}|${t.mtimeMs}`;return v("sha256").update(r).digest("hex").slice(0,16)}catch{return}}function u(e){return v("sha256").update(`env:${e}`).digest("hex").slice(0,16)}function c(e,t){for(let r of t){let n=process.env[r]?.trim();if(n)return n}return e}function d(e,t,r={}){let n=r.timeoutMs??8e3;try{let o=A(e,t,{encoding:"utf8",timeout:n,env:{...process.env,CI:"1",NO_COLOR:"1"}});if(o.status===0)return{ok:!0,note:r.okNote??`${e} ${t.join(" ")}: ok`};let i=(o.stderr||o.stdout||"").trim(),s=r.failPrefix??`${e} ${t.join(" ")} failed`;return{ok:!1,note:i?`${s}: ${i.slice(0,200)}`:s}}catch(o){return{ok:!1,note:o instanceof Error?o.message:`${e} probe failed`}}}function l(e,t,r={}){let n=r.timeoutMs??8e3;try{return A(e,t,{stdio:"ignore",timeout:n,env:{...process.env,CI:"1",NO_COLOR:"1"}}).status===0?{ok:!0,note:r.okNote??`${e} authenticated`}:{ok:!1,note:r.failNote??`${e} not authenticated`}}catch(o){return{ok:!1,note:o instanceof Error?o.message:`${e} auth probe failed`}}}var T="claude";function j(){let e=K();return[H.join(e,".claude",".credentials.json")]}function _(e=new Date().toISOString()){let t=c(T,["KYNVER_CLAUDE_BIN","CLAUDE_BIN"]);if(process.env.ANTHROPIC_API_KEY?.trim())return{providerId:"claude",ready:!0,authSource:"api_key_env",sessionFingerprint:u("ANTHROPIC_API_KEY"),checkedAt:e,note:"ANTHROPIC_API_KEY present (env binding \u2014 cloud credits path, no token stored in Kynver)"};let r=d(t,["--version"],{okNote:`${t} CLI available`,failPrefix:`${t} CLI not available`}),n=j().find(s=>R(s)),o=l(t,["auth","status"],{okNote:"claude auth status: authenticated",failNote:"claude auth status: not authenticated"}),i=r.ok&&(o.ok||!!n);return{providerId:"claude",ready:i,authSource:"oauth_local",sessionFingerprint:n?a(n):void 0,checkedAt:e,note:i?"Local Claude Code OAuth session bound on runner":[r.note,o.note,n?void 0:"no ~/.claude/.credentials.json"].filter(Boolean).join("; ")}}import{existsSync as L}from"node:fs";import{homedir as Y}from"node:os";import x from"node:path";var D="codex";function M(){let e=Y();return[x.join(e,".codex","auth.json"),x.join(e,".config","codex","auth.json")]}function P(e=new Date().toISOString()){let t=c(D,["KYNVER_CODEX_BIN","CODEX_BIN"]);if(process.env.CODEX_API_KEY?.trim())return{providerId:"codex",ready:!0,authSource:"api_key_env",sessionFingerprint:u("CODEX_API_KEY"),checkedAt:e,note:"CODEX_API_KEY present (env binding \u2014 cloud credits path, no token stored in Kynver)"};let r=M().find(i=>L(i)),n=d(t,["login","status"],{okNote:"codex login status: authenticated",failPrefix:"codex login status"}),o=!!r&&n.ok;return{providerId:"codex",ready:o,authSource:"oauth_local",sessionFingerprint:r?a(r):void 0,checkedAt:e,note:o?"Local Codex OAuth session bound on runner":[n.note,r?void 0:"no ~/.codex/auth.json"].filter(Boolean).join("; ")}}import{existsSync as $}from"node:fs";import{homedir as F}from"node:os";import f from"node:path";function w(){let e=process.env.HERMES_HOME?.trim(),t=e?f.resolve(e):f.join(F(),".hermes");return f.join(t,"auth.json")}function h(e=new Date().toISOString()){let t=c("hermes",["KYNVER_HERMES_BIN","HERMES_BIN"]),r=d(t,["--version"],{okNote:`${t} CLI available`,failPrefix:`${t} CLI not available`}),n=w(),o=$(n),i=l(t,["auth","status","openai-codex"],{okNote:"hermes openai-codex: logged in",failNote:"hermes openai-codex: not logged in"}),s=r.ok&&i.ok;return{path:"hermes_openai_codex",ready:s,authSource:s?"subscription_hermes":"none",sessionFingerprint:o?a(n):void 0,checkedAt:e,note:s?"Hermes openai-codex subscription session bound (ChatGPT Codex OAuth)":[r.note,i.note,o?void 0:"no ~/.hermes/auth.json"].filter(Boolean).join("; ")}}function I(e=new Date().toISOString()){let t=P(e);if(t.ready)return{...t,path:"codex_cli"};let r=h(e);return r.ready?{providerId:"codex",ready:!0,authSource:r.authSource,sessionFingerprint:r.sessionFingerprint,checkedAt:r.checkedAt,note:r.note,path:"hermes_openai_codex",hermesOpenAiCodex:r}:{providerId:"codex",ready:!1,authSource:"none",checkedAt:e,path:"none",hermesOpenAiCodex:r,note:[t.note,r.note].filter(Boolean).join("; ")||"Codex CLI and Hermes openai-codex unavailable"}}import{existsSync as U}from"node:fs";import{homedir as V}from"node:os";import X from"node:path";var G="agent";function J(){let e=V();return[X.join(e,".config","cursor","auth.json")]}function S(e=new Date().toISOString()){let t=c(G,["KYNVER_CURSOR_AGENT_BIN","CURSOR_AGENT_BIN"]);if(process.env.CURSOR_API_KEY?.trim())return{providerId:"cursor",ready:!0,authSource:"api_key_env",sessionFingerprint:u("CURSOR_API_KEY"),checkedAt:e,note:"CURSOR_API_KEY present (env binding \u2014 cloud credits path, no token stored in Kynver)"};let r=d(t,["-v"],{okNote:`${t} CLI available`,failPrefix:`${t} CLI not available`}),n=J().find(i=>U(i)),o=!!n&&r.ok;return{providerId:"cursor",ready:o,authSource:"oauth_local",sessionFingerprint:n?a(n):void 0,checkedAt:e,note:o?"Local Cursor/Composer OAuth session bound on runner":[r.note,n?void 0:"no ~/.config/cursor/auth.json"].filter(Boolean).join("; ")}}import{existsSync as z,readFileSync as W}from"node:fs";import{homedir as q}from"node:os";import O from"node:path";var Q=["OPENAI_API_KEY","ANTHROPIC_API_KEY","KYNVER_API_KEY","KYNVER_BASE_URL"];function Z(){let e=process.env.HERMES_HOME?.trim(),t=e?O.resolve(e):O.join(q(),".hermes");return O.join(t,".env")}function ee(e){try{let t=W(e,"utf8"),r=[];for(let n of Q)new RegExp(`^${n}=`,"m").test(t)&&r.push(n);return r}catch{return[]}}function E(e=new Date().toISOString()){let t=c("hermes",["KYNVER_HERMES_BIN","HERMES_BIN"]),r=d(t,["--version"],{okNote:`${t} CLI available`,failPrefix:`${t} CLI not available`}),n=Z(),o=z(n),i=o?ee(n):[],C=i.some(k=>k.endsWith("_API_KEY"))?"api_key_env":o?"oauth_local":"none",N=r.ok&&o;return{adapterId:"hermes",cliAvailable:r.ok,profileBound:o,authSource:C,sessionFingerprint:o?a(n):void 0,checkedAt:e,note:N?`Hermes profile bound (${i.length?`keys: ${i.join(", ")}`:"no API keys detected"})`:[r.note,o?void 0:"no ~/.hermes/.env"].filter(Boolean).join("; ")}}function te(e={}){let t=e.nowIso?.()??new Date().toISOString(),r=I(t),n={codex:r,cursor:S(t),claude:_(t)},o=Object.values(n).filter(i=>i.ready).length;return{generatedAt:t,bindings:n,cloudApiCredits:{anthropicApiKey:!!process.env.ANTHROPIC_API_KEY?.trim(),openaiApiKey:!!process.env.OPENAI_API_KEY?.trim(),codexApiKey:!!process.env.CODEX_API_KEY?.trim()},hermes:E(t),hermesOpenAiCodex:h(t),codexAdapterPath:r.path,readyCount:o}}var re={codex:{id:"codex",displayName:"Codex (BYO OAuth / Hermes openai-codex)",costTier:"low",authSources:["oauth_local","api_key_env","subscription_hermes"],supportsLowRiskOrchestration:!0,supportsPrivilegedPlatformActions:!1},cursor:{id:"cursor",displayName:"Cursor / Composer",costTier:"medium",authSources:["oauth_local","api_key_env"],supportsLowRiskOrchestration:!0,supportsPrivilegedPlatformActions:!0},claude:{id:"claude",displayName:"Claude Code",costTier:"high",authSources:["oauth_local"],supportsLowRiskOrchestration:!0,supportsPrivilegedPlatformActions:!0}};function oe(){return Object.values(re)}var b=["off","observe","enforce"];function ne(e){let t=(e??"off").trim().toLowerCase();return b.includes(t)?t:"off"}function m(e=process.env){return ne(e.KYNVER_ORCHESTRATION_POLICY_MODE)}function g(e=process.env){let t=e.KYNVER_ORCHESTRATION_ENFORCE_TASKS?.trim().toLowerCase();return t?t==="1"||t==="true"||t==="yes"||t==="on":m(e)==="enforce"}import{createHash as ie}from"node:crypto";function p(e){if(e==null)return null;let t=e.trim();return t.length?t:null}function y(e){let t=p(e.sessionId)??"anonymous",r=p(e.title)??p(e.action)??"foreground",n=ie("sha256").update([p(e.planId)??"",p(e.parentTaskId)??"",r.toLowerCase()].join("|")).digest("hex").slice(0,16);return`hermes-foreground:${t}:${n}`}function se(e,t){return e==="enforce"&&t?"enforce_harness_task":e==="observe"?"observe_bypass":"allow_local"}function ae(e,t=process.env){let r=m(t),n=g(t),o=se(r,n),i=o==="enforce_harness_task"?y({sessionId:e.sessionId,planId:e.planId,parentTaskId:e.parentTaskId,title:e.title,action:e.action}):null,s;return r==="off"?s="Orchestration policy off \u2014 local foreground path allowed.":o==="observe_bypass"?s=`Observe mode: ${e.action} bypass logged; local fallback preserved.`:o==="enforce_harness_task"?s=`Enforce mode: ${e.action} must create linked harness AgentTask (${i}).`:s="Local foreground path allowed.",{mode:r,decision:o,idempotencyKey:i,bypassLogged:o==="observe_bypass",reason:s}}export{y as buildForegroundHarnessIdempotencyKey,te as buildOrchestrationProviderInventory,ae as evaluateOrchestrationPolicy,g as isOrchestrationEnforceTasksEnabled,oe as listOrchestrationProviderCapabilities,m as resolveOrchestrationPolicyMode};
|
|
@@ -1,163 +1 @@
|
|
|
1
|
-
|
|
2
|
-
var VERCEL_HOST_RE = /(^|\.)vercel\.app$/i;
|
|
3
|
-
var DPL_ID_RE = /^dpl_[a-z0-9]+$/i;
|
|
4
|
-
function tryParseUrl(raw) {
|
|
5
|
-
const trimmed = raw.trim();
|
|
6
|
-
if (!trimmed) return null;
|
|
7
|
-
try {
|
|
8
|
-
return new URL(trimmed);
|
|
9
|
-
} catch {
|
|
10
|
-
return null;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
function parseDashboardDeployment(url) {
|
|
14
|
-
const parts = url.pathname.split("/").filter(Boolean);
|
|
15
|
-
if (parts.length < 3) return null;
|
|
16
|
-
const deploymentId = parts[parts.length - 1]?.trim();
|
|
17
|
-
if (!deploymentId || deploymentId === "deployments") return null;
|
|
18
|
-
return deploymentId;
|
|
19
|
-
}
|
|
20
|
-
function parseDeploymentsSegment(url) {
|
|
21
|
-
const parts = url.pathname.split("/").filter(Boolean);
|
|
22
|
-
const idx = parts.indexOf("deployments");
|
|
23
|
-
if (idx < 0 || idx >= parts.length - 1) return null;
|
|
24
|
-
const deploymentId = parts[idx + 1]?.trim();
|
|
25
|
-
return deploymentId || null;
|
|
26
|
-
}
|
|
27
|
-
function classifyVercelUrl(raw) {
|
|
28
|
-
const empty = {
|
|
29
|
-
kind: "unknown",
|
|
30
|
-
previewUrl: null,
|
|
31
|
-
inspectTarget: null,
|
|
32
|
-
deploymentId: null
|
|
33
|
-
};
|
|
34
|
-
const trimmed = raw.trim();
|
|
35
|
-
if (!trimmed) return empty;
|
|
36
|
-
if (/^dpl_[a-z0-9]+$/i.test(trimmed)) {
|
|
37
|
-
return {
|
|
38
|
-
kind: "deployment_id",
|
|
39
|
-
previewUrl: null,
|
|
40
|
-
inspectTarget: trimmed,
|
|
41
|
-
deploymentId: trimmed
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
const url = tryParseUrl(trimmed);
|
|
45
|
-
if (!url) return empty;
|
|
46
|
-
if (VERCEL_HOST_RE.test(url.hostname)) {
|
|
47
|
-
const hostUrl = url.origin;
|
|
48
|
-
return {
|
|
49
|
-
kind: "deployment_host",
|
|
50
|
-
previewUrl: hostUrl,
|
|
51
|
-
inspectTarget: hostUrl,
|
|
52
|
-
deploymentId: null
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
if (url.hostname === "vercel.com" || url.hostname.endsWith(".vercel.com")) {
|
|
56
|
-
const deploymentId = parseDeploymentsSegment(url) ?? parseDashboardDeployment(url);
|
|
57
|
-
const inspectTarget = deploymentId && DPL_ID_RE.test(deploymentId) ? deploymentId : null;
|
|
58
|
-
return {
|
|
59
|
-
kind: "dashboard",
|
|
60
|
-
previewUrl: null,
|
|
61
|
-
inspectTarget,
|
|
62
|
-
deploymentId
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
return empty;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// src/vercel/vercel-github-status.ts
|
|
69
|
-
var VERCEL_CONTEXT_RE = /vercel/i;
|
|
70
|
-
function normalizeGitHubStatusState(state) {
|
|
71
|
-
const value = typeof state === "string" ? state.trim().toLowerCase() : "";
|
|
72
|
-
if (value === "success") return "success";
|
|
73
|
-
if (value === "pending") return "pending";
|
|
74
|
-
if (value === "failure") return "failure";
|
|
75
|
-
if (value === "error") return "error";
|
|
76
|
-
return "unknown";
|
|
77
|
-
}
|
|
78
|
-
function isVercelStatusContext(context) {
|
|
79
|
-
const label = typeof context === "string" ? context.trim() : "";
|
|
80
|
-
return Boolean(label && VERCEL_CONTEXT_RE.test(label));
|
|
81
|
-
}
|
|
82
|
-
function pickVercelStatusContext(statuses) {
|
|
83
|
-
const rows = Array.isArray(statuses) ? statuses : [];
|
|
84
|
-
const vercelRows = rows.filter((row) => isVercelStatusContext(row.context));
|
|
85
|
-
if (vercelRows.length === 0) return null;
|
|
86
|
-
const score = (state) => {
|
|
87
|
-
if (state === "failure" || state === "error") return 0;
|
|
88
|
-
if (state === "pending") return 1;
|
|
89
|
-
if (state === "success") return 2;
|
|
90
|
-
return 1;
|
|
91
|
-
};
|
|
92
|
-
let best = null;
|
|
93
|
-
let bestScore = Infinity;
|
|
94
|
-
for (const row of vercelRows) {
|
|
95
|
-
const rowScore = score(normalizeGitHubStatusState(row.state));
|
|
96
|
-
if (rowScore < bestScore) {
|
|
97
|
-
best = row;
|
|
98
|
-
bestScore = rowScore;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (!best) return null;
|
|
102
|
-
const targetUrl = typeof best.target_url === "string" && best.target_url.trim() ? best.target_url.trim() : null;
|
|
103
|
-
const classified = targetUrl ? classifyVercelUrl(targetUrl) : null;
|
|
104
|
-
return {
|
|
105
|
-
context: String(best.context ?? "Vercel").trim(),
|
|
106
|
-
state: normalizeGitHubStatusState(best.state),
|
|
107
|
-
targetUrl,
|
|
108
|
-
description: typeof best.description === "string" && best.description.trim() ? best.description.trim() : null,
|
|
109
|
-
deploymentId: classified?.deploymentId ?? null,
|
|
110
|
-
previewUrl: classified?.previewUrl ?? null,
|
|
111
|
-
dashboardUrl: classified?.kind === "dashboard" ? targetUrl : null
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// src/vercel/vercel-evidence.ts
|
|
116
|
-
function mapGitHubStateToEvidence(state) {
|
|
117
|
-
if (state === "success") return "ready";
|
|
118
|
-
if (state === "pending") return "building";
|
|
119
|
-
if (state === "failure" || state === "error") return "error";
|
|
120
|
-
return "unavailable";
|
|
121
|
-
}
|
|
122
|
-
function evidenceSummary(parts) {
|
|
123
|
-
return parts.filter(Boolean).join("; ");
|
|
124
|
-
}
|
|
125
|
-
function evidenceFromGitHubVercelStatus(statuses, options = {}) {
|
|
126
|
-
const observedAt = options.observedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
127
|
-
const row = pickVercelStatusContext(statuses);
|
|
128
|
-
if (!row) {
|
|
129
|
-
return {
|
|
130
|
-
status: "not_run",
|
|
131
|
-
previewUrl: null,
|
|
132
|
-
deploymentUrl: null,
|
|
133
|
-
summary: "No Vercel GitHub status context on commit",
|
|
134
|
-
observedAt,
|
|
135
|
-
inspectSkipped: true,
|
|
136
|
-
inspectReason: "no_vercel_status_context",
|
|
137
|
-
githubState: null,
|
|
138
|
-
vercelContext: null
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
const status = mapGitHubStateToEvidence(row.state);
|
|
142
|
-
const previewUrl = row.previewUrl ?? row.dashboardUrl;
|
|
143
|
-
const deploymentUrl = row.previewUrl ?? row.dashboardUrl;
|
|
144
|
-
return {
|
|
145
|
-
status,
|
|
146
|
-
previewUrl,
|
|
147
|
-
deploymentUrl,
|
|
148
|
-
summary: evidenceSummary([
|
|
149
|
-
`GitHub ${row.context}=${row.state}`,
|
|
150
|
-
row.description ?? "",
|
|
151
|
-
row.dashboardUrl ? "dashboard target_url (API lookup skipped)" : ""
|
|
152
|
-
]),
|
|
153
|
-
observedAt,
|
|
154
|
-
inspectSkipped: true,
|
|
155
|
-
inspectReason: row.dashboardUrl && row.state === "success" ? "trusted_github_status_dashboard_url" : row.dashboardUrl ? "dashboard_url_not_api_inspectable" : "github_status_only",
|
|
156
|
-
githubState: row.state,
|
|
157
|
-
vercelContext: row.context
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
export {
|
|
161
|
-
evidenceFromGitHubVercelStatus
|
|
162
|
-
};
|
|
163
|
-
//# sourceMappingURL=pr-evidence.js.map
|
|
1
|
+
var m=/(^|\.)vercel\.app$/i,f=/^dpl_[a-z0-9]+$/i;function g(t){let r=t.trim();if(!r)return null;try{return new URL(r)}catch{return null}}function y(t){let r=t.pathname.split("/").filter(Boolean);if(r.length<3)return null;let l=r[r.length-1]?.trim();return!l||l==="deployments"?null:l}function b(t){let r=t.pathname.split("/").filter(Boolean),l=r.indexOf("deployments");return l<0||l>=r.length-1?null:r[l+1]?.trim()||null}function a(t){let r={kind:"unknown",previewUrl:null,inspectTarget:null,deploymentId:null},l=t.trim();if(!l)return r;if(/^dpl_[a-z0-9]+$/i.test(l))return{kind:"deployment_id",previewUrl:null,inspectTarget:l,deploymentId:l};let e=g(l);if(!e)return r;if(m.test(e.hostname)){let n=e.origin;return{kind:"deployment_host",previewUrl:n,inspectTarget:n,deploymentId:null}}if(e.hostname==="vercel.com"||e.hostname.endsWith(".vercel.com")){let n=b(e)??y(e);return{kind:"dashboard",previewUrl:null,inspectTarget:n&&f.test(n)?n:null,deploymentId:n}}return r}var S=/vercel/i;function p(t){let r=typeof t=="string"?t.trim().toLowerCase():"";return r==="success"?"success":r==="pending"?"pending":r==="failure"?"failure":r==="error"?"error":"unknown"}function v(t){let r=typeof t=="string"?t.trim():"";return!!(r&&S.test(r))}function d(t){let l=(Array.isArray(t)?t:[]).filter(s=>v(s.context));if(l.length===0)return null;let e=s=>s==="failure"||s==="error"?0:s==="pending"?1:s==="success"?2:1,n=null,i=1/0;for(let s of l){let c=e(p(s.state));c<i&&(n=s,i=c)}if(!n)return null;let o=typeof n.target_url=="string"&&n.target_url.trim()?n.target_url.trim():null,u=o?a(o):null;return{context:String(n.context??"Vercel").trim(),state:p(n.state),targetUrl:o,description:typeof n.description=="string"&&n.description.trim()?n.description.trim():null,deploymentId:u?.deploymentId??null,previewUrl:u?.previewUrl??null,dashboardUrl:u?.kind==="dashboard"?o:null}}function U(t){return t==="success"?"ready":t==="pending"?"building":t==="failure"||t==="error"?"error":"unavailable"}function h(t){return t.filter(Boolean).join("; ")}function V(t,r={}){let l=r.observedAt??new Date().toISOString(),e=d(t);if(!e)return{status:"not_run",previewUrl:null,deploymentUrl:null,summary:"No Vercel GitHub status context on commit",observedAt:l,inspectSkipped:!0,inspectReason:"no_vercel_status_context",githubState:null,vercelContext:null};let n=U(e.state),i=e.previewUrl??e.dashboardUrl,o=e.previewUrl??e.dashboardUrl;return{status:n,previewUrl:i,deploymentUrl:o,summary:h([`GitHub ${e.context}=${e.state}`,e.description??"",e.dashboardUrl?"dashboard target_url (API lookup skipped)":""]),observedAt:l,inspectSkipped:!0,inspectReason:e.dashboardUrl&&e.state==="success"?"trusted_github_status_dashboard_url":e.dashboardUrl?"dashboard_url_not_api_inspectable":"github_status_only",githubState:e.state,vercelContext:e.context}}export{V as evidenceFromGitHubVercelStatus};
|