oh-my-knowledge 0.48.0 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -18
- package/README.zh.md +55 -23
- package/dist/analysis/coverage-analyzer.d.ts +1 -0
- package/dist/analysis/coverage-analyzer.js +125 -62
- package/dist/analysis/failure-clusterer.js +2 -1
- package/dist/analysis/gap-analyzer.d.ts +2 -2
- package/dist/analysis/gap-analyzer.js +13 -3
- package/dist/analysis/hedging-classifier.d.ts +2 -2
- package/dist/analysis/hedging-classifier.js +3 -4
- package/dist/analysis/report-diagnostics.js +9 -7
- package/dist/analysis/sample-diagnostics.js +6 -6
- package/dist/artifact-graph/doctor.js +15 -7
- package/dist/assets/agent-skills/omk/SKILL.md +27 -7
- package/dist/assets/agent-skills/omk/references/commands.md +18 -17
- package/dist/authoring/evolver.d.ts +10 -6
- package/dist/authoring/evolver.js +496 -83
- package/dist/authoring/generator.d.ts +3 -3
- package/dist/authoring/generator.js +5 -10
- package/dist/authoring/sample-fixer.d.ts +8 -6
- package/dist/authoring/sample-fixer.js +76 -5
- package/dist/cli/commands/doctor.js +31 -14
- package/dist/cli/commands/eval/index.d.ts +3 -0
- package/dist/cli/commands/eval/index.js +163 -17
- package/dist/cli/commands/evolve.d.ts +4 -4
- package/dist/cli/commands/evolve.js +27 -13
- package/dist/cli/commands/init.js +16 -3
- package/dist/cli/commands/observe/inbox.js +28 -21
- package/dist/cli/commands/observe/index.js +20 -11
- package/dist/cli/commands/observe/ingest.d.ts +3 -0
- package/dist/cli/commands/observe/ingest.js +30 -2
- package/dist/cli/commands/sample.d.ts +6 -3
- package/dist/cli/commands/sample.js +72 -68
- package/dist/cli/lib/codex-model-hint.d.ts +9 -0
- package/dist/cli/lib/codex-model-hint.js +45 -0
- package/dist/cli/lib/generation-failure-hint.d.ts +2 -0
- package/dist/cli/lib/generation-failure-hint.js +61 -0
- package/dist/cli/lib/i18n-dict/common.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/common.js +4 -0
- package/dist/cli/lib/i18n-dict/gen.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/gen.js +38 -6
- package/dist/cli/lib/i18n-dict/help.js +6 -6
- package/dist/cli/lib/i18n-dict/init.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/init.js +13 -9
- package/dist/cli/lib/i18n-dict/run.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/run.js +34 -2
- package/dist/cli/lib/llm-failure-classifier.d.ts +2 -0
- package/dist/cli/lib/llm-failure-classifier.js +8 -0
- package/dist/cli/lib/parse-run-config.d.ts +6 -5
- package/dist/cli/lib/parse-run-config.js +16 -9
- package/dist/cli/lib/runtime-defaults.d.ts +21 -0
- package/dist/cli/lib/runtime-defaults.js +79 -0
- package/dist/diagnosis/observe-mapper.js +14 -15
- package/dist/diagnosis/observe-producer.js +3 -1
- package/dist/diagnosis/studio-projection.js +14 -7
- package/dist/diagnosis/types.d.ts +2 -0
- package/dist/diagnosis/types.js +12 -0
- package/dist/doctor/endpoint-rule.js +2 -1
- package/dist/eval-core/artifact-file-names.js +18 -1
- package/dist/eval-core/artifact-index.d.ts +7 -11
- package/dist/eval-core/artifact-index.js +139 -80
- package/dist/eval-core/cache.d.ts +12 -3
- package/dist/eval-core/cache.js +89 -29
- package/dist/eval-core/comparability.js +10 -6
- package/dist/eval-core/evaluation-execution.d.ts +2 -1
- package/dist/eval-core/evaluation-execution.js +122 -37
- package/dist/eval-core/evaluation-job.d.ts +4 -1
- package/dist/eval-core/evaluation-job.js +4 -1
- package/dist/eval-core/evaluation-reporting.d.ts +15 -13
- package/dist/eval-core/evaluation-reporting.js +54 -52
- package/dist/eval-core/execution-strategy.d.ts +2 -0
- package/dist/eval-core/execution-strategy.js +11 -9
- package/dist/eval-core/fact-checker.js +15 -7
- package/dist/eval-core/holdout.js +3 -2
- package/dist/eval-core/judge-independence.d.ts +2 -2
- package/dist/eval-core/mock-hook.cjs +23 -6
- package/dist/eval-core/mocks-runtime.js +30 -8
- package/dist/eval-core/report-document.d.ts +12 -0
- package/dist/eval-core/report-document.js +1151 -0
- package/dist/eval-core/report-extensions.d.ts +4 -0
- package/dist/eval-core/report-extensions.js +500 -0
- package/dist/eval-core/report-file-migration.js +7 -2
- package/dist/eval-core/resume-compatibility.d.ts +31 -0
- package/dist/eval-core/resume-compatibility.js +141 -0
- package/dist/eval-core/sample-fingerprint.d.ts +12 -0
- package/dist/eval-core/sample-fingerprint.js +193 -0
- package/dist/eval-core/schema.js +86 -31
- package/dist/eval-core/verdict.d.ts +8 -4
- package/dist/eval-core/verdict.js +24 -10
- package/dist/eval-workflows/batch-evaluation-workflow.d.ts +2 -1
- package/dist/eval-workflows/batch-evaluation-workflow.js +25 -12
- package/dist/eval-workflows/evaluation-pipeline/preflight-warnings.d.ts +10 -5
- package/dist/eval-workflows/evaluation-pipeline/preflight-warnings.js +58 -21
- package/dist/eval-workflows/evaluation-pipeline/report-finalize.js +3 -1
- package/dist/eval-workflows/evaluation-pipeline/run-state.d.ts +4 -1
- package/dist/eval-workflows/evaluation-pipeline/run-state.js +4 -1
- package/dist/eval-workflows/evaluation-pipeline/test-set-hash.d.ts +6 -5
- package/dist/eval-workflows/evaluation-pipeline/test-set-hash.js +17 -10
- package/dist/eval-workflows/evaluation-pipeline.js +12 -7
- package/dist/eval-workflows/run-evaluation.d.ts +9 -7
- package/dist/eval-workflows/run-evaluation.js +79 -51
- package/dist/executors/anthropic-api.js +65 -9
- package/dist/executors/claude-cli.js +16 -79
- package/dist/executors/claude-protocol.d.ts +28 -0
- package/dist/executors/claude-protocol.js +180 -0
- package/dist/executors/claude-sdk-trace.js +56 -28
- package/dist/executors/claude-sdk.d.ts +1 -0
- package/dist/executors/claude-sdk.js +39 -93
- package/dist/executors/codex-cli-trace.js +166 -31
- package/dist/executors/codex-cli.d.ts +6 -8
- package/dist/executors/codex-cli.js +49 -151
- package/dist/executors/codex-protocol.d.ts +24 -0
- package/dist/executors/codex-protocol.js +234 -0
- package/dist/executors/codex-sdk.js +68 -120
- package/dist/executors/gemini.js +88 -13
- package/dist/executors/index.d.ts +2 -3
- package/dist/executors/index.js +5 -3
- package/dist/executors/openai-api.js +70 -9
- package/dist/executors/runtime-fingerprint.js +88 -11
- package/dist/executors/script-command.d.ts +8 -0
- package/dist/executors/script-command.js +87 -0
- package/dist/executors/script.js +202 -29
- package/dist/executors/shared.d.ts +35 -3
- package/dist/executors/shared.js +113 -15
- package/dist/grading/assertions.d.ts +1 -1
- package/dist/grading/assertions.js +19 -9
- package/dist/grading/diagnostic.d.ts +9 -2
- package/dist/grading/diagnostic.js +25 -2
- package/dist/grading/index.js +10 -4
- package/dist/grading/judge.js +19 -6
- package/dist/grading/layered-scores.d.ts +2 -3
- package/dist/grading/layered-scores.js +2 -3
- package/dist/inputs/load-samples.d.ts +1 -2
- package/dist/inputs/load-samples.js +23 -1
- package/dist/inputs/mcp-resolver.js +6 -3
- package/dist/inputs/sample-document.d.ts +11 -0
- package/dist/inputs/sample-document.js +96 -0
- package/dist/managed/evidence.d.ts +1 -0
- package/dist/managed/evidence.js +1 -1
- package/dist/managed/store.js +200 -91
- package/dist/observability/codex-trace-adapter.d.ts +5 -0
- package/dist/observability/codex-trace-adapter.js +850 -0
- package/dist/observability/experience.d.ts +32 -6
- package/dist/observability/experience.js +2695 -459
- package/dist/observability/feedback-matchers.js +16 -1
- package/dist/observability/inbox-view-model.d.ts +1 -1
- package/dist/observability/inbox-view-model.js +19 -14
- package/dist/observability/inbox.d.ts +7 -1
- package/dist/observability/inbox.js +632 -124
- package/dist/observability/problem-patterns.js +2 -0
- package/dist/observability/review-state.d.ts +6 -0
- package/dist/observability/review-state.js +235 -63
- package/dist/observability/skill-chain-advisories.js +1 -1
- package/dist/observability/skill-chain.js +17 -4
- package/dist/observability/skill-health-analyzer.d.ts +32 -7
- package/dist/observability/skill-health-analyzer.js +194 -121
- package/dist/observability/skill-health-report.d.ts +10 -0
- package/dist/observability/skill-health-report.js +620 -0
- package/dist/observability/soft-standards/constants.d.ts +0 -1
- package/dist/observability/soft-standards/constants.js +0 -1
- package/dist/observability/soft-standards/index.d.ts +1 -1
- package/dist/observability/soft-standards/index.js +1 -1
- package/dist/observability/soft-standards/llm-extractor.js +8 -10
- package/dist/observability/soft-standards/skill-standards-store.d.ts +2 -1
- package/dist/observability/soft-standards/skill-standards-store.js +59 -18
- package/dist/observability/soft-standards/types.d.ts +2 -2
- package/dist/observability/trace-adapter.d.ts +12 -7
- package/dist/observability/trace-adapter.js +11 -9
- package/dist/observability/trace-attribution.d.ts +13 -5
- package/dist/observability/trace-attribution.js +315 -21
- package/dist/observability/trace-ingestion.d.ts +9 -0
- package/dist/observability/trace-ingestion.js +80 -0
- package/dist/observability/trace-ir.d.ts +113 -0
- package/dist/observability/trace-ir.js +87 -0
- package/dist/observability/trace-segmenter.d.ts +19 -6
- package/dist/observability/trace-segmenter.js +377 -196
- package/dist/observability/trace-session-index.d.ts +19 -0
- package/dist/observability/trace-session-index.js +68 -0
- package/dist/observability/trace-source.d.ts +12 -4
- package/dist/observability/trace-source.js +939 -215
- package/dist/renderer/html-renderer.js +37 -6
- package/dist/renderer/icons.js +3 -0
- package/dist/renderer/observation-inbox-renderer.js +208 -90
- package/dist/renderer/skill-detail-renderer.js +452 -109
- package/dist/renderer/skill-health-renderer.js +69 -12
- package/dist/renderer/summary.js +28 -7
- package/dist/renderer/table.js +21 -4
- package/dist/renderer/test-view.d.ts +1 -0
- package/dist/renderer/test-view.js +44 -9
- package/dist/server/indexed-report-store.js +14 -18
- package/dist/server/job-store.js +64 -26
- package/dist/server/report-server.js +190 -78
- package/dist/server/report-store.js +57 -80
- package/dist/server/skill-index.js +143 -49
- package/dist/server/skill-insights.js +44 -5
- package/dist/shared/artifact-graph.d.ts +3 -0
- package/dist/shared/artifact-graph.js +224 -0
- package/dist/shared/assertion-types.d.ts +8 -0
- package/dist/shared/assertion-types.js +46 -0
- package/dist/shared/atomic-json.d.ts +8 -0
- package/dist/shared/atomic-json.js +33 -0
- package/dist/shared/diagnosis-schema.d.ts +9 -0
- package/dist/shared/diagnosis-schema.js +181 -0
- package/dist/shared/doctor-report.d.ts +3 -0
- package/dist/shared/doctor-report.js +103 -0
- package/dist/shared/evaluation-job.d.ts +6 -0
- package/dist/shared/evaluation-job.js +217 -0
- package/dist/shared/executor-result.d.ts +17 -0
- package/dist/shared/executor-result.js +221 -0
- package/dist/shared/file-lock.d.ts +12 -0
- package/dist/shared/file-lock.js +129 -0
- package/dist/shared/json-value.d.ts +5 -0
- package/dist/shared/json-value.js +36 -0
- package/dist/shared/keyed-mutex.d.ts +7 -0
- package/dist/shared/keyed-mutex.js +24 -0
- package/dist/shared/record-count.d.ts +8 -0
- package/dist/shared/record-count.js +43 -0
- package/dist/shared/sample-contract.d.ts +3 -0
- package/dist/shared/sample-contract.js +332 -0
- package/dist/shared/timestamp.d.ts +6 -0
- package/dist/shared/timestamp.js +64 -0
- package/dist/shared/token-usage.d.ts +19 -0
- package/dist/shared/token-usage.js +50 -0
- package/dist/shared/tool-call-status.d.ts +8 -0
- package/dist/shared/tool-call-status.js +28 -0
- package/dist/shared/tool-identity.d.ts +21 -0
- package/dist/shared/tool-identity.js +84 -0
- package/dist/shared/tool-search.js +73 -16
- package/dist/shared/trace-projection.d.ts +5 -0
- package/dist/shared/trace-projection.js +20 -0
- package/dist/shared/trace-source-kind.d.ts +3 -0
- package/dist/shared/trace-source-kind.js +12 -0
- package/dist/types/diagnosis.d.ts +2 -0
- package/dist/types/eval.d.ts +4 -0
- package/dist/types/executor.d.ts +32 -5
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/judge.d.ts +2 -0
- package/dist/types/observability.d.ts +116 -9
- package/dist/types/report.d.ts +58 -6
- package/dist/types/skill-index.d.ts +7 -0
- package/dist/types/trace.d.ts +2 -0
- package/dist/types/trace.js +1 -0
- package/package.json +9 -5
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { dirname } from 'node:path';
|
|
2
|
-
import { existsSync, mkdirSync } from 'node:fs';
|
|
3
2
|
import { DEFAULT_ISOLATED_CWD_DIR } from './default-dirs.js';
|
|
4
3
|
/**
|
|
5
4
|
* Isolated cwd for strict baseline. Empty dir under ~/.oh-my-knowledge/
|
|
@@ -8,14 +7,11 @@ import { DEFAULT_ISOLATED_CWD_DIR } from './default-dirs.js';
|
|
|
8
7
|
* leak the skill content into baseline via plain file-system access, even when
|
|
9
8
|
* Skill auto-discovery is blocked).
|
|
10
9
|
*
|
|
11
|
-
*
|
|
10
|
+
* This is a stable logical path for cache identity. executeTasks replaces it
|
|
11
|
+
* with a fresh physical directory for every executor attempt, then removes it.
|
|
12
12
|
*/
|
|
13
13
|
function getIsolatedCwd() {
|
|
14
|
-
|
|
15
|
-
if (!existsSync(dir)) {
|
|
16
|
-
mkdirSync(dir, { recursive: true });
|
|
17
|
-
}
|
|
18
|
-
return dir;
|
|
14
|
+
return DEFAULT_ISOLATED_CWD_DIR;
|
|
19
15
|
}
|
|
20
16
|
function combineUserPrompt(prefix, prompt) {
|
|
21
17
|
if (!prefix)
|
|
@@ -84,6 +80,11 @@ function extractSkillDir(artifact) {
|
|
|
84
80
|
return dirname(artifact.locator);
|
|
85
81
|
}
|
|
86
82
|
export function resolveExecutionStrategy(task, model, timeoutMs, verbose, effort, samplesBaseDir) {
|
|
83
|
+
if (Array.isArray(task.artifact.allowedSkills)
|
|
84
|
+
&& task.artifact.allowedSkills.length > 0) {
|
|
85
|
+
throw new Error(`skill 白名单(allowedSkills=${JSON.stringify(task.artifact.allowedSkills)})不再支持:`
|
|
86
|
+
+ '非空白名单无法在所有执行器上保证隔离。请使用 [](完全隔离)或省略该字段。');
|
|
87
|
+
}
|
|
87
88
|
const skillDir = extractSkillDir(task.artifact);
|
|
88
89
|
// strict-baseline cwd 沙箱:baseline + allowedSkills===[] + 用户没显式
|
|
89
90
|
// cwd 时,改用 isolated empty dir。否则 baseline 的 Glob/Read 会走进用户工作目录
|
|
@@ -102,8 +103,8 @@ export function resolveExecutionStrategy(task, model, timeoutMs, verbose, effort
|
|
|
102
103
|
...(effort && { effort }),
|
|
103
104
|
// pass skill-isolation declaration to executors. undefined keeps
|
|
104
105
|
// SDK default; [] = strict isolation (skills:[] + disallowedTools:['Skill']).
|
|
105
|
-
//
|
|
106
|
-
//
|
|
106
|
+
// Non-empty allowedSkills is rejected at this common planning boundary, including
|
|
107
|
+
// programmatic callers that bypass eval.yaml validation.
|
|
107
108
|
...(task.artifact.allowedSkills !== undefined && { allowedSkills: task.artifact.allowedSkills }),
|
|
108
109
|
// Sample.mocks 透传到 executor。executor(claude-sdk / claude-cli)
|
|
109
110
|
// 自决定怎么落地(in-process hook vs 临时 CLAUDE_CONFIG_DIR + on-disk hook)。
|
|
@@ -121,6 +122,7 @@ export function resolveExecutionStrategy(task, model, timeoutMs, verbose, effort
|
|
|
121
122
|
return {
|
|
122
123
|
strategy: resolveArtifactExecutionStrategy(task.artifact),
|
|
123
124
|
cacheSystem: '',
|
|
125
|
+
...(isStrictBaseline && !task.cwd && { isolatedCwd: true }),
|
|
124
126
|
input: {
|
|
125
127
|
...baseInput,
|
|
126
128
|
system: null,
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
* Currently supports file/directory path verification via fs.existsSync.
|
|
4
4
|
*/
|
|
5
5
|
import { existsSync } from 'node:fs';
|
|
6
|
-
import { resolve } from 'node:path';
|
|
6
|
+
import { isAbsolute, relative, resolve } from 'node:path';
|
|
7
7
|
// Patterns that look like file/directory paths in agent output
|
|
8
8
|
const PATH_PATTERNS = [
|
|
9
9
|
// Explicit code paths: repos/xxx, src/xxx, lib/xxx, packages/xxx
|
|
10
10
|
/(?:repos|src|lib|packages|dist|test|components)\/[a-zA-Z0-9_/.@-]+/g,
|
|
11
|
-
//
|
|
12
|
-
/\.claude\/[a-zA-Z0-9_/.@-]+/g,
|
|
11
|
+
// Agent configuration and skill paths across supported trace sources.
|
|
12
|
+
/\.(?:agents|claude|codex|gemini)\/[a-zA-Z0-9_/.@-]+/g,
|
|
13
13
|
// Paths with file extensions mentioned in text
|
|
14
|
-
/[a-zA-Z0-9_/-]+\.(?:ts|js|tsx|jsx|md|json|yaml|yml|sh)\b(?!\s*\()/g,
|
|
14
|
+
/(?<![a-zA-Z0-9_./-])[a-zA-Z0-9_/-]+\.(?:ts|js|tsx|jsx|md|json|yaml|yml|sh)\b(?!\s*\()/g,
|
|
15
15
|
];
|
|
16
16
|
// Paths to ignore (too generic or always present)
|
|
17
17
|
const IGNORE_PATTERNS = [
|
|
@@ -48,14 +48,22 @@ export function extractPathClaims(output) {
|
|
|
48
48
|
*/
|
|
49
49
|
export function checkFacts(output, cwd) {
|
|
50
50
|
const pathClaims = extractPathClaims(output);
|
|
51
|
+
const root = resolve(cwd);
|
|
51
52
|
const claims = pathClaims.map((path) => {
|
|
52
|
-
const fullPath = resolve(
|
|
53
|
-
const
|
|
53
|
+
const fullPath = resolve(root, path);
|
|
54
|
+
const relativePath = relative(root, fullPath);
|
|
55
|
+
const insideCwd = relativePath === ''
|
|
56
|
+
|| (!relativePath.startsWith('..') && !isAbsolute(relativePath));
|
|
57
|
+
const exists = insideCwd && existsSync(fullPath);
|
|
54
58
|
return {
|
|
55
59
|
type: 'file-path',
|
|
56
60
|
value: path,
|
|
57
61
|
verified: exists,
|
|
58
|
-
...(!exists && {
|
|
62
|
+
...(!exists && {
|
|
63
|
+
evidence: insideCwd
|
|
64
|
+
? `${fullPath} not found`
|
|
65
|
+
: `${path} is outside the evaluation cwd`,
|
|
66
|
+
}),
|
|
59
67
|
};
|
|
60
68
|
});
|
|
61
69
|
const verifiedCount = claims.filter((c) => c.verified).length;
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* signal the verdict's overfitting gate reads (`src/eval-core/verdict.ts`).
|
|
13
13
|
*/
|
|
14
14
|
import { buildVariantSummary } from './schema.js';
|
|
15
|
+
import { setOwnRecordValue } from '../shared/record-count.js';
|
|
15
16
|
/** Below this many samples on any side, a split is too small to be meaningful —
|
|
16
17
|
* callers fall back to full-set scoring and mark the breakdown `disabled`. */
|
|
17
18
|
export const MIN_HOLDOUT_SUBSET = 3;
|
|
@@ -105,14 +106,14 @@ export function computeHoldoutBreakdown(report, variantNames, ratio, sampleIdOrd
|
|
|
105
106
|
}
|
|
106
107
|
const perVariant = {};
|
|
107
108
|
for (const v of variantNames) {
|
|
108
|
-
perVariant
|
|
109
|
+
setOwnRecordValue(perVariant, v, {
|
|
109
110
|
trainScore: Number(subsetCompositeScore(report, v, split.trainIds).toFixed(4)),
|
|
110
111
|
holdoutScore: Number(subsetCompositeScore(report, v, split.holdoutIds).toFixed(4)),
|
|
111
112
|
trainCount: split.trainIds.size,
|
|
112
113
|
holdoutCount: split.holdoutIds.size,
|
|
113
114
|
trainScorable: subsetScorableCount(report, v, split.trainIds),
|
|
114
115
|
holdoutScorable: subsetScorableCount(report, v, split.holdoutIds),
|
|
115
|
-
};
|
|
116
|
+
});
|
|
116
117
|
}
|
|
117
118
|
return { ratio, perVariant };
|
|
118
119
|
}
|
|
@@ -3,8 +3,8 @@ import { type ExecutorVendor } from '../executors/shared.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* 评委独立性分析(单一来源,verdict caveat 与 analysis 诊断共用)。
|
|
5
5
|
*
|
|
6
|
-
* LLM 评委有自我偏好偏置:偏爱与自己同模型家族产出的输出。
|
|
7
|
-
*
|
|
6
|
+
* LLM 评委有自我偏好偏置:偏爱与自己同模型家族产出的输出。CLI 默认评委跟随所选 runtime
|
|
7
|
+
* (Claude 用 haiku,Codex 沿用被测模型),故敞口默认就开着。本 helper 只算客观事实(评委/输出各属哪家、有没有
|
|
8
8
|
* 跨厂商评委、是不是单厂商 ensemble、有没有挂 gold 校准),严重度与文案交给消费方(report-diagnostics
|
|
9
9
|
* / verdict)决定。
|
|
10
10
|
*
|
|
@@ -13,6 +13,22 @@ const fs = require('fs');
|
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const os = require('os');
|
|
15
15
|
|
|
16
|
+
function recordCount(record, key) {
|
|
17
|
+
const value = Object.prototype.hasOwnProperty.call(record, key) ? record[key] : undefined;
|
|
18
|
+
return typeof value === 'number' && Number.isInteger(value) && value >= 0 ? value : 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function incrementRecordCount(record, key, amount = 1) {
|
|
22
|
+
const next = recordCount(record, key) + amount;
|
|
23
|
+
Object.defineProperty(record, key, {
|
|
24
|
+
value: next,
|
|
25
|
+
enumerable: true,
|
|
26
|
+
configurable: true,
|
|
27
|
+
writable: true,
|
|
28
|
+
});
|
|
29
|
+
return next;
|
|
30
|
+
}
|
|
31
|
+
|
|
16
32
|
function expandHome(p) {
|
|
17
33
|
if (p.startsWith('~/')) return path.join(os.homedir(), p.slice(2));
|
|
18
34
|
if (p === '~') return os.homedir();
|
|
@@ -151,12 +167,13 @@ process.stdin.on('end', () => {
|
|
|
151
167
|
// 统计文件:perMock(每条 mock 的命中次数,用于状态机 + 报告)+ hits_total + misses_total
|
|
152
168
|
// 同一 spawn 内多次 hook 调用共享。
|
|
153
169
|
const statsFile = path.join(path.dirname(mocksFile), 'hits.json');
|
|
154
|
-
|
|
170
|
+
let stats = fs.existsSync(statsFile)
|
|
155
171
|
? JSON.parse(fs.readFileSync(statsFile, 'utf8'))
|
|
156
172
|
: { perMock: {}, hits_total: 0, misses_total: 0 };
|
|
157
|
-
if (!stats.
|
|
158
|
-
if (!stats.
|
|
159
|
-
|
|
173
|
+
if (!stats || typeof stats !== 'object' || Array.isArray(stats)) stats = {};
|
|
174
|
+
if (!stats.perMock || typeof stats.perMock !== 'object' || Array.isArray(stats.perMock)) stats.perMock = {};
|
|
175
|
+
stats.hits_total = recordCount(stats, 'hits_total');
|
|
176
|
+
stats.misses_total = recordCount(stats, 'misses_total');
|
|
160
177
|
|
|
161
178
|
const writeStats = () => {
|
|
162
179
|
try { fs.writeFileSync(statsFile, JSON.stringify(stats)); } catch { /* best effort */ }
|
|
@@ -176,9 +193,9 @@ process.stdin.on('end', () => {
|
|
|
176
193
|
for (let i = 0; i < mocks.length; i++) {
|
|
177
194
|
if (isMockHit(mocks[i], toolName, toolInput)) {
|
|
178
195
|
const key = keyOfMock[i];
|
|
179
|
-
const c = stats.perMock
|
|
196
|
+
const c = recordCount(stats.perMock, key);
|
|
180
197
|
const result = resolveMockReturn(mocks[i], c, baseDir);
|
|
181
|
-
stats.perMock
|
|
198
|
+
incrementRecordCount(stats.perMock, key);
|
|
182
199
|
stats.hits_total += 1;
|
|
183
200
|
writeStats();
|
|
184
201
|
// 与 SDK 路径(mocks-runtime.ts)对齐:最小化前缀,避免拖慢多步 sample。
|
|
@@ -17,6 +17,7 @@ import { mkdtempSync, rmSync, writeFileSync, mkdirSync, readFileSync, existsSync
|
|
|
17
17
|
import { homedir, tmpdir } from 'node:os';
|
|
18
18
|
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
19
19
|
import { fileURLToPath } from 'node:url';
|
|
20
|
+
import { incrementRecordCount, setOwnRecordValue } from '../shared/record-count.js';
|
|
20
21
|
// ─── Match logic ────────────────────────────────────────────────────────────
|
|
21
22
|
function expandHome(p) {
|
|
22
23
|
if (p.startsWith('~/'))
|
|
@@ -209,7 +210,7 @@ export function buildSdkHookCallback(mocks, baseDir, strict = false) {
|
|
|
209
210
|
hitCounters.set(i, c + 1);
|
|
210
211
|
stats.hits++;
|
|
211
212
|
const key = keyOfMock[i];
|
|
212
|
-
stats.perMock
|
|
213
|
+
incrementRecordCount(stats.perMock, key);
|
|
213
214
|
// 关键 UX:LLM 看到 permissionDecision='deny' 容易误判"被拒绝/失败"。
|
|
214
215
|
// 给 reason 加一行最小前缀,告诉它把内容当成真实成功输出。措辞越短越好 ——
|
|
215
216
|
// 长措辞会显著拉慢多步 sample(每个工具调用都要读这段),实测 6 步流程从 60s 拖到 120s+。
|
|
@@ -289,11 +290,11 @@ export function materializeForCliConfigDir(mocks, baseDir, strict = false) {
|
|
|
289
290
|
writeFileSync(mcpServerScript, fakeMcpServerSource(), 'utf8');
|
|
290
291
|
const mcpServers = {};
|
|
291
292
|
for (const serverName of fakeMcpServers.keys()) {
|
|
292
|
-
mcpServers
|
|
293
|
+
setOwnRecordValue(mcpServers, serverName, {
|
|
293
294
|
command: 'node',
|
|
294
295
|
args: [mcpServerScript, serverName],
|
|
295
296
|
env: { OMK_MOCKS_FILE: mocksFile },
|
|
296
|
-
};
|
|
297
|
+
});
|
|
297
298
|
}
|
|
298
299
|
writeFileSync(mcpConfigFile, JSON.stringify({ mcpServers }, null, 2));
|
|
299
300
|
}
|
|
@@ -359,6 +360,20 @@ const mocksFile = process.env.OMK_MOCKS_FILE;
|
|
|
359
360
|
const rl = readline.createInterface({ input: process.stdin });
|
|
360
361
|
|
|
361
362
|
function send(obj) { process.stdout.write(JSON.stringify(obj) + '\\n'); }
|
|
363
|
+
function recordCount(record, key) {
|
|
364
|
+
const value = Object.prototype.hasOwnProperty.call(record, key) ? record[key] : undefined;
|
|
365
|
+
return typeof value === 'number' && Number.isInteger(value) && value >= 0 ? value : 0;
|
|
366
|
+
}
|
|
367
|
+
function incrementRecordCount(record, key, amount = 1) {
|
|
368
|
+
const next = recordCount(record, key) + amount;
|
|
369
|
+
Object.defineProperty(record, key, {
|
|
370
|
+
value: next,
|
|
371
|
+
enumerable: true,
|
|
372
|
+
configurable: true,
|
|
373
|
+
writable: true,
|
|
374
|
+
});
|
|
375
|
+
return next;
|
|
376
|
+
}
|
|
362
377
|
function globMatch(pattern, value) {
|
|
363
378
|
const escaped = pattern.replace(/[.+?^\${}()|[\\]\\\\]/g, '\\\\$&');
|
|
364
379
|
return new RegExp('^' + escaped.replace(/\\*/g, '.*') + '$', 's').test(value);
|
|
@@ -445,7 +460,12 @@ function schemaForTool(name, mocks) {
|
|
|
445
460
|
const input = m.match && m.match.input;
|
|
446
461
|
if (typeof input !== 'object' || input === null || Array.isArray(input)) continue;
|
|
447
462
|
for (const k of Object.keys(input)) {
|
|
448
|
-
properties
|
|
463
|
+
Object.defineProperty(properties, k, {
|
|
464
|
+
value: inferJsonSchema(input[k]),
|
|
465
|
+
enumerable: true,
|
|
466
|
+
configurable: true,
|
|
467
|
+
writable: true,
|
|
468
|
+
});
|
|
449
469
|
if (!required.includes(k)) required.push(k);
|
|
450
470
|
}
|
|
451
471
|
}
|
|
@@ -476,9 +496,10 @@ function recordHit(mockKey) {
|
|
|
476
496
|
const statsFile = path.join(path.dirname(mocksFile), 'hits.json');
|
|
477
497
|
let stats = { perMock: {}, hits_total: 0, misses_total: 0 };
|
|
478
498
|
try { if (fs.existsSync(statsFile)) stats = JSON.parse(fs.readFileSync(statsFile, 'utf8')); } catch {}
|
|
479
|
-
if (!stats.
|
|
480
|
-
stats.perMock
|
|
481
|
-
|
|
499
|
+
if (!stats || typeof stats !== 'object' || Array.isArray(stats)) stats = {};
|
|
500
|
+
if (!stats.perMock || typeof stats.perMock !== 'object' || Array.isArray(stats.perMock)) stats.perMock = {};
|
|
501
|
+
incrementRecordCount(stats.perMock, mockKey);
|
|
502
|
+
stats.hits_total = recordCount(stats, 'hits_total') + 1;
|
|
482
503
|
fs.writeFileSync(statsFile, JSON.stringify(stats));
|
|
483
504
|
}
|
|
484
505
|
function recordMiss() {
|
|
@@ -486,7 +507,8 @@ function recordMiss() {
|
|
|
486
507
|
const statsFile = path.join(path.dirname(mocksFile), 'hits.json');
|
|
487
508
|
let stats = { perMock: {}, hits_total: 0, misses_total: 0 };
|
|
488
509
|
try { if (fs.existsSync(statsFile)) stats = JSON.parse(fs.readFileSync(statsFile, 'utf8')); } catch {}
|
|
489
|
-
stats
|
|
510
|
+
if (!stats || typeof stats !== 'object' || Array.isArray(stats)) stats = {};
|
|
511
|
+
stats.misses_total = recordCount(stats, 'misses_total') + 1;
|
|
490
512
|
fs.writeFileSync(statsFile, JSON.stringify(stats));
|
|
491
513
|
}
|
|
492
514
|
const hitCounters = new Map();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReportDocument, ReportIndexCard } from '../types/index.js';
|
|
2
|
+
export declare function isCanonicalReportId(value: unknown): value is string;
|
|
3
|
+
/**
|
|
4
|
+
* Parse a persisted report at every storage boundary. Canonical report files
|
|
5
|
+
* are the source of truth; index cards must never relax this contract.
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseReportDocument(value: unknown, fallbackId: string, expectedId?: string): ReportDocument | null;
|
|
8
|
+
/**
|
|
9
|
+
* Validate a lightweight report discovery card. The card is still only a
|
|
10
|
+
* pointer: consumers must parse `path` through `parseReportDocument` before use.
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseReportIndexCard(value: unknown): ReportIndexCard | null;
|