open-multi-agent-kit 0.78.8 → 0.79.3
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/AGENTS.md +131 -2
- package/CHANGELOG.md +32 -0
- package/CLAUDE.md +105 -3
- package/DESIGN.md +141 -117
- package/MATURITY.md +7 -12
- package/README.md +66 -347
- package/ROADMAP.md +33 -47
- package/dist/adapters/kimi/runner.js +2 -2
- package/dist/brand/theme.js +2 -2
- package/dist/cli/register-basic-commands.js +3 -2
- package/dist/cli/register-mcp-dag-cron-screenshot-commands.js +1 -1
- package/dist/cli/root.d.ts +1 -0
- package/dist/cli/root.js +2 -0
- package/dist/cli/runtime/command-bus.js +14 -1
- package/dist/cli/theme/terminal-capability.js +1 -1
- package/dist/cli/theme/theme-registry.js +90 -2
- package/dist/cli/ui/event.d.ts +1 -0
- package/dist/cli/ui/neon-grid-renderer.d.ts +8 -0
- package/dist/cli/ui/neon-grid-renderer.js +84 -14
- package/dist/cli/ui/plain-renderer.js +3 -1
- package/dist/cli/ui/system24-renderer.js +3 -1
- package/dist/cli/v2/chat-repl.d.ts +2 -1
- package/dist/cli/v2/chat-repl.js +58 -2
- package/dist/cli/v2/cli-v2-skeleton.js +7 -4
- package/dist/cli/v2/interactive-prompt.js +4 -3
- package/dist/commands/auth.js +2 -0
- package/dist/commands/chat/native-root-loop.d.ts +1 -0
- package/dist/commands/chat/native-root-loop.js +162 -13
- package/dist/commands/chat/runtime.js +9 -0
- package/dist/commands/chat/slash/commands/routing.js +31 -1
- package/dist/commands/chat/utils.js +3 -1
- package/dist/commands/cockpit/render.js +2 -1
- package/dist/commands/doctor/checks.js +2 -2
- package/dist/commands/init/core.js +2 -2
- package/dist/commands/init.js +2 -2
- package/dist/commands/mcp/config.js +38 -16
- package/dist/commands/mcp/doctor.js +7 -8
- package/dist/commands/mcp/list.js +4 -3
- package/dist/commands/mcp/shared.d.ts +4 -1
- package/dist/commands/mcp/shared.js +21 -3
- package/dist/commands/mcp/test.js +13 -12
- package/dist/commands/model.js +4 -0
- package/dist/commands/provider.js +5 -1
- package/dist/commands/version.d.ts +1 -0
- package/dist/commands/version.js +18 -0
- package/dist/contracts/command.d.ts +25 -0
- package/dist/contracts/command.js +1 -0
- package/dist/contracts/evidence-bundle.d.ts +52 -0
- package/dist/contracts/evidence-bundle.js +1 -0
- package/dist/contracts/index.d.ts +2 -0
- package/dist/contracts/index.js +2 -0
- package/dist/contracts/web-bridge.d.ts +1 -1
- package/dist/contracts/web-bridge.js +1 -1
- package/dist/evidence/bundle-validator.d.ts +7 -0
- package/dist/evidence/bundle-validator.js +103 -0
- package/dist/evidence/index.d.ts +5 -0
- package/dist/evidence/index.js +2 -0
- package/dist/evidence/proof-trust.js +2 -10
- package/dist/evidence/trust-calibration.d.ts +25 -0
- package/dist/evidence/trust-calibration.js +151 -0
- package/dist/mcp/omk-project-server.js +1 -1
- package/dist/metrics/provenance-ratio.d.ts +16 -0
- package/dist/metrics/provenance-ratio.js +33 -0
- package/dist/orchestration/dag.d.ts +17 -0
- package/dist/orchestration/ensemble-decision.d.ts +2 -0
- package/dist/orchestration/ensemble-decision.js +4 -0
- package/dist/orchestration/hedge-persona-weights.d.ts +25 -0
- package/dist/orchestration/hedge-persona-weights.js +43 -0
- package/dist/orchestration/parallel-ui.d.ts +1 -0
- package/dist/orchestration/parallel-ui.js +12 -3
- package/dist/orchestration/route-calibration.d.ts +27 -0
- package/dist/orchestration/route-calibration.js +123 -0
- package/dist/orchestration/routing/mcp-config.js +5 -1
- package/dist/orchestration/routing/types.d.ts +21 -0
- package/dist/orchestration/routing.d.ts +10 -0
- package/dist/orchestration/routing.js +89 -3
- package/dist/providers/model-registry.d.ts +2 -1
- package/dist/providers/model-registry.js +76 -4
- package/dist/providers/provider-runtime.js +9 -1
- package/dist/providers/thinking-levels.js +2 -0
- package/dist/providers/types.d.ts +1 -1
- package/dist/runtime/glm-api-runtime.d.ts +4 -0
- package/dist/runtime/glm-api-runtime.js +15 -0
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/kimi-api-runtime.d.ts +6 -1
- package/dist/runtime/kimi-api-runtime.js +10 -4
- package/dist/runtime/recovery-artifact-store.d.ts +39 -0
- package/dist/runtime/recovery-artifact-store.js +111 -0
- package/dist/runtime/runtime-backed-task-runner.js +10 -0
- package/dist/runtime/runtime-bootstrap.js +17 -1
- package/dist/runtime/slash-commands.js +38 -5
- package/dist/schema/command.schema.d.ts +121 -0
- package/dist/schema/command.schema.js +25 -0
- package/dist/schema/envelope.schema.d.ts +2 -2
- package/dist/schema/evidence-bundle.schema.d.ts +196 -0
- package/dist/schema/evidence-bundle.schema.js +38 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +2 -0
- package/dist/schema/proof-bundle.schema.d.ts +2 -2
- package/dist/theme/external-theme-adapters.d.ts +27 -0
- package/dist/theme/external-theme-adapters.js +52 -0
- package/dist/theme/library-effects.d.ts +12 -0
- package/dist/theme/library-effects.js +47 -0
- package/dist/theme/parallel.js +3 -2
- package/dist/tui/terminal-frame-renderer.d.ts +9 -1
- package/dist/tui/terminal-frame-renderer.js +77 -7
- package/dist/util/chat-cockpit.d.ts +3 -1
- package/dist/util/chat-cockpit.js +44 -5
- package/dist/util/command-envelope.d.ts +19 -0
- package/dist/util/command-envelope.js +31 -0
- package/dist/util/events-logger.d.ts +1 -1
- package/dist/util/events-logger.js +23 -16
- package/dist/util/fs/mcp-diagnose.js +2 -1
- package/dist/util/fs/mcp-runtime-config.js +14 -2
- package/dist/util/i18n.js +2 -2
- package/dist/util/screenshot-store.d.ts +7 -0
- package/dist/util/screenshot-store.js +30 -0
- package/dist/util/terminal-kit-bridge.d.ts +24 -0
- package/dist/util/terminal-kit-bridge.js +60 -0
- package/dist/util/terminal-owner.d.ts +1 -0
- package/dist/util/terminal-owner.js +31 -0
- package/dist/version.d.ts +3 -1
- package/dist/version.js +4 -0
- package/docs/2026-05-18-project-direction.md +1 -1
- package/docs/2026-06-14/critical-issues.md +19 -0
- package/docs/2026-06-14/improvements.md +15 -0
- package/docs/2026-06-14/init-checklist.md +25 -0
- package/docs/2026-06-14/plan.md +20 -0
- package/docs/2026-06-15/critical-issues.md +19 -0
- package/docs/2026-06-15/improvements.md +15 -0
- package/docs/2026-06-15/init-checklist.md +25 -0
- package/docs/2026-06-15/plan.md +20 -0
- package/docs/claims.md +85 -0
- package/docs/comparisons/omk-vs-claude-code.md +31 -0
- package/docs/comparisons/omk-vs-codex.md +33 -0
- package/docs/comparisons/omk-vs-mcp-agent.md +33 -0
- package/docs/comparisons/omk-vs-opencode.md +32 -0
- package/docs/decision-layer-calibration.md +20 -0
- package/docs/geo-eval-prompts.md +53 -0
- package/docs/getting-started.md +3 -31
- package/docs/headroom-omk-setup-guide.md +2 -2
- package/docs/integrations/adaptorch.md +46 -0
- package/docs/native-root-runtime-algorithms.md +2 -303
- package/docs/native-root-runtime-hardening.md +1 -1
- package/docs/provider-maturity.md +1 -1
- package/docs/use-cases/evidence-gated-coding-agents.md +52 -0
- package/docs/use-cases/no-kimi-mode.md +38 -0
- package/docs/use-cases/provider-routing-for-ai-coding.md +36 -0
- package/docs/use-cases/replayable-agent-runs.md +40 -0
- package/docs/use-cases/scoped-mcp-for-coding-agents.md +34 -0
- package/docs/versioning.md +9 -3
- package/docs/what-is-omk.md +64 -0
- package/llms.txt +28 -18
- package/package.json +7 -2
- package/readmeasset/.npmignore +3 -0
- package/readmeasset/ASSET_INDEX.md +3 -0
- package/readmeasset/ASSET_PROVENANCE.md +6 -0
- package/readmeasset/omk-adaptorch-ouroboros-supermemory.svg +95 -0
- package/readmeasset/omk-init-control-loop.svg +118 -0
- package/readmeasset/omk-parallel-subagents.svg +97 -0
- package/templates/web-bridge/chrome-extension/background.js +1 -1
|
@@ -5,14 +5,15 @@ import { style, header, status, label } from "../../util/theme.js";
|
|
|
5
5
|
import { maskSensitiveText } from "../../util/secret-mask.js";
|
|
6
6
|
import { buildSubprocessEnv } from "../../mcp/transports/stdio.js";
|
|
7
7
|
import { McpClientSession } from "../../mcp/client.js";
|
|
8
|
-
import { collectServers, formatArgsForDisplay, resolveAllConfigs, sanitizeMcpUrlForDisplay, selectEffectiveServer, serverTargetText, validateRemoteMcpUrl, } from "./shared.js";
|
|
8
|
+
import { collectServers, formatArgsForDisplay, normalizeMcpEnv, normalizeMcpServerName, resolveAllConfigs, sanitizeMcpUrlForDisplay, selectEffectiveServer, serverTargetText, validateRemoteMcpUrl, } from "./shared.js";
|
|
9
9
|
const JSON_RPC_INTERNAL_ERROR_CODE = -32603;
|
|
10
10
|
export async function mcpTestCommand(serverName) {
|
|
11
|
+
const normalizedServerName = normalizeMcpServerName(serverName);
|
|
11
12
|
const sources = await resolveAllConfigs();
|
|
12
13
|
const servers = collectServers(sources);
|
|
13
|
-
const info = servers.get(
|
|
14
|
+
const info = servers.get(normalizedServerName);
|
|
14
15
|
if (!info) {
|
|
15
|
-
console.error(status.error(`Server not found: ${
|
|
16
|
+
console.error(status.error(`Server not found: ${normalizedServerName}`));
|
|
16
17
|
console.error(style.gray("Run `omk mcp list` to see available servers."));
|
|
17
18
|
process.exit(1);
|
|
18
19
|
}
|
|
@@ -20,31 +21,31 @@ export async function mcpTestCommand(serverName) {
|
|
|
20
21
|
const activePathOrder = await collectMcpConfigs(resources.mcpScope);
|
|
21
22
|
const activeSources = info.sources.filter((source) => activePathOrder.includes(source));
|
|
22
23
|
if (activeSources.length === 0) {
|
|
23
|
-
console.error(status.error(`Server ${
|
|
24
|
+
console.error(status.error(`Server ${normalizedServerName} is not active in MCP scope "${resources.mcpScope}".`));
|
|
24
25
|
console.error(style.gray(`Defined in: ${info.sources.join(", ")}`));
|
|
25
26
|
process.exit(1);
|
|
26
27
|
}
|
|
27
28
|
const server = selectEffectiveServer(info, activePathOrder);
|
|
28
29
|
if (!server.url && !server.command) {
|
|
29
|
-
console.error(status.error(`Server ${
|
|
30
|
+
console.error(status.error(`Server ${normalizedServerName} has no command`));
|
|
30
31
|
process.exit(1);
|
|
31
32
|
}
|
|
32
|
-
console.log(header(`MCP Test: ${
|
|
33
|
+
console.log(header(`MCP Test: ${normalizedServerName}`));
|
|
33
34
|
if (server.url) {
|
|
34
35
|
console.log(label("URL", sanitizeMcpUrlForDisplay(server.url)));
|
|
35
|
-
await testRemoteMcpServer(
|
|
36
|
+
await testRemoteMcpServer(normalizedServerName, server);
|
|
36
37
|
return;
|
|
37
38
|
}
|
|
38
39
|
const command = server.command;
|
|
39
40
|
if (!command) {
|
|
40
|
-
console.error(status.error(`Server ${
|
|
41
|
+
console.error(status.error(`Server ${normalizedServerName} has no command`));
|
|
41
42
|
process.exit(1);
|
|
42
43
|
}
|
|
43
44
|
console.log(label("Command", maskSensitiveText(command)));
|
|
44
45
|
if (server.args)
|
|
45
46
|
console.log(label("Args", formatArgsForDisplay(server.args)));
|
|
46
47
|
console.log("");
|
|
47
|
-
const testEnv = buildSubprocessEnv(process.env, server.env
|
|
48
|
+
const testEnv = buildSubprocessEnv(process.env, normalizeMcpEnv(server.env));
|
|
48
49
|
// Test 1: executable exists
|
|
49
50
|
const resolved = await which(command);
|
|
50
51
|
if (resolved.failed) {
|
|
@@ -137,8 +138,8 @@ export async function mcpTestCommand(serverName) {
|
|
|
137
138
|
console.error(status.error(`JSON-RPC initialize failed: ${maskSensitiveText(handshakeResult.stderr || "unknown error")}`));
|
|
138
139
|
process.exit(1);
|
|
139
140
|
}
|
|
140
|
-
if (shouldRunOmkProjectProbe(
|
|
141
|
-
await runOmkProjectToolProbe(command, smokeArgs, server.env);
|
|
141
|
+
if (shouldRunOmkProjectProbe(normalizedServerName, server)) {
|
|
142
|
+
await runOmkProjectToolProbe(command, smokeArgs, normalizeMcpEnv(server.env));
|
|
142
143
|
}
|
|
143
144
|
}
|
|
144
145
|
export async function mcpPrewarmCommand(serverName, options = {}) {
|
|
@@ -211,7 +212,7 @@ export async function mcpPrewarmCommand(serverName, options = {}) {
|
|
|
211
212
|
console.log(header(`${isCheck ? "MCP Check" : "MCP Prewarm/Check"}: ${serverName}`));
|
|
212
213
|
console.log(style.gray("Runs the MCP startup probe outside chat; package-manager caches may warm as a side effect."));
|
|
213
214
|
console.log(style.gray("For a zero-global-noise session, run chat/goal/parallel with `--mcp-scope project` or `--mcp-scope none`."));
|
|
214
|
-
await mcpTestCommand(serverName);
|
|
215
|
+
await mcpTestCommand(normalizeMcpServerName(serverName));
|
|
215
216
|
}
|
|
216
217
|
function shouldRunOmkProjectProbe(serverName, server) {
|
|
217
218
|
const target = serverTargetText(server);
|
package/dist/commands/model.js
CHANGED
|
@@ -72,6 +72,8 @@ export async function modelResolveCommand(model, options = {}) {
|
|
|
72
72
|
input: resolved.input,
|
|
73
73
|
provider: resolved.provider,
|
|
74
74
|
model: resolved.model,
|
|
75
|
+
thinking: resolved.thinkingLevel,
|
|
76
|
+
modelVariant: resolved.thinkingLevel ? formatThinkingModelVariant(resolved.model, resolved.thinkingLevel) : undefined,
|
|
75
77
|
source: resolved.source,
|
|
76
78
|
secretValuesPrinted: false,
|
|
77
79
|
tokenFilesRead: false,
|
|
@@ -91,6 +93,8 @@ export async function modelUseCommand(model, options = {}) {
|
|
|
91
93
|
input: resolved.input,
|
|
92
94
|
defaultProvider: result.defaults.provider,
|
|
93
95
|
defaultModel: result.defaults.model,
|
|
96
|
+
thinking: resolved.thinkingLevel,
|
|
97
|
+
modelVariant: resolved.thinkingLevel ? formatThinkingModelVariant(result.defaults.model, resolved.thinkingLevel) : undefined,
|
|
94
98
|
modelSource: resolved.source,
|
|
95
99
|
configPath: result.configPath,
|
|
96
100
|
secretValuesPrinted: false,
|
|
@@ -538,7 +538,9 @@ export function buildProviderOAuthResult(provider, options = {}) {
|
|
|
538
538
|
? "DeepSeek"
|
|
539
539
|
: target === "qwen"
|
|
540
540
|
? "Qwen/DashScope"
|
|
541
|
-
: target
|
|
541
|
+
: target === "glm"
|
|
542
|
+
? "Zhipu GLM"
|
|
543
|
+
: target;
|
|
542
544
|
const setCommand = `omk provider set ${target} --api-key-env ${apiKeyEnv}`;
|
|
543
545
|
const apiKeySetup = target === "deepseek"
|
|
544
546
|
? `For user-local DeepSeek secret storage, use \`omk deepseek api --from-env ${apiKeyEnv}\`; this command does not do that storage.`
|
|
@@ -594,6 +596,8 @@ function defaultApiKeyEnvForProvider(provider) {
|
|
|
594
596
|
return "OPENROUTER_API_KEY";
|
|
595
597
|
if (provider === "qwen")
|
|
596
598
|
return "DASHSCOPE_API_KEY";
|
|
599
|
+
if (provider === "glm")
|
|
600
|
+
return "BIGMODEL_API_KEY";
|
|
597
601
|
return "PROVIDER_API_KEY";
|
|
598
602
|
}
|
|
599
603
|
function normalizeAuthMethodOption(value) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { VersionReport } from "../contracts/index.js";
|
|
2
2
|
export type VersionCommandOptions = {
|
|
3
3
|
json?: boolean;
|
|
4
|
+
commandEnvelope?: boolean;
|
|
4
5
|
};
|
|
5
6
|
export declare function buildVersionReport(): VersionReport;
|
|
6
7
|
export declare function versionCommand(options?: VersionCommandOptions): Promise<void>;
|
package/dist/commands/version.js
CHANGED
|
@@ -5,6 +5,7 @@ import { fileURLToPath } from "node:url";
|
|
|
5
5
|
import { OMK_PACKAGE_NAME, OMK_RELEASE_CHANNEL, OMK_RUNTIME_VERSION, OMK_SCHEMA_VERSIONS, OMK_VERSION_SCHEMA_VERSION, } from "../version.js";
|
|
6
6
|
import { emitJson } from "../util/cli-contract.js";
|
|
7
7
|
import { createOmkJsonEnvelope } from "../util/json-envelope.js";
|
|
8
|
+
import { createOmkCommandEnvelope } from "../util/command-envelope.js";
|
|
8
9
|
import { getOmkVersionSync } from "../util/version.js";
|
|
9
10
|
function packageRoot() {
|
|
10
11
|
const currentFile = fileURLToPath(import.meta.url);
|
|
@@ -65,6 +66,23 @@ export async function versionCommand(options = {}) {
|
|
|
65
66
|
const started = Date.now();
|
|
66
67
|
const report = buildVersionReport();
|
|
67
68
|
if (options.json) {
|
|
69
|
+
if (options.commandEnvelope) {
|
|
70
|
+
emitJson(createOmkCommandEnvelope({
|
|
71
|
+
command: "version",
|
|
72
|
+
status: report.consistent ? "pass" : "fail",
|
|
73
|
+
commit: report.gitCommit,
|
|
74
|
+
data: report,
|
|
75
|
+
diagnostics: report.mismatches.map((mismatch) => ({
|
|
76
|
+
severity: "error",
|
|
77
|
+
code: "VERSION_MISMATCH",
|
|
78
|
+
message: `${mismatch.file}: expected ${mismatch.expected} but found ${mismatch.actual}`,
|
|
79
|
+
redacted: true,
|
|
80
|
+
path: mismatch.file,
|
|
81
|
+
})),
|
|
82
|
+
exitCode: report.consistent ? 0 : 1,
|
|
83
|
+
}));
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
68
86
|
emitJson(createOmkJsonEnvelope({
|
|
69
87
|
command: "version",
|
|
70
88
|
status: report.consistent ? "passed" : "failed",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { OMK_COMMAND_SCHEMA_VERSION } from "../version.js";
|
|
2
|
+
import type { EvidenceRef } from "./evidence.js";
|
|
3
|
+
export type OmkCommandEnvelopeStatus = "pass" | "warn" | "fail";
|
|
4
|
+
export type OmkCommandDiagnosticSeverity = "info" | "warn" | "error";
|
|
5
|
+
export type OmkCommandDiagnostic = {
|
|
6
|
+
severity: OmkCommandDiagnosticSeverity;
|
|
7
|
+
code: string;
|
|
8
|
+
message: string;
|
|
9
|
+
redacted: boolean;
|
|
10
|
+
remediation?: string;
|
|
11
|
+
path?: string;
|
|
12
|
+
};
|
|
13
|
+
export type OmkCommandEnvelope<TData = unknown> = {
|
|
14
|
+
schemaVersion: typeof OMK_COMMAND_SCHEMA_VERSION;
|
|
15
|
+
command: string;
|
|
16
|
+
status: OmkCommandEnvelopeStatus;
|
|
17
|
+
runId?: string;
|
|
18
|
+
commit?: string;
|
|
19
|
+
startedAt: string;
|
|
20
|
+
finishedAt: string;
|
|
21
|
+
data: TData;
|
|
22
|
+
diagnostics: OmkCommandDiagnostic[];
|
|
23
|
+
evidenceRefs: EvidenceRef[];
|
|
24
|
+
exitCode: number;
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { OMK_EVIDENCE_BUNDLE_SCHEMA_VERSION, OMK_RUNTIME_VERSION } from "../version.js";
|
|
2
|
+
import type { DecisionRef } from "./decision.js";
|
|
3
|
+
import type { EvidenceRef } from "./evidence.js";
|
|
4
|
+
export type EvidenceBundleVerdict = "pass" | "warn" | "fail";
|
|
5
|
+
export type EvidenceBundleArtifact = {
|
|
6
|
+
path: string;
|
|
7
|
+
sha256: string;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
kind?: "file" | "log" | "diff" | "metric" | "review" | "custom";
|
|
10
|
+
};
|
|
11
|
+
export type EvidenceBundle = {
|
|
12
|
+
schemaVersion: typeof OMK_EVIDENCE_BUNDLE_SCHEMA_VERSION;
|
|
13
|
+
runId: string;
|
|
14
|
+
nodeId?: string;
|
|
15
|
+
commit: string;
|
|
16
|
+
provider: string;
|
|
17
|
+
model?: string;
|
|
18
|
+
runtimeVersion: typeof OMK_RUNTIME_VERSION | string;
|
|
19
|
+
command: {
|
|
20
|
+
value: string;
|
|
21
|
+
exitCode: number;
|
|
22
|
+
};
|
|
23
|
+
changedFiles: string[];
|
|
24
|
+
diffHash?: string;
|
|
25
|
+
artifacts: EvidenceBundleArtifact[];
|
|
26
|
+
verifier: {
|
|
27
|
+
verdict: EvidenceBundleVerdict;
|
|
28
|
+
version: string;
|
|
29
|
+
checkedAt?: string;
|
|
30
|
+
};
|
|
31
|
+
redaction: {
|
|
32
|
+
applied: boolean;
|
|
33
|
+
summary: string;
|
|
34
|
+
leakedSecretPatterns?: string[];
|
|
35
|
+
};
|
|
36
|
+
evidenceRefs?: EvidenceRef[];
|
|
37
|
+
decisionRefs?: DecisionRef[];
|
|
38
|
+
};
|
|
39
|
+
export type EvidenceBundleIssueKind = "missing_required_field" | "missing_artifact" | "hash_mismatch" | "unlinked_decision" | "stale_commit" | "redaction_violation" | "unsupported_schema";
|
|
40
|
+
export type EvidenceBundleIssue = {
|
|
41
|
+
kind: EvidenceBundleIssueKind;
|
|
42
|
+
severity: "error" | "warn";
|
|
43
|
+
message: string;
|
|
44
|
+
path?: string;
|
|
45
|
+
expected?: string;
|
|
46
|
+
actual?: string;
|
|
47
|
+
};
|
|
48
|
+
export type EvidenceBundleValidationResult = {
|
|
49
|
+
ok: boolean;
|
|
50
|
+
verdict: EvidenceBundleVerdict;
|
|
51
|
+
issues: EvidenceBundleIssue[];
|
|
52
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
export * from "./command.js";
|
|
1
2
|
export * from "./decision.js";
|
|
2
3
|
export * from "./envelope.js";
|
|
3
4
|
export * from "./errors.js";
|
|
4
5
|
export * from "./evidence.js";
|
|
6
|
+
export * from "./evidence-bundle.js";
|
|
5
7
|
export * from "./provider.js";
|
|
6
8
|
export * from "./proof.js";
|
|
7
9
|
export * from "./run.js";
|
package/dist/contracts/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
export * from "./command.js";
|
|
1
2
|
export * from "./decision.js";
|
|
2
3
|
export * from "./envelope.js";
|
|
3
4
|
export * from "./errors.js";
|
|
4
5
|
export * from "./evidence.js";
|
|
6
|
+
export * from "./evidence-bundle.js";
|
|
5
7
|
export * from "./provider.js";
|
|
6
8
|
export * from "./proof.js";
|
|
7
9
|
export * from "./run.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const WEB_BRIDGE_SCHEMA_VERSION: 1;
|
|
2
|
-
export declare const WEB_BRIDGE_NATIVE_HOST_NAME = "io.
|
|
2
|
+
export declare const WEB_BRIDGE_NATIVE_HOST_NAME = "io.omk.web_bridge";
|
|
3
3
|
export declare const WEB_BRIDGE_MCP_SERVER_NAME = "omk-web-bridge";
|
|
4
4
|
export declare const WEB_BRIDGE_MAX_TEXT_CHARS = 120000;
|
|
5
5
|
export declare const WEB_BRIDGE_MAX_PAYLOAD_BYTES = 1000000;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { maskSensitiveText } from "../util/secret-mask.js";
|
|
2
2
|
export const WEB_BRIDGE_SCHEMA_VERSION = 1;
|
|
3
|
-
export const WEB_BRIDGE_NATIVE_HOST_NAME = "io.
|
|
3
|
+
export const WEB_BRIDGE_NATIVE_HOST_NAME = "io.omk.web_bridge";
|
|
4
4
|
export const WEB_BRIDGE_MCP_SERVER_NAME = "omk-web-bridge";
|
|
5
5
|
export const WEB_BRIDGE_MAX_TEXT_CHARS = 120_000;
|
|
6
6
|
export const WEB_BRIDGE_MAX_PAYLOAD_BYTES = 1_000_000;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { EvidenceBundle, EvidenceBundleValidationResult } from "../contracts/evidence-bundle.js";
|
|
2
|
+
export interface ValidateEvidenceBundleOptions {
|
|
3
|
+
root?: string;
|
|
4
|
+
currentCommit?: string;
|
|
5
|
+
requireDecisionRef?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function validateEvidenceBundle(bundle: EvidenceBundle, options?: ValidateEvidenceBundleOptions): EvidenceBundleValidationResult;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolve, isAbsolute, relative } from "node:path";
|
|
4
|
+
import { OMK_EVIDENCE_BUNDLE_SCHEMA_VERSION } from "../version.js";
|
|
5
|
+
function issue(kind, message, details = {}) {
|
|
6
|
+
return {
|
|
7
|
+
kind,
|
|
8
|
+
severity: details.severity ?? "error",
|
|
9
|
+
message,
|
|
10
|
+
...(details.path ? { path: details.path } : {}),
|
|
11
|
+
...(details.expected ? { expected: details.expected } : {}),
|
|
12
|
+
...(details.actual ? { actual: details.actual } : {}),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function sha256File(path) {
|
|
16
|
+
return createHash("sha256").update(readFileSync(path)).digest("hex");
|
|
17
|
+
}
|
|
18
|
+
function hasText(value) {
|
|
19
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
20
|
+
}
|
|
21
|
+
export function validateEvidenceBundle(bundle, options = {}) {
|
|
22
|
+
const issues = [];
|
|
23
|
+
const root = resolve(options.root ?? process.cwd());
|
|
24
|
+
if (bundle.schemaVersion !== OMK_EVIDENCE_BUNDLE_SCHEMA_VERSION) {
|
|
25
|
+
issues.push(issue("unsupported_schema", "Evidence bundle schemaVersion is unsupported", {
|
|
26
|
+
expected: OMK_EVIDENCE_BUNDLE_SCHEMA_VERSION,
|
|
27
|
+
actual: String(bundle.schemaVersion),
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
const requiredFields = [
|
|
31
|
+
["runId", bundle.runId],
|
|
32
|
+
["commit", bundle.commit],
|
|
33
|
+
["provider", bundle.provider],
|
|
34
|
+
["runtimeVersion", bundle.runtimeVersion],
|
|
35
|
+
["command.value", bundle.command?.value],
|
|
36
|
+
["verifier.version", bundle.verifier?.version],
|
|
37
|
+
["redaction.summary", bundle.redaction?.summary],
|
|
38
|
+
];
|
|
39
|
+
for (const [field, value] of requiredFields) {
|
|
40
|
+
if (!hasText(value)) {
|
|
41
|
+
issues.push(issue("missing_required_field", `Evidence bundle is missing ${field}`));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (typeof bundle.command?.exitCode !== "number" || !Number.isInteger(bundle.command.exitCode)) {
|
|
45
|
+
issues.push(issue("missing_required_field", "Evidence bundle command.exitCode must be an integer"));
|
|
46
|
+
}
|
|
47
|
+
if (!Array.isArray(bundle.artifacts) || bundle.artifacts.length === 0) {
|
|
48
|
+
issues.push(issue("missing_artifact", "Evidence bundle must link at least one artifact"));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
for (const artifact of bundle.artifacts) {
|
|
52
|
+
if (!hasText(artifact.path)) {
|
|
53
|
+
issues.push(issue("missing_artifact", "Evidence artifact is missing a path"));
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (isAbsolute(artifact.path) || artifact.path.split(/[\\/]+/u).includes("..")) {
|
|
57
|
+
issues.push(issue("missing_artifact", "Evidence artifact path must stay inside the validation root", { path: artifact.path }));
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const artifactPath = resolve(root, artifact.path);
|
|
61
|
+
const rel = relative(root, artifactPath);
|
|
62
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
63
|
+
issues.push(issue("missing_artifact", "Evidence artifact path escapes the validation root", { path: artifact.path }));
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const actual = sha256File(artifactPath);
|
|
68
|
+
if (actual !== artifact.sha256) {
|
|
69
|
+
issues.push(issue("hash_mismatch", "Evidence artifact sha256 mismatch", {
|
|
70
|
+
path: artifact.path,
|
|
71
|
+
expected: artifact.sha256,
|
|
72
|
+
actual,
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
issues.push(issue("missing_artifact", "Evidence artifact file is missing", { path: artifact.path }));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (options.currentCommit && bundle.commit !== options.currentCommit) {
|
|
82
|
+
issues.push(issue("stale_commit", "Evidence bundle commit does not match current commit", {
|
|
83
|
+
expected: options.currentCommit,
|
|
84
|
+
actual: bundle.commit,
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
if (options.requireDecisionRef && (!bundle.decisionRefs || bundle.decisionRefs.length === 0)) {
|
|
88
|
+
issues.push(issue("unlinked_decision", "Evidence bundle has no linked decision reference"));
|
|
89
|
+
}
|
|
90
|
+
if (bundle.redaction?.leakedSecretPatterns && bundle.redaction.leakedSecretPatterns.length > 0) {
|
|
91
|
+
issues.push(issue("redaction_violation", "Evidence bundle reports leaked secret patterns", {
|
|
92
|
+
actual: bundle.redaction.leakedSecretPatterns.join(","),
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
const errors = issues.filter((item) => item.severity === "error");
|
|
96
|
+
const verifierVerdict = bundle.verifier?.verdict ?? "fail";
|
|
97
|
+
const verdict = errors.length > 0 || verifierVerdict === "fail"
|
|
98
|
+
? "fail"
|
|
99
|
+
: issues.length > 0 || verifierVerdict === "warn"
|
|
100
|
+
? "warn"
|
|
101
|
+
: "pass";
|
|
102
|
+
return { ok: verdict !== "fail", verdict, issues };
|
|
103
|
+
}
|
package/dist/evidence/index.d.ts
CHANGED
|
@@ -15,7 +15,12 @@ export type { DecisionTraceStore } from "./decision-trace.js";
|
|
|
15
15
|
export { createDecisionTraceStore } from "./decision-trace.js";
|
|
16
16
|
export type { ProofTrustMvpEngine, ProofTrustResult } from "./proof-trust.js";
|
|
17
17
|
export { createProofTrustMvpEngine } from "./proof-trust.js";
|
|
18
|
+
export type { TrustCalibrationExample, TrustCalibrationResult, TrustFieldKey, TrustWeights } from "./trust-calibration.js";
|
|
19
|
+
export { calibrateTrustWeights, DEFAULT_TRUST_WEIGHTS, scoreTrustFeatures, TRUST_FIELD_KEYS } from "./trust-calibration.js";
|
|
18
20
|
export type { EtsClaim, EtsClaimCategory, EtsTaskType, EtsRiskTier, RequiredEvidenceItem, RunArtifactMeta, CollectedEvidence, EvidenceVerificationResult, EtsV2Result, EtsV2Engine, EtsV2Params, EtsV2EngineOptions, } from "./evidence-trust-score.js";
|
|
19
21
|
export { extractClaims, requiredEvidenceForClaim, collectEvidenceFromRunDir, verifyEvidence, createEvidenceTrustScoreV2Engine, createEvidenceTrustScore, } from "./evidence-trust-score.js";
|
|
22
|
+
export type { EvidenceBundle, EvidenceBundleArtifact, EvidenceBundleIssue, EvidenceBundleIssueKind, EvidenceBundleValidationResult, EvidenceBundleVerdict, } from "../contracts/evidence-bundle.js";
|
|
23
|
+
export type { ValidateEvidenceBundleOptions } from "./bundle-validator.js";
|
|
24
|
+
export { validateEvidenceBundle } from "./bundle-validator.js";
|
|
20
25
|
export type { AlgorithmSpec, ReleaseCandidate, RegressionProofMatrixResult, RegressionProofMatrixEngine, RegressionProofMatrixOptions, } from "./regression-proof-matrix.js";
|
|
21
26
|
export { createRegressionProofMatrixEngine } from "./regression-proof-matrix.js";
|
package/dist/evidence/index.js
CHANGED
|
@@ -6,5 +6,7 @@ export { createRunTraceStore } from "./run-trace.js";
|
|
|
6
6
|
export { decideRepair } from "../orchestration/repair-policy.js";
|
|
7
7
|
export { createDecisionTraceStore } from "./decision-trace.js";
|
|
8
8
|
export { createProofTrustMvpEngine } from "./proof-trust.js";
|
|
9
|
+
export { calibrateTrustWeights, DEFAULT_TRUST_WEIGHTS, scoreTrustFeatures, TRUST_FIELD_KEYS } from "./trust-calibration.js";
|
|
9
10
|
export { extractClaims, requiredEvidenceForClaim, collectEvidenceFromRunDir, verifyEvidence, createEvidenceTrustScoreV2Engine, createEvidenceTrustScore, } from "./evidence-trust-score.js";
|
|
11
|
+
export { validateEvidenceBundle } from "./bundle-validator.js";
|
|
10
12
|
export { createRegressionProofMatrixEngine } from "./regression-proof-matrix.js";
|
|
@@ -8,18 +8,10 @@ import { createHash } from "node:crypto";
|
|
|
8
8
|
import { existsSync } from "node:fs";
|
|
9
9
|
import { readFile, readdir, stat } from "node:fs/promises";
|
|
10
10
|
import { isAbsolute, join, relative } from "node:path";
|
|
11
|
+
import { DEFAULT_TRUST_WEIGHTS } from "./trust-calibration.js";
|
|
11
12
|
// ─── Constants ─────────────────────────────────────────────────────────────
|
|
12
13
|
const EXPECTED_SCHEMA_VERSION = "omk.proof-bundle.v1";
|
|
13
|
-
const WEIGHTS =
|
|
14
|
-
schema: 0.15,
|
|
15
|
-
commands: 0.15,
|
|
16
|
-
stdout: 0.10,
|
|
17
|
-
hashes: 0.15,
|
|
18
|
-
decisions: 0.15,
|
|
19
|
-
evidence: 0.15,
|
|
20
|
-
limitations: 0.05,
|
|
21
|
-
replay: 0.10,
|
|
22
|
-
};
|
|
14
|
+
const WEIGHTS = DEFAULT_TRUST_WEIGHTS;
|
|
23
15
|
const FIELD_TO_MISSING = {
|
|
24
16
|
schema: "schema",
|
|
25
17
|
commands: "commands",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare const TRUST_FIELD_KEYS: readonly ["schema", "commands", "stdout", "hashes", "decisions", "evidence", "limitations", "replay"];
|
|
2
|
+
export type TrustFieldKey = typeof TRUST_FIELD_KEYS[number];
|
|
3
|
+
export type TrustWeights = Record<TrustFieldKey, number>;
|
|
4
|
+
export interface TrustCalibrationExample {
|
|
5
|
+
readonly features: Record<TrustFieldKey, 0 | 1>;
|
|
6
|
+
readonly success: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface TrustCalibrationResult {
|
|
9
|
+
readonly adopted: boolean;
|
|
10
|
+
readonly weights: TrustWeights;
|
|
11
|
+
readonly threshold: number;
|
|
12
|
+
readonly baselineAuc: number;
|
|
13
|
+
readonly candidateAuc: number;
|
|
14
|
+
readonly reason: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const DEFAULT_TRUST_WEIGHTS: TrustWeights;
|
|
17
|
+
export declare function scoreTrustFeatures(features: Record<TrustFieldKey, number>, weights?: TrustWeights): number;
|
|
18
|
+
export declare function calibrateTrustWeights(data: readonly TrustCalibrationExample[], options?: {
|
|
19
|
+
minSamples?: number;
|
|
20
|
+
epsilon?: number;
|
|
21
|
+
iterations?: number;
|
|
22
|
+
learningRate?: number;
|
|
23
|
+
priorSigma?: number;
|
|
24
|
+
}): TrustCalibrationResult;
|
|
25
|
+
export declare function normalizeTrustWeights(weights: TrustWeights): TrustWeights;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
export const TRUST_FIELD_KEYS = [
|
|
2
|
+
"schema",
|
|
3
|
+
"commands",
|
|
4
|
+
"stdout",
|
|
5
|
+
"hashes",
|
|
6
|
+
"decisions",
|
|
7
|
+
"evidence",
|
|
8
|
+
"limitations",
|
|
9
|
+
"replay",
|
|
10
|
+
];
|
|
11
|
+
export const DEFAULT_TRUST_WEIGHTS = Object.freeze({
|
|
12
|
+
schema: 0.15,
|
|
13
|
+
commands: 0.15,
|
|
14
|
+
stdout: 0.10,
|
|
15
|
+
hashes: 0.15,
|
|
16
|
+
decisions: 0.15,
|
|
17
|
+
evidence: 0.15,
|
|
18
|
+
limitations: 0.05,
|
|
19
|
+
replay: 0.10,
|
|
20
|
+
});
|
|
21
|
+
export function scoreTrustFeatures(features, weights = DEFAULT_TRUST_WEIGHTS) {
|
|
22
|
+
return round6(TRUST_FIELD_KEYS.reduce((sum, key) => sum + (weights[key] * (features[key] ? 1 : 0)), 0));
|
|
23
|
+
}
|
|
24
|
+
export function calibrateTrustWeights(data, options = {}) {
|
|
25
|
+
const minSamples = options.minSamples ?? 100;
|
|
26
|
+
if (data.length < minSamples) {
|
|
27
|
+
return {
|
|
28
|
+
adopted: false,
|
|
29
|
+
weights: { ...DEFAULT_TRUST_WEIGHTS },
|
|
30
|
+
threshold: 0.75,
|
|
31
|
+
baselineAuc: 0,
|
|
32
|
+
candidateAuc: 0,
|
|
33
|
+
reason: `insufficient labeled runs: ${data.length} < ${minSamples}`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const beta = fitLogisticMap(data, options);
|
|
37
|
+
const weights = normalizeTrustWeights(Object.fromEntries(TRUST_FIELD_KEYS.map((key, index) => [key, Math.max(options.epsilon ?? 0.01, beta[index])])));
|
|
38
|
+
const baselineScores = data.map((example) => scoreTrustFeatures(example.features, DEFAULT_TRUST_WEIGHTS));
|
|
39
|
+
const candidateScores = data.map((example) => scoreTrustFeatures(example.features, weights));
|
|
40
|
+
const labels = data.map((example) => example.success);
|
|
41
|
+
const baselineAuc = auc(baselineScores, labels);
|
|
42
|
+
const candidateAuc = auc(candidateScores, labels);
|
|
43
|
+
const threshold = youdenThreshold(candidateScores, labels);
|
|
44
|
+
const adopted = candidateAuc > baselineAuc;
|
|
45
|
+
return {
|
|
46
|
+
adopted,
|
|
47
|
+
weights: adopted ? weights : { ...DEFAULT_TRUST_WEIGHTS },
|
|
48
|
+
threshold: adopted ? threshold : 0.75,
|
|
49
|
+
baselineAuc,
|
|
50
|
+
candidateAuc,
|
|
51
|
+
reason: adopted
|
|
52
|
+
? `candidate trust weights improved AUC by ${(candidateAuc - baselineAuc).toFixed(4)}`
|
|
53
|
+
: "current trust weights not yet beaten by labeled evidence",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function normalizeTrustWeights(weights) {
|
|
57
|
+
const positive = Object.fromEntries(TRUST_FIELD_KEYS.map((key) => [key, Math.max(0, Number(weights[key]) || 0)]));
|
|
58
|
+
const sum = TRUST_FIELD_KEYS.reduce((acc, key) => acc + positive[key], 0);
|
|
59
|
+
if (sum <= 0)
|
|
60
|
+
return { ...DEFAULT_TRUST_WEIGHTS };
|
|
61
|
+
return Object.fromEntries(TRUST_FIELD_KEYS.map((key) => [key, round6(positive[key] / sum)]));
|
|
62
|
+
}
|
|
63
|
+
function fitLogisticMap(data, options = {}) {
|
|
64
|
+
const iterations = options.iterations ?? 500;
|
|
65
|
+
const learningRate = options.learningRate ?? 0.05;
|
|
66
|
+
const priorSigma = options.priorSigma ?? 1;
|
|
67
|
+
const prior = TRUST_FIELD_KEYS.map((key) => DEFAULT_TRUST_WEIGHTS[key]);
|
|
68
|
+
const beta = [...prior];
|
|
69
|
+
let intercept = 0;
|
|
70
|
+
for (let iter = 0; iter < iterations; iter += 1) {
|
|
71
|
+
const grad = new Array(beta.length).fill(0);
|
|
72
|
+
let interceptGrad = 0;
|
|
73
|
+
for (const example of data) {
|
|
74
|
+
const x = TRUST_FIELD_KEYS.map((key) => example.features[key]);
|
|
75
|
+
const y = example.success ? 1 : 0;
|
|
76
|
+
const p = sigmoid(intercept + dot(beta, x));
|
|
77
|
+
const error = p - y;
|
|
78
|
+
interceptGrad += error;
|
|
79
|
+
for (let i = 0; i < beta.length; i += 1)
|
|
80
|
+
grad[i] += error * x[i];
|
|
81
|
+
}
|
|
82
|
+
intercept -= learningRate * (interceptGrad / data.length);
|
|
83
|
+
for (let i = 0; i < beta.length; i += 1) {
|
|
84
|
+
const shrinkage = (beta[i] - prior[i]) / (priorSigma * priorSigma);
|
|
85
|
+
beta[i] -= learningRate * ((grad[i] / data.length) + shrinkage);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return beta;
|
|
89
|
+
}
|
|
90
|
+
function auc(scores, labels) {
|
|
91
|
+
const positives = [];
|
|
92
|
+
const negatives = [];
|
|
93
|
+
for (let i = 0; i < scores.length; i += 1) {
|
|
94
|
+
if (labels[i])
|
|
95
|
+
positives.push(scores[i]);
|
|
96
|
+
else
|
|
97
|
+
negatives.push(scores[i]);
|
|
98
|
+
}
|
|
99
|
+
if (positives.length === 0 || negatives.length === 0)
|
|
100
|
+
return 0.5;
|
|
101
|
+
let wins = 0;
|
|
102
|
+
for (const pos of positives) {
|
|
103
|
+
for (const neg of negatives) {
|
|
104
|
+
if (pos > neg)
|
|
105
|
+
wins += 1;
|
|
106
|
+
else if (pos === neg)
|
|
107
|
+
wins += 0.5;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return round6(wins / (positives.length * negatives.length));
|
|
111
|
+
}
|
|
112
|
+
function youdenThreshold(scores, labels) {
|
|
113
|
+
const thresholds = [...new Set(scores)].sort((a, b) => a - b);
|
|
114
|
+
let best = thresholds[0] ?? 0.75;
|
|
115
|
+
let bestJ = -Infinity;
|
|
116
|
+
for (const threshold of thresholds) {
|
|
117
|
+
let tp = 0;
|
|
118
|
+
let tn = 0;
|
|
119
|
+
let fp = 0;
|
|
120
|
+
let fn = 0;
|
|
121
|
+
for (let i = 0; i < scores.length; i += 1) {
|
|
122
|
+
const predicted = scores[i] >= threshold;
|
|
123
|
+
const actual = labels[i];
|
|
124
|
+
if (predicted && actual)
|
|
125
|
+
tp += 1;
|
|
126
|
+
else if (predicted && !actual)
|
|
127
|
+
fp += 1;
|
|
128
|
+
else if (!predicted && actual)
|
|
129
|
+
fn += 1;
|
|
130
|
+
else
|
|
131
|
+
tn += 1;
|
|
132
|
+
}
|
|
133
|
+
const sensitivity = tp / Math.max(1, tp + fn);
|
|
134
|
+
const specificity = tn / Math.max(1, tn + fp);
|
|
135
|
+
const j = sensitivity + specificity - 1;
|
|
136
|
+
if (j > bestJ) {
|
|
137
|
+
bestJ = j;
|
|
138
|
+
best = threshold;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return round6(best);
|
|
142
|
+
}
|
|
143
|
+
function sigmoid(value) {
|
|
144
|
+
return 1 / (1 + Math.exp(-value));
|
|
145
|
+
}
|
|
146
|
+
function dot(a, b) {
|
|
147
|
+
return a.reduce((sum, value, index) => sum + value * b[index], 0);
|
|
148
|
+
}
|
|
149
|
+
function round6(value) {
|
|
150
|
+
return Math.round(value * 1_000_000) / 1_000_000;
|
|
151
|
+
}
|
|
@@ -777,7 +777,7 @@ async function handleTailRunEvents(args) {
|
|
|
777
777
|
afterSeq: typeof args.afterSeq === "number" ? args.afterSeq : undefined,
|
|
778
778
|
limit: typeof args.limit === "number" ? Math.max(0, Math.min(500, args.limit)) : 200,
|
|
779
779
|
});
|
|
780
|
-
return { events: redactSecrets(events), source: "events.
|
|
780
|
+
return { events: redactSecrets(events), source: "events.ndjson" };
|
|
781
781
|
}
|
|
782
782
|
async function handleReadRunState(args) {
|
|
783
783
|
const runId = sanitizeRunId(args.runId);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ProvenanceLayerInput {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly addedModifiedLines: number;
|
|
4
|
+
readonly loc: number;
|
|
5
|
+
readonly importance: number;
|
|
6
|
+
}
|
|
7
|
+
export interface ProvenanceLayerResult extends ProvenanceLayerInput {
|
|
8
|
+
readonly originality: number;
|
|
9
|
+
readonly weightedOriginality: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ProvenanceRatioResult {
|
|
12
|
+
readonly headlineOriginality: number;
|
|
13
|
+
readonly layers: readonly ProvenanceLayerResult[];
|
|
14
|
+
readonly importanceSum: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function computeProvenanceRatio(layers: readonly ProvenanceLayerInput[]): ProvenanceRatioResult;
|