@kynver-app/runtime 0.1.166 → 0.1.168
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/byoc/m6-golden-path.d.ts +6 -0
- package/dist/cli.js +53 -52
- package/dist/index.js +69 -68
- package/dist/model-routing.d.ts +7 -0
- package/dist/orchestration-providers/oauth-binding-utils.d.ts +1 -0
- package/dist/provider-quota-preflight.d.ts +38 -0
- package/dist/server/orchestration.js +1 -1
- package/package.json +1 -1
package/dist/model-routing.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type KynverUserConfig } from "./config.js";
|
|
2
|
+
import type { OrchestrationProviderInventory } from "./orchestration-providers/inventory.js";
|
|
2
3
|
import type { OrchestrationRoutingAudit } from "./orchestration-providers/types.js";
|
|
3
4
|
import { CLAUDE_REVIEW_MODEL } from "./providers/claude.js";
|
|
4
5
|
export { CLAUDE_REVIEW_MODEL };
|
|
@@ -37,6 +38,12 @@ export declare function resolveWorkerLaunch(input: {
|
|
|
37
38
|
/** When true, `--provider claude` is honored without a task-level override. */
|
|
38
39
|
explicitProviderIsOperatorOverride?: boolean;
|
|
39
40
|
task?: Record<string, unknown>;
|
|
41
|
+
/**
|
|
42
|
+
* Pre-built provider inventory for the orchestration overlay. Callers that
|
|
43
|
+
* already probed bindings (or tests) pass this so routing does not re-probe
|
|
44
|
+
* the live host CLIs.
|
|
45
|
+
*/
|
|
46
|
+
orchestrationInventory?: OrchestrationProviderInventory | null;
|
|
40
47
|
}): ModelRoutingDecision;
|
|
41
48
|
/** Fallback chain tail after provider start — never hard-code Opus here. */
|
|
42
49
|
export declare function resolveModelFallback(startedModel: string | undefined, launchModel: string | undefined, providerDefault: string | undefined): string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface ProviderQuotaCooldownRecord {
|
|
2
|
+
lastExhaustedAt: string;
|
|
3
|
+
reason: string;
|
|
4
|
+
}
|
|
5
|
+
export type ProviderQuotaCooldownStore = Record<string, ProviderQuotaCooldownRecord>;
|
|
6
|
+
export type ProviderQuotaPreflightVerdict = {
|
|
7
|
+
ok: true;
|
|
8
|
+
} | {
|
|
9
|
+
ok: false;
|
|
10
|
+
provider: string;
|
|
11
|
+
reason: string;
|
|
12
|
+
retryAtIso: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function isProviderQuotaExhaustionText(value: string | null | undefined): boolean;
|
|
15
|
+
/** Preflight is on by default; `KYNVER_PROVIDER_QUOTA_PREFLIGHT=off|0|false|no` disables. */
|
|
16
|
+
export declare function providerQuotaPreflightEnabled(): boolean;
|
|
17
|
+
export declare function providerQuotaCooldownMinutes(): number;
|
|
18
|
+
/** Record that `provider` reported quota exhaustion (starts/refreshes its cooldown). */
|
|
19
|
+
export declare function recordProviderQuotaExhaustion(provider: string, reason: string, nowMs?: number): void;
|
|
20
|
+
/** Drop the cooldown for `provider` (a completion proved it works again). */
|
|
21
|
+
export declare function clearProviderQuotaCooldown(provider: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Decide whether spawning a worker on `provider` is admissible right now.
|
|
24
|
+
* Blocked only while a recorded exhaustion is inside the cooldown window;
|
|
25
|
+
* expired records are pruned so the next spawn probes the provider.
|
|
26
|
+
*/
|
|
27
|
+
export declare function assessProviderQuotaPreflight(provider: string | null | undefined, nowMs?: number): ProviderQuotaPreflightVerdict;
|
|
28
|
+
/**
|
|
29
|
+
* Observe a finished worker's outcome for provider quota health:
|
|
30
|
+
* quota-shaped failure text → record/refresh the cooldown; any other
|
|
31
|
+
* substantive completion → clear it (the provider demonstrably served a run).
|
|
32
|
+
*/
|
|
33
|
+
export declare function observeProviderQuotaFromCompletion(input: {
|
|
34
|
+
provider: string | null | undefined;
|
|
35
|
+
finalResult: unknown;
|
|
36
|
+
error?: string | null;
|
|
37
|
+
nowMs?: number;
|
|
38
|
+
}): "recorded" | "cleared" | "none";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as R}from"node:fs";import{homedir as
|
|
1
|
+
import{existsSync as R}from"node:fs";import{homedir as H}from"node:os";import K from"node:path";import{createHash as A}from"node:crypto";import{statSync as B}from"node:fs";import{spawnSync as x}from"node:child_process";function c(e){try{let t=B(e),r=`${e}|${t.size}|${t.mtimeMs}`;return A("sha256").update(r).digest("hex").slice(0,16)}catch{return}}function u(e){return A("sha256").update(`env:${e}`).digest("hex").slice(0,16)}function d(e,t){for(let r of t){let n=process.env[r]?.trim();if(n)return n}return e}function a(e,t,r={}){let n=r.timeoutMs??8e3;try{let o=x(e,t,{encoding:"utf8",timeout:n,env:{...process.env,...r.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 h(e,t,r={}){let n=r.timeoutMs??8e3;try{return x(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=H();return[K.join(e,".claude",".credentials.json")]}function _(e=new Date().toISOString()){let t=d(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=a(t,["--version"],{okNote:`${t} CLI available`,failPrefix:`${t} CLI not available`}),n=j().find(s=>R(s)),o=h(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?c(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 D}from"node:os";import l from"node:path";var M="codex";function Y(){let e=D();return[process.env.CODEX_HOME?.trim()?l.join(l.resolve(process.env.CODEX_HOME.trim()),"auth.json"):null,l.join(e,".codex","auth.json"),l.join(e,".config","codex","auth.json")].filter(r=>!!r)}function $(e){return l.dirname(e)}function F(e){let t,r;for(let n of Y()){if(!L(n))continue;t??=n;let o=a(e,["login","status"],{okNote:"codex login status: authenticated",failPrefix:"codex login status",env:{CODEX_HOME:$(n)}});if(r??=o,o.ok)return{authPath:n,login:o}}return{authPath:t,login:r??a(e,["login","status"],{okNote:"codex login status: authenticated",failPrefix:"codex login status"})}}function P(e=new Date().toISOString()){let t=d(M,["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{authPath:r,login:n}=F(t),o=!!r&&n.ok;return{providerId:"codex",ready:o,authSource:"oauth_local",sessionFingerprint:r?c(r):void 0,checkedAt:e,note:o?"Local Codex OAuth session bound on runner":[n.note,r?void 0:"no Codex auth store found"].filter(Boolean).join("; ")}}import{existsSync as w}from"node:fs";import{homedir as U}from"node:os";import O from"node:path";function V(){let e=process.env.HERMES_HOME?.trim(),t=e?O.resolve(e):O.join(U(),".hermes");return O.join(t,"auth.json")}function m(e=new Date().toISOString()){let t=d("hermes",["KYNVER_HERMES_BIN","HERMES_BIN"]),r=a(t,["--version"],{okNote:`${t} CLI available`,failPrefix:`${t} CLI not available`}),n=V(),o=w(n),i=h(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?c(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 S(e=new Date().toISOString()){let t=P(e);if(t.ready)return{...t,path:"codex_cli"};let r=m(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 X}from"node:fs";import{homedir as G}from"node:os";import J from"node:path";var z="agent";function W(){let e=G();return[J.join(e,".config","cursor","auth.json")]}function I(e=new Date().toISOString()){let t=d(z,["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=a(t,["-v"],{okNote:`${t} CLI available`,failPrefix:`${t} CLI not available`}),n=W().find(i=>X(i)),o=!!n&&r.ok;return{providerId:"cursor",ready:o,authSource:"oauth_local",sessionFingerprint:n?c(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 q,readFileSync as Q}from"node:fs";import{homedir as Z}from"node:os";import g from"node:path";var ee=["OPENAI_API_KEY","ANTHROPIC_API_KEY","KYNVER_API_KEY","KYNVER_BASE_URL"];function te(){let e=process.env.HERMES_HOME?.trim(),t=e?g.resolve(e):g.join(Z(),".hermes");return g.join(t,".env")}function re(e){try{let t=Q(e,"utf8"),r=[];for(let n of ee)new RegExp(`^${n}=`,"m").test(t)&&r.push(n);return r}catch{return[]}}function E(e=new Date().toISOString()){let t=d("hermes",["KYNVER_HERMES_BIN","HERMES_BIN"]),r=a(t,["--version"],{okNote:`${t} CLI available`,failPrefix:`${t} CLI not available`}),n=te(),o=q(n),i=o?re(n):[],v=i.some(N=>N.endsWith("_API_KEY"))?"api_key_env":o?"oauth_local":"none",k=r.ok&&o;return{adapterId:"hermes",cliAvailable:r.ok,profileBound:o,authSource:v,sessionFingerprint:o?c(n):void 0,checkedAt:e,note:k?`Hermes profile bound (${i.length?`keys: ${i.join(", ")}`:"no API keys detected"})`:[r.note,o?void 0:"no ~/.hermes/.env"].filter(Boolean).join("; ")}}function oe(e={}){let t=e.nowIso?.()??new Date().toISOString(),r=S(t),n={codex:r,cursor:I(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:m(t),codexAdapterPath:r.path,readyCount:o}}var ne={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 ie(){return Object.values(ne)}var b=["off","observe","enforce"];function se(e){let t=(e??"off").trim().toLowerCase();return b.includes(t)?t:"off"}function f(e=process.env){return se(e.KYNVER_ORCHESTRATION_POLICY_MODE)}function C(e=process.env){let t=e.KYNVER_ORCHESTRATION_ENFORCE_TASKS?.trim().toLowerCase();return t?t==="1"||t==="true"||t==="yes"||t==="on":f(e)==="enforce"}import{createHash as ae}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=ae("sha256").update([p(e.planId)??"",p(e.parentTaskId)??"",r.toLowerCase()].join("|")).digest("hex").slice(0,16);return`hermes-foreground:${t}:${n}`}function ce(e,t){return e==="enforce"&&t?"enforce_harness_task":e==="observe"?"observe_bypass":"allow_local"}function de(e,t=process.env){let r=f(t),n=C(t),o=ce(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,oe as buildOrchestrationProviderInventory,de as evaluateOrchestrationPolicy,C as isOrchestrationEnforceTasksEnabled,ie as listOrchestrationProviderCapabilities,f as resolveOrchestrationPolicyMode};
|