@dailephd/my-dev-kit-lab 0.6.2 → 0.7.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/CHANGELOG.md +26 -0
- package/README.md +11 -8
- package/benchmarks/contracts/context-window-scaling-cases.json +220 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/README.md +14 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/carrier-depot-catalog-01.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/course-module-catalog-06.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/library-shelf-catalog-07.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/sensor-station-catalog-05.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/staff-rota-catalog-03.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/supplier-contract-catalog-02.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/vehicle-route-catalog-04.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/archive-box-catalog-12.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/clinic-ward-catalog-08.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/greenhouse-bay-catalog-13.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/harbor-berth-catalog-10.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/kitchen-section-catalog-15.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/market-stall-catalog-09.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/station-platform-catalog-14.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/workshop-bench-catalog-11.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/archive-box-catalog-28.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/carrier-depot-catalog-17.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/clinic-ward-catalog-24.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/course-module-catalog-22.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/greenhouse-bay-catalog-29.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/harbor-berth-catalog-26.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/kitchen-section-catalog-31.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/library-shelf-catalog-23.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/market-stall-catalog-25.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/sensor-station-catalog-21.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/staff-rota-catalog-19.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/station-platform-catalog-30.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/supplier-contract-catalog-18.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/vehicle-route-catalog-20.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/warehouse-zone-catalog-16.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/workshop-bench-catalog-27.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/archive-box-catalog-44.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/carrier-depot-catalog-33.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/carrier-depot-catalog-49.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/clinic-ward-catalog-40.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/clinic-ward-catalog-56.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/course-module-catalog-38.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/course-module-catalog-54.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/greenhouse-bay-catalog-45.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/harbor-berth-catalog-42.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/harbor-berth-catalog-58.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/kitchen-section-catalog-47.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/library-shelf-catalog-39.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/library-shelf-catalog-55.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/market-stall-catalog-41.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/market-stall-catalog-57.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/sensor-station-catalog-37.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/sensor-station-catalog-53.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/staff-rota-catalog-35.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/staff-rota-catalog-51.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/station-platform-catalog-46.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/supplier-contract-catalog-34.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/supplier-contract-catalog-50.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/vehicle-route-catalog-36.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/vehicle-route-catalog-52.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/warehouse-zone-catalog-32.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/warehouse-zone-catalog-48.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/workshop-bench-catalog-43.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/auditRedaction.ts +25 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/inventoryReservation.ts +26 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/invoiceTotals.ts +25 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/shippingQuote.ts +32 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/auditRedaction.test.ts +17 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/inventoryReservation.test.ts +19 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/invoiceTotals.test.ts +14 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/shippingQuote.test.ts +19 -0
- package/dist/src/cli/help.js +27 -10
- package/dist/src/commands/runExperimentDescribeCommand.js +5 -2
- package/dist/src/commands/runExperimentRunCommand.js +64 -8
- package/dist/src/evaluation/benchmarkMetadata.js +5 -1
- package/dist/src/evaluation/parseAgentAnswer.js +172 -24
- package/dist/src/evaluation/runMyDevKitRetrieval.js +120 -7
- package/dist/src/experiments/defaultRegistry.js +2 -0
- package/dist/src/experiments/plugins/contextWindowScaling/cliBudgets.js +31 -0
- package/dist/src/experiments/plugins/contextWindowScaling/config.js +84 -0
- package/dist/src/experiments/plugins/contextWindowScaling/contextBudget.js +43 -0
- package/dist/src/experiments/plugins/contextWindowScaling/evaluation.js +36 -0
- package/dist/src/experiments/plugins/contextWindowScaling/execution.js +187 -0
- package/dist/src/experiments/plugins/contextWindowScaling/executionArtifact.js +15 -0
- package/dist/src/experiments/plugins/contextWindowScaling/executionArtifactReader.js +186 -0
- package/dist/src/experiments/plugins/contextWindowScaling/index.js +14 -0
- package/dist/src/experiments/plugins/contextWindowScaling/metadata.js +12 -0
- package/dist/src/experiments/plugins/contextWindowScaling/metrics.js +149 -0
- package/dist/src/experiments/plugins/contextWindowScaling/plugin.js +185 -0
- package/dist/src/experiments/plugins/contextWindowScaling/projectProfile.js +51 -0
- package/dist/src/experiments/plugins/contextWindowScaling/relevantFiles.js +76 -0
- package/dist/src/experiments/plugins/contextWindowScaling/successEvidence.js +60 -0
- package/dist/src/experiments/plugins/contextWindowScaling/types.js +1 -0
- package/dist/src/experiments/plugins/incrementalChangeStaleness/comparisonV2.js +49 -0
- package/dist/src/experiments/plugins/incrementalChangeStaleness/config.js +5 -4
- package/dist/src/experiments/plugins/incrementalChangeStaleness/disposableTarget.js +20 -2
- package/dist/src/experiments/plugins/incrementalChangeStaleness/execution.js +42 -16
- package/dist/src/experiments/plugins/incrementalChangeStaleness/executionArtifact.js +4 -4
- package/dist/src/experiments/plugins/incrementalChangeStaleness/executionArtifactV2.js +289 -0
- package/dist/src/experiments/plugins/incrementalChangeStaleness/executionV2.js +195 -0
- package/dist/src/experiments/plugins/incrementalChangeStaleness/indexClone.js +76 -0
- package/dist/src/experiments/plugins/incrementalChangeStaleness/lifecycle.js +64 -32
- package/dist/src/experiments/plugins/incrementalChangeStaleness/lifecyclePolicy.js +6 -4
- package/dist/src/experiments/plugins/incrementalChangeStaleness/lifecyclePolicyV2.js +78 -0
- package/dist/src/experiments/plugins/incrementalChangeStaleness/lifecycleV2.js +298 -0
- package/dist/src/experiments/plugins/incrementalChangeStaleness/plugin.js +213 -12
- package/dist/src/experiments/plugins/incrementalChangeStaleness/treatmentSessionV2.js +5 -0
- package/dist/src/experiments/plugins/index.js +1 -0
- package/dist/src/experiments/plugins/warmIndexReuse/agentEvaluation.js +1 -1
- package/dist/src/experiments/plugins/warmIndexReuse/warmIndexSession.js +3 -1
- package/dist/src/mobile/android/advancedSecurity/candidateEvidence.js +9 -2
- package/dist/src/mobile/android/advancedSecurity/redaction.js +19 -10
- package/dist/src/mobile/android/advancedSecurity/secretCandidates/analyzeSecretCandidates.js +12 -2
- package/dist/src/mobile/android/advancedSecurity/signingConfiguration/analyzeSigningConfiguration.js +1 -1
- package/dist/src/mobile/android/advancedSecurity/signingConfiguration/extractSigningConfigurations.js +7 -7
- package/dist/src/plots/buildContextWindowScalingPlotData.js +96 -0
- package/dist/src/plots/index.js +1 -0
- package/dist/src/plots/writePlotArtifacts.js +12 -3
- package/dist/src/report/experiments/buildContextWindowScalingReport.js +84 -0
- package/dist/src/report/experiments/buildIncrementalChangeStalenessPluginReport.js +33 -0
- package/dist/src/report/experiments/buildIncrementalChangeStalenessReport.js +1 -1
- package/dist/src/report/experiments/buildIncrementalChangeStalenessReportV2.js +80 -0
- package/dist/src/report/experiments/buildPluginExperimentReport.js +24 -4
- package/dist/src/report/experiments/contextWindowScalingReportModel.js +3 -0
- package/dist/src/report/experiments/incrementalChangeStalenessReportModelV2.js +3 -0
- package/dist/src/report/experiments/incrementalChangeStalenessReportRowsV2.js +146 -0
- package/dist/src/report/experiments/index.js +7 -0
- package/dist/src/report/experiments/renderContextWindowScalingHtml.js +99 -0
- package/dist/src/report/experiments/renderContextWindowScalingText.js +108 -0
- package/dist/src/report/experiments/renderIncrementalChangeStalenessHtml.js +4 -0
- package/dist/src/report/experiments/renderIncrementalChangeStalenessHtmlV2.js +111 -0
- package/dist/src/report/experiments/renderIncrementalChangeStalenessTextV2.js +96 -0
- package/dist/src/report/experiments/renderPluginExperimentReportHtml.js +3 -0
- package/dist/src/report/experiments/renderPluginExperimentReportText.js +14 -0
- package/dist/src/securityValidation/staticScans/codeql.js +8 -8
- package/docs/METRICS.md +58 -0
- package/examples/tutorial-browser/prepare.mjs +13 -13
- package/examples/tutorial-browser/server.mjs +13 -13
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import { parseAgentCommandTemplate } from "../agents/index.js";
|
|
3
3
|
import { parseAgentId } from "../agents/agentRegistry.js";
|
|
4
4
|
import { readBenchmarkProjectProfiles, readEvaluationCases } from "../evaluation/index.js";
|
|
5
|
-
import { contextStrategyComparisonPlugin, createDefaultExperimentPluginRegistry, getWarmIndexCampaignPreset, incrementalChangeStalenessPlugin, parseWarmIndexCampaignPresetId, resolveExperimentTarget, runExperiment, warmIndexReusePlugin } from "../experiments/index.js";
|
|
5
|
+
import { contextStrategyComparisonPlugin, contextWindowScalingPlugin, createDefaultExperimentPluginRegistry, getWarmIndexCampaignPreset, incrementalChangeStalenessPlugin, parseContextBudgetsCliValue, parseWarmIndexCampaignPresetId, resolveExperimentTarget, runExperiment, warmIndexReusePlugin } from "../experiments/index.js";
|
|
6
6
|
import { buildDefaultExperimentOutputRoot } from "../experiments/outputPaths.js";
|
|
7
7
|
import { parsePromptComplexityLevel, parsePromptStrategy } from "../prompts/index.js";
|
|
8
8
|
import { writePluginExperimentReports } from "../report/index.js";
|
|
@@ -32,6 +32,11 @@ import { runWarmIndexCampaignPresentation } from "./runWarmIndexCampaignPresenta
|
|
|
32
32
|
// ---------------------------------------------------------------------------
|
|
33
33
|
const DEFAULT_CASES_RESOURCE = "examples/token-savings-cases.json";
|
|
34
34
|
const DEFAULT_PROJECT_PROFILES_RESOURCE = "benchmarks/contracts/benchmark-project-profiles.json";
|
|
35
|
+
// context-window-scaling owns one frozen bundled case catalog; its fixed project is referenced by the
|
|
36
|
+
// catalog's package-relative targetRoot, so both resolve from the package root, never the cwd.
|
|
37
|
+
const CONTEXT_WINDOW_SCALING_CASES_RESOURCE = "benchmarks/contracts/context-window-scaling-cases.json";
|
|
38
|
+
// Options the context-window-scaling plugin accepts; every other flag is rejected, not ignored.
|
|
39
|
+
const CONTEXT_WINDOW_SCALING_ALLOWED_FLAGS = ["--experiment", "--out", "--case", "--context-budgets", "--kit-command"];
|
|
35
40
|
export async function runExperimentRunCommandFromArgs(argv, options = {}) {
|
|
36
41
|
try {
|
|
37
42
|
const args = parseRunExperimentArgs(argv);
|
|
@@ -52,7 +57,7 @@ export async function runExperimentRunCommandFromArgs(argv, options = {}) {
|
|
|
52
57
|
registry,
|
|
53
58
|
targetPath: args.targetPath,
|
|
54
59
|
outputRoot,
|
|
55
|
-
config: args
|
|
60
|
+
config: pluginConfigFor(args),
|
|
56
61
|
inputs,
|
|
57
62
|
toolRoot,
|
|
58
63
|
runId
|
|
@@ -76,7 +81,6 @@ export async function runExperimentRunCommandFromArgs(argv, options = {}) {
|
|
|
76
81
|
// Automatic presentation (report already produced above) applies only to warm-index-reuse
|
|
77
82
|
// campaign runs; legacy fake-agent warm-index runs and context-strategy-comparison stay
|
|
78
83
|
// report-only, unchanged.
|
|
79
|
-
let screenshotFailed = false;
|
|
80
84
|
if (args.experimentId === warmIndexReusePlugin.metadata.id && args.config.campaignPreset) {
|
|
81
85
|
const executionArtifactPath = readMetadataString(result.metadata?.executionArtifactPath);
|
|
82
86
|
const campaignAgentId = readMetadataString(result.metadata?.campaignAgentId);
|
|
@@ -106,7 +110,6 @@ export async function runExperimentRunCommandFromArgs(argv, options = {}) {
|
|
|
106
110
|
else {
|
|
107
111
|
outputLines.push("Screenshot: failed");
|
|
108
112
|
outputLines.push(presentation.screenshot.error ?? "Screenshot capture failed.");
|
|
109
|
-
screenshotFailed = true;
|
|
110
113
|
}
|
|
111
114
|
outputLines.push(`Gallery manifest: ${presentation.gallery.manifestPath}`);
|
|
112
115
|
outputLines.push(`Gallery index: ${presentation.gallery.indexPath}`);
|
|
@@ -114,8 +117,6 @@ export async function runExperimentRunCommandFromArgs(argv, options = {}) {
|
|
|
114
117
|
console.log(outputLines.join("\n"));
|
|
115
118
|
if (result.status === "failed")
|
|
116
119
|
return 1;
|
|
117
|
-
if (screenshotFailed)
|
|
118
|
-
return 1;
|
|
119
120
|
return 0;
|
|
120
121
|
}
|
|
121
122
|
catch (error) {
|
|
@@ -146,9 +147,13 @@ export function parseRunExperimentArgs(argv) {
|
|
|
146
147
|
let includeRealAgents;
|
|
147
148
|
let kitCommand;
|
|
148
149
|
let campaignPreset;
|
|
150
|
+
let contextBudgets;
|
|
151
|
+
const seenFlags = [];
|
|
149
152
|
const commandTemplates = {};
|
|
150
153
|
for (let index = 0; index < argv.length; index += 1) {
|
|
151
154
|
const arg = argv[index];
|
|
155
|
+
if (arg !== undefined && arg.startsWith("--"))
|
|
156
|
+
seenFlags.push(arg);
|
|
152
157
|
if (arg === "--experiment") {
|
|
153
158
|
experimentId = readRequiredValue(argv, ++index, "--experiment");
|
|
154
159
|
}
|
|
@@ -206,6 +211,9 @@ export function parseRunExperimentArgs(argv) {
|
|
|
206
211
|
else if (arg === "--kit-command") {
|
|
207
212
|
kitCommand = readRequiredValue(argv, ++index, "--kit-command");
|
|
208
213
|
}
|
|
214
|
+
else if (arg === "--context-budgets") {
|
|
215
|
+
contextBudgets = parseContextBudgetsCliValue(readRequiredValue(argv, ++index, "--context-budgets"));
|
|
216
|
+
}
|
|
209
217
|
else if (arg === "--campaign") {
|
|
210
218
|
campaignPreset = parseWarmIndexCampaignPresetId(readRequiredValue(argv, ++index, "--campaign"));
|
|
211
219
|
}
|
|
@@ -220,7 +228,23 @@ export function parseRunExperimentArgs(argv) {
|
|
|
220
228
|
if (!experimentId) {
|
|
221
229
|
throw new Error("Usage: --experiment <id> [--target <path>] [--out <directory>]");
|
|
222
230
|
}
|
|
223
|
-
const KIT_COMMAND_PLUGIN_IDS = [
|
|
231
|
+
const KIT_COMMAND_PLUGIN_IDS = [
|
|
232
|
+
warmIndexReusePlugin.metadata.id,
|
|
233
|
+
incrementalChangeStalenessPlugin.metadata.id,
|
|
234
|
+
contextWindowScalingPlugin.metadata.id
|
|
235
|
+
];
|
|
236
|
+
if (contextBudgets !== undefined && experimentId !== contextWindowScalingPlugin.metadata.id) {
|
|
237
|
+
throw new Error(`--context-budgets is only supported for --experiment ${contextWindowScalingPlugin.metadata.id}.`);
|
|
238
|
+
}
|
|
239
|
+
if (experimentId === contextWindowScalingPlugin.metadata.id) {
|
|
240
|
+
const unsupported = [...new Set(seenFlags.filter((flag) => !CONTEXT_WINDOW_SCALING_ALLOWED_FLAGS.includes(flag)))];
|
|
241
|
+
if (unsupported.length > 0) {
|
|
242
|
+
throw new Error(`${unsupported.join(", ")} ${unsupported.length === 1 ? "is" : "are"} not supported for --experiment ${experimentId}; supported options: ${CONTEXT_WINDOW_SCALING_ALLOWED_FLAGS.join(", ")}.`);
|
|
243
|
+
}
|
|
244
|
+
if (seenFlags.includes("--case") && caseIds.length === 0) {
|
|
245
|
+
throw new Error("--case must list at least one case id.");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
224
248
|
if (kitCommand !== undefined && !KIT_COMMAND_PLUGIN_IDS.includes(experimentId)) {
|
|
225
249
|
throw new Error(`--kit-command is only supported for --experiment ${KIT_COMMAND_PLUGIN_IDS.join(" or ")}.`);
|
|
226
250
|
}
|
|
@@ -257,7 +281,8 @@ export function parseRunExperimentArgs(argv) {
|
|
|
257
281
|
includeRealAgents,
|
|
258
282
|
commandTemplates: Object.keys(commandTemplates).length > 0 ? commandTemplates : undefined,
|
|
259
283
|
kitCommand,
|
|
260
|
-
campaignPreset
|
|
284
|
+
campaignPreset,
|
|
285
|
+
contextBudgets
|
|
261
286
|
})
|
|
262
287
|
};
|
|
263
288
|
}
|
|
@@ -301,8 +326,39 @@ async function loadPluginInputs(args, toolRoot, context) {
|
|
|
301
326
|
}
|
|
302
327
|
return loadCasesAndProjectProfiles(args, toolRoot, context);
|
|
303
328
|
}
|
|
329
|
+
if (args.experimentId === contextWindowScalingPlugin.metadata.id) {
|
|
330
|
+
return loadContextWindowScalingInputs(args, toolRoot, context);
|
|
331
|
+
}
|
|
304
332
|
return undefined;
|
|
305
333
|
}
|
|
334
|
+
// --case is a selection over the frozen bundled catalog (catalog order, not argument order);
|
|
335
|
+
// the rest of the CLI config is the plugin's own ContextWindowScalingConfig.
|
|
336
|
+
function pluginConfigFor(args) {
|
|
337
|
+
if (args.experimentId !== contextWindowScalingPlugin.metadata.id)
|
|
338
|
+
return args.config;
|
|
339
|
+
const { caseIds: _caseIds, ...config } = args.config;
|
|
340
|
+
return config;
|
|
341
|
+
}
|
|
342
|
+
async function loadContextWindowScalingInputs(args, toolRoot, context) {
|
|
343
|
+
const validation = contextWindowScalingPlugin.validateConfig(pluginConfigFor(args));
|
|
344
|
+
if (!validation.valid || !validation.config) {
|
|
345
|
+
throw new Error(`Invalid context window scaling config: ${validation.errors.join("; ")}`);
|
|
346
|
+
}
|
|
347
|
+
const catalog = await readEvaluationCases(resolvePackageResource(context, CONTEXT_WINDOW_SCALING_CASES_RESOURCE), toolRoot);
|
|
348
|
+
const requested = args.config.caseIds;
|
|
349
|
+
if (requested === undefined)
|
|
350
|
+
return { cases: catalog, env: process.env };
|
|
351
|
+
const duplicates = [...new Set(requested.filter((id, position) => requested.indexOf(id) !== position))];
|
|
352
|
+
if (duplicates.length > 0) {
|
|
353
|
+
throw new Error(`--case contains duplicate case id(s): ${duplicates.join(", ")}.`);
|
|
354
|
+
}
|
|
355
|
+
const known = new Set(catalog.map((evaluationCase) => evaluationCase.id));
|
|
356
|
+
const unknown = requested.filter((id) => !known.has(id));
|
|
357
|
+
if (unknown.length > 0) {
|
|
358
|
+
throw new Error(`--case contains unknown case id(s): ${unknown.join(", ")}. Expected one of ${catalog.map((evaluationCase) => evaluationCase.id).join(", ")}.`);
|
|
359
|
+
}
|
|
360
|
+
return { cases: catalog.filter((evaluationCase) => requested.includes(evaluationCase.id)), env: process.env };
|
|
361
|
+
}
|
|
306
362
|
// Shared by both registered plugins: explicit paths resolve against toolRoot, defaults come from
|
|
307
363
|
// bundled package resources so they do not depend on the invocation cwd.
|
|
308
364
|
async function loadCasesAndProjectProfiles(args, toolRoot, context) {
|
|
@@ -280,7 +280,11 @@ function validateWarmIndexSourceRoots(sourceRoots, profile, label) {
|
|
|
280
280
|
return errors;
|
|
281
281
|
}
|
|
282
282
|
function normalizeRelativeRoot(value) {
|
|
283
|
-
|
|
283
|
+
const normalized = path.posix.normalize(value.replaceAll("\\", "/"));
|
|
284
|
+
let end = normalized.length;
|
|
285
|
+
while (end > 0 && normalized[end - 1] === "/")
|
|
286
|
+
end -= 1;
|
|
287
|
+
return normalized.slice(0, end);
|
|
284
288
|
}
|
|
285
289
|
function sameOrderedValues(left, right) {
|
|
286
290
|
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
@@ -77,11 +77,24 @@ function collectJsonCandidates(text) {
|
|
|
77
77
|
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
78
78
|
candidates.push(trimmed);
|
|
79
79
|
}
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
let cursor = 0;
|
|
81
|
+
while (cursor < text.length) {
|
|
82
|
+
const opening = text.indexOf("```", cursor);
|
|
83
|
+
if (opening < 0)
|
|
84
|
+
break;
|
|
85
|
+
let bodyStart = opening + 3;
|
|
86
|
+
if (text.slice(bodyStart, bodyStart + 4).toLowerCase() === "json")
|
|
87
|
+
bodyStart += 4;
|
|
88
|
+
while (bodyStart < text.length && isWhitespace(text[bodyStart]))
|
|
89
|
+
bodyStart += 1;
|
|
90
|
+
const closing = text.indexOf("```", bodyStart);
|
|
91
|
+
if (closing < 0)
|
|
92
|
+
break;
|
|
93
|
+
const body = text.slice(bodyStart, closing).trim();
|
|
82
94
|
if (body?.startsWith("{")) {
|
|
83
95
|
candidates.push(body);
|
|
84
96
|
}
|
|
97
|
+
cursor = closing + 3;
|
|
85
98
|
}
|
|
86
99
|
return candidates;
|
|
87
100
|
}
|
|
@@ -89,39 +102,103 @@ function collectFieldValues(text) {
|
|
|
89
102
|
const fields = new Map();
|
|
90
103
|
let currentKey;
|
|
91
104
|
for (const line of text.split(/\r?\n/)) {
|
|
92
|
-
const
|
|
93
|
-
if (
|
|
94
|
-
currentKey = normalizeKey(
|
|
105
|
+
const field = parseStructuredFieldLine(line);
|
|
106
|
+
if (field) {
|
|
107
|
+
currentKey = normalizeKey(field.label);
|
|
95
108
|
const current = fields.get(currentKey) ?? [];
|
|
96
|
-
current.push(stripMarkupOnlyValue(
|
|
109
|
+
current.push(stripMarkupOnlyValue(field.value));
|
|
97
110
|
fields.set(currentKey, current);
|
|
98
111
|
continue;
|
|
99
112
|
}
|
|
100
|
-
if (currentKey
|
|
101
|
-
|
|
113
|
+
if (currentKey) {
|
|
114
|
+
const continuation = parseFieldContinuation(line);
|
|
115
|
+
if (continuation !== undefined)
|
|
116
|
+
fields.get(currentKey)?.push(continuation);
|
|
102
117
|
}
|
|
103
118
|
}
|
|
104
119
|
return fields;
|
|
105
120
|
}
|
|
121
|
+
function isWhitespace(character) {
|
|
122
|
+
return character.trim().length === 0;
|
|
123
|
+
}
|
|
124
|
+
function parseStructuredFieldLine(line) {
|
|
125
|
+
let start = 0;
|
|
126
|
+
while (start < line.length && isWhitespace(line[start]))
|
|
127
|
+
start += 1;
|
|
128
|
+
if (line[start] === "-" || line[start] === "*") {
|
|
129
|
+
start += 1;
|
|
130
|
+
while (start < line.length && isWhitespace(line[start]))
|
|
131
|
+
start += 1;
|
|
132
|
+
}
|
|
133
|
+
let leadingMarkup = 0;
|
|
134
|
+
while (start < line.length && leadingMarkup < 2 && "*_`".includes(line[start])) {
|
|
135
|
+
start += 1;
|
|
136
|
+
leadingMarkup += 1;
|
|
137
|
+
}
|
|
138
|
+
const colon = line.indexOf(":", start);
|
|
139
|
+
if (colon < 0)
|
|
140
|
+
return undefined;
|
|
141
|
+
let labelEnd = colon;
|
|
142
|
+
let trailingMarkup = 0;
|
|
143
|
+
while (labelEnd > start && trailingMarkup < 2 && "*_`".includes(line[labelEnd - 1])) {
|
|
144
|
+
labelEnd -= 1;
|
|
145
|
+
trailingMarkup += 1;
|
|
146
|
+
}
|
|
147
|
+
const label = line.slice(start, labelEnd);
|
|
148
|
+
if (label.length < 2 || label.length > 41 || !isAsciiLetter(label[0]))
|
|
149
|
+
return undefined;
|
|
150
|
+
for (let index = 1; index < label.length; index += 1) {
|
|
151
|
+
const character = label[index];
|
|
152
|
+
if (!isAsciiLetter(character) && !(character >= "0" && character <= "9") && character !== " " && character !== "_" && character !== "-")
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
let valueStart = colon + 1;
|
|
156
|
+
while (valueStart < line.length && isWhitespace(line[valueStart]))
|
|
157
|
+
valueStart += 1;
|
|
158
|
+
return { label, value: line.slice(valueStart) };
|
|
159
|
+
}
|
|
160
|
+
function isAsciiLetter(character) {
|
|
161
|
+
return (character >= "a" && character <= "z") || (character >= "A" && character <= "Z");
|
|
162
|
+
}
|
|
163
|
+
function parseFieldContinuation(line) {
|
|
164
|
+
let index = 0;
|
|
165
|
+
while (index < line.length && isWhitespace(line[index]))
|
|
166
|
+
index += 1;
|
|
167
|
+
const indented = index > 0;
|
|
168
|
+
if (index === line.length)
|
|
169
|
+
return undefined;
|
|
170
|
+
if (line[index] === "-" || line[index] === "*") {
|
|
171
|
+
index += 1;
|
|
172
|
+
const whitespaceStart = index;
|
|
173
|
+
while (index < line.length && isWhitespace(line[index]))
|
|
174
|
+
index += 1;
|
|
175
|
+
if ((!indented && index === whitespaceStart) || index === line.length)
|
|
176
|
+
return undefined;
|
|
177
|
+
return line.slice(index).trim();
|
|
178
|
+
}
|
|
179
|
+
if (!indented)
|
|
180
|
+
return undefined;
|
|
181
|
+
return line.slice(index).trim();
|
|
182
|
+
}
|
|
106
183
|
function parseMarkdownSection(text, headings) {
|
|
107
184
|
const lines = text.split(/\r?\n/);
|
|
108
185
|
const values = [];
|
|
109
186
|
let inSection = false;
|
|
110
187
|
for (const line of lines) {
|
|
111
|
-
const heading = line
|
|
112
|
-
if (heading) {
|
|
113
|
-
inSection = headings.some((candidate) => normalizeKey(candidate) === normalizeKey(heading
|
|
188
|
+
const heading = parseMarkdownHeading(line);
|
|
189
|
+
if (heading !== undefined) {
|
|
190
|
+
inSection = headings.some((candidate) => normalizeKey(candidate) === normalizeKey(heading));
|
|
114
191
|
continue;
|
|
115
192
|
}
|
|
116
193
|
if (!inSection) {
|
|
117
194
|
continue;
|
|
118
195
|
}
|
|
119
|
-
if (
|
|
196
|
+
if (isMarkdownHeading(line)) {
|
|
120
197
|
break;
|
|
121
198
|
}
|
|
122
|
-
const bullet = line
|
|
123
|
-
if (bullet) {
|
|
124
|
-
values.push(bullet
|
|
199
|
+
const bullet = parseMarkdownBullet(line);
|
|
200
|
+
if (bullet !== undefined) {
|
|
201
|
+
values.push(bullet);
|
|
125
202
|
}
|
|
126
203
|
else if (line.includes(",")) {
|
|
127
204
|
values.push(...splitListValues([line]));
|
|
@@ -129,6 +206,41 @@ function parseMarkdownSection(text, headings) {
|
|
|
129
206
|
}
|
|
130
207
|
return unique(values);
|
|
131
208
|
}
|
|
209
|
+
function parseMarkdownHeading(line) {
|
|
210
|
+
let index = 0;
|
|
211
|
+
while (index < line.length && isWhitespace(line[index]))
|
|
212
|
+
index += 1;
|
|
213
|
+
const hashStart = index;
|
|
214
|
+
while (index < line.length && line[index] === "#" && index - hashStart < 6)
|
|
215
|
+
index += 1;
|
|
216
|
+
if (index === hashStart || (index < line.length && line[index] === "#"))
|
|
217
|
+
return undefined;
|
|
218
|
+
const heading = line.slice(index).trim();
|
|
219
|
+
return heading.length > 0 ? heading : undefined;
|
|
220
|
+
}
|
|
221
|
+
function isMarkdownHeading(line) {
|
|
222
|
+
let index = 0;
|
|
223
|
+
while (index < line.length && isWhitespace(line[index]))
|
|
224
|
+
index += 1;
|
|
225
|
+
const start = index;
|
|
226
|
+
while (index < line.length && line[index] === "#" && index - start < 6)
|
|
227
|
+
index += 1;
|
|
228
|
+
return index > start && index < line.length && isWhitespace(line[index]);
|
|
229
|
+
}
|
|
230
|
+
function parseMarkdownBullet(line) {
|
|
231
|
+
let index = 0;
|
|
232
|
+
while (index < line.length && isWhitespace(line[index]))
|
|
233
|
+
index += 1;
|
|
234
|
+
if (line[index] !== "-" && line[index] !== "*")
|
|
235
|
+
return undefined;
|
|
236
|
+
index += 1;
|
|
237
|
+
if (index >= line.length || !isWhitespace(line[index]))
|
|
238
|
+
return undefined;
|
|
239
|
+
while (index < line.length && isWhitespace(line[index]))
|
|
240
|
+
index += 1;
|
|
241
|
+
const content = line.slice(index).trim();
|
|
242
|
+
return content.length > 0 ? content : undefined;
|
|
243
|
+
}
|
|
132
244
|
function enrichFacts(parsed, text, answerKey) {
|
|
133
245
|
parsed.expectedFactsFound = normalizeFactMatches(parsed.expectedFactsFound, text, answerKey);
|
|
134
246
|
if (parsed.answerText.length === 0) {
|
|
@@ -168,15 +280,51 @@ function splitListValues(values) {
|
|
|
168
280
|
.filter(Boolean));
|
|
169
281
|
}
|
|
170
282
|
function cleanListItem(value) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
.
|
|
178
|
-
|
|
179
|
-
|
|
283
|
+
let source = value;
|
|
284
|
+
let searchFrom = 0;
|
|
285
|
+
while (searchFrom < value.length) {
|
|
286
|
+
const open = value.indexOf("`", searchFrom);
|
|
287
|
+
if (open < 0)
|
|
288
|
+
break;
|
|
289
|
+
const close = value.indexOf("`", open + 1);
|
|
290
|
+
if (close < 0)
|
|
291
|
+
break;
|
|
292
|
+
if (close > open + 1) {
|
|
293
|
+
source = value.slice(open + 1, close);
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
searchFrom = close + 1;
|
|
297
|
+
}
|
|
298
|
+
let start = 0;
|
|
299
|
+
let end = source.length;
|
|
300
|
+
while (start < end && isWhitespace(source[start]))
|
|
301
|
+
start += 1;
|
|
302
|
+
while (end > start && isWhitespace(source[end - 1]))
|
|
303
|
+
end -= 1;
|
|
304
|
+
if (source[start] === "-" || source[start] === "*") {
|
|
305
|
+
start += 1;
|
|
306
|
+
while (start < end && isWhitespace(source[start]))
|
|
307
|
+
start += 1;
|
|
308
|
+
}
|
|
309
|
+
while (start < end && (source[start] === '"' || source[start] === "'" || source[start] === "`"))
|
|
310
|
+
start += 1;
|
|
311
|
+
while (end > start && (source[end - 1] === '"' || source[end - 1] === "'" || source[end - 1] === "`" || source[end - 1] === "."))
|
|
312
|
+
end -= 1;
|
|
313
|
+
let whitespaceStart = -1;
|
|
314
|
+
for (let index = start; index < end; index += 1) {
|
|
315
|
+
const character = source[index];
|
|
316
|
+
if (isWhitespace(character)) {
|
|
317
|
+
if (whitespaceStart < 0)
|
|
318
|
+
whitespaceStart = index;
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
if ((character === "-" || character === "–" || character === "—") && whitespaceStart >= start && index + 1 < end && isWhitespace(source[index + 1])) {
|
|
322
|
+
end = whitespaceStart;
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
whitespaceStart = -1;
|
|
326
|
+
}
|
|
327
|
+
return source.slice(start, end).trim();
|
|
180
328
|
}
|
|
181
329
|
function stripMarkupOnlyValue(value) {
|
|
182
330
|
return /^[*_`\s]+$/.test(value) ? "" : value;
|
|
@@ -55,13 +55,118 @@ function skippedRetrieval(caseId, warnings, commands, durationMs) {
|
|
|
55
55
|
durationMs
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
|
+
const APPLIED_SCOPES = ["none", "changed-files", "affected-neighborhood", "full"];
|
|
59
|
+
const SELECTION_STATUSES = ["not-needed", "applied", "fallback-full"];
|
|
60
|
+
const NEIGHBORHOOD_COUNT_KEYS = ["seedFileCount", "seedSymbolCount", "affectedNodeCount", "affectedEdgeCount"];
|
|
61
|
+
function isNonNegativeInteger(value) {
|
|
62
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Validates the per-invocation `incrementalRefresh` object from `my-dev-kit index --incremental --json`
|
|
66
|
+
* stdout against the scope Lab requested. Returns validated evidence or an explicit error; never coerces.
|
|
67
|
+
* The fallback reason is intentionally an open string: upstream reason codes may evolve additively.
|
|
68
|
+
*/
|
|
69
|
+
export function parseIncrementalRefreshEvidence(stdout, requestedScope) {
|
|
70
|
+
const payload = parseJsonIfPossible(stdout);
|
|
71
|
+
if (payload === undefined)
|
|
72
|
+
return { ok: false, error: "index stdout is not valid JSON" };
|
|
73
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
74
|
+
return { ok: false, error: "index JSON result is not an object" };
|
|
75
|
+
}
|
|
76
|
+
const raw = payload.incrementalRefresh;
|
|
77
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
78
|
+
return { ok: false, error: "index JSON result has no incrementalRefresh object" };
|
|
79
|
+
}
|
|
80
|
+
const r = raw;
|
|
81
|
+
if (r.requestedScope !== requestedScope) {
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
error: `incrementalRefresh.requestedScope ${JSON.stringify(r.requestedScope)} does not match requested scope ${requestedScope}`
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
if (!APPLIED_SCOPES.includes(r.appliedScope)) {
|
|
88
|
+
return { ok: false, error: `incrementalRefresh.appliedScope ${JSON.stringify(r.appliedScope)} is not a known value` };
|
|
89
|
+
}
|
|
90
|
+
if (!SELECTION_STATUSES.includes(r.selectionStatus)) {
|
|
91
|
+
return { ok: false, error: `incrementalRefresh.selectionStatus ${JSON.stringify(r.selectionStatus)} is not a known value` };
|
|
92
|
+
}
|
|
93
|
+
if (r.fallbackReason !== null && typeof r.fallbackReason !== "string") {
|
|
94
|
+
return { ok: false, error: "incrementalRefresh.fallbackReason must be a string or null" };
|
|
95
|
+
}
|
|
96
|
+
for (const key of NEIGHBORHOOD_COUNT_KEYS) {
|
|
97
|
+
if (r[key] !== null && !isNonNegativeInteger(r[key])) {
|
|
98
|
+
return { ok: false, error: `incrementalRefresh.${key} must be a non-negative integer or null` };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
for (const key of ["forcedNeighborReanalysisFileCount", "freshExtractionFileCount", "reusedFileCount"]) {
|
|
102
|
+
if (!isNonNegativeInteger(r[key])) {
|
|
103
|
+
return { ok: false, error: `incrementalRefresh.${key} must be a non-negative integer` };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (!Array.isArray(r.forcedNeighborSample) || r.forcedNeighborSample.some((item) => typeof item !== "string")) {
|
|
107
|
+
return { ok: false, error: "incrementalRefresh.forcedNeighborSample must be an array of strings" };
|
|
108
|
+
}
|
|
109
|
+
const appliedScope = r.appliedScope;
|
|
110
|
+
const selectionStatus = r.selectionStatus;
|
|
111
|
+
const fallbackReason = r.fallbackReason;
|
|
112
|
+
if (selectionStatus === "applied") {
|
|
113
|
+
if (appliedScope !== requestedScope) {
|
|
114
|
+
return { ok: false, error: "incrementalRefresh applied status requires appliedScope equal to requestedScope" };
|
|
115
|
+
}
|
|
116
|
+
if (fallbackReason !== null)
|
|
117
|
+
return { ok: false, error: "incrementalRefresh applied status requires a null fallbackReason" };
|
|
118
|
+
}
|
|
119
|
+
else if (selectionStatus === "fallback-full") {
|
|
120
|
+
if (appliedScope !== "full")
|
|
121
|
+
return { ok: false, error: "incrementalRefresh fallback-full status requires appliedScope full" };
|
|
122
|
+
if (fallbackReason === null || fallbackReason.length === 0) {
|
|
123
|
+
return { ok: false, error: "incrementalRefresh fallback-full status requires a nonempty fallbackReason" };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
if (appliedScope !== "none")
|
|
128
|
+
return { ok: false, error: "incrementalRefresh not-needed status requires appliedScope none" };
|
|
129
|
+
if (fallbackReason !== null)
|
|
130
|
+
return { ok: false, error: "incrementalRefresh not-needed status requires a null fallbackReason" };
|
|
131
|
+
}
|
|
132
|
+
if (requestedScope === "affected-neighborhood" && selectionStatus === "applied") {
|
|
133
|
+
for (const key of NEIGHBORHOOD_COUNT_KEYS) {
|
|
134
|
+
if (r[key] === null) {
|
|
135
|
+
return { ok: false, error: `incrementalRefresh.${key} must be numeric for an applied affected-neighborhood refresh` };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
ok: true,
|
|
141
|
+
evidence: {
|
|
142
|
+
requestedScope,
|
|
143
|
+
appliedScope,
|
|
144
|
+
selectionStatus,
|
|
145
|
+
fallbackReason,
|
|
146
|
+
seedFileCount: r.seedFileCount,
|
|
147
|
+
seedSymbolCount: r.seedSymbolCount,
|
|
148
|
+
affectedNodeCount: r.affectedNodeCount,
|
|
149
|
+
affectedEdgeCount: r.affectedEdgeCount,
|
|
150
|
+
forcedNeighborReanalysisFileCount: r.forcedNeighborReanalysisFileCount,
|
|
151
|
+
forcedNeighborSample: [...r.forcedNeighborSample],
|
|
152
|
+
freshExtractionFileCount: r.freshExtractionFileCount,
|
|
153
|
+
reusedFileCount: r.reusedFileCount
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
58
157
|
/**
|
|
59
158
|
* Runs exactly one my-dev-kit `index` command for the target and writes the index only to
|
|
60
159
|
* `indexDir`. Performs no search/lookup/slice/source work. With `requireKit` a failed index
|
|
61
160
|
* throws; otherwise the failure is returned as `ok: false` with a warning.
|
|
161
|
+
*
|
|
162
|
+
* `mode` defaults to a full index. An incremental mode adds `--incremental --refresh-scope <scope>`
|
|
163
|
+
* and requires valid per-invocation `incrementalRefresh` JSON evidence on stdout; a successful
|
|
164
|
+
* process without that evidence is not a usable incremental build. Upstream full-fallback and
|
|
165
|
+
* no-change outcomes are valid evidence and are returned as-is.
|
|
62
166
|
*/
|
|
63
167
|
export async function buildMyDevKitIndex(options) {
|
|
64
168
|
const warnings = [];
|
|
169
|
+
const mode = options.mode ?? { kind: "full" };
|
|
65
170
|
const command = await runMeasuredCommand({
|
|
66
171
|
commandId: "index",
|
|
67
172
|
commandString: options.kitCommand,
|
|
@@ -74,22 +179,30 @@ export async function buildMyDevKitIndex(options) {
|
|
|
74
179
|
...options.target.sourceRoots.flatMap((sourceRoot) => ["--src", sourceRoot]),
|
|
75
180
|
"--out",
|
|
76
181
|
options.indexDir,
|
|
182
|
+
...(mode.kind === "incremental" ? ["--incremental", "--refresh-scope", mode.refreshScope] : []),
|
|
77
183
|
"--json"
|
|
78
184
|
]
|
|
79
185
|
});
|
|
186
|
+
const result = { indexDir: options.indexDir, durationMs: command.durationMs, command, mode };
|
|
80
187
|
if (!command.ok) {
|
|
81
188
|
if (options.requireKit) {
|
|
82
189
|
throw new Error(command.error || `my-dev-kit index failed with exit code ${command.exitCode}`);
|
|
83
190
|
}
|
|
84
191
|
warnings.push("my-dev-kit index command was unavailable or failed.");
|
|
192
|
+
return { ...result, ok: false, warnings, incrementalRefresh: null };
|
|
85
193
|
}
|
|
86
|
-
|
|
87
|
-
ok:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
194
|
+
if (mode.kind === "full") {
|
|
195
|
+
return { ...result, ok: true, warnings, incrementalRefresh: null };
|
|
196
|
+
}
|
|
197
|
+
const parsed = parseIncrementalRefreshEvidence(command.stdout, mode.refreshScope);
|
|
198
|
+
if (!parsed.ok) {
|
|
199
|
+
const message = `my-dev-kit incremental index (${mode.refreshScope}) returned no valid incrementalRefresh evidence: ${parsed.error}`;
|
|
200
|
+
if (options.requireKit)
|
|
201
|
+
throw new Error(message);
|
|
202
|
+
warnings.push(message);
|
|
203
|
+
return { ...result, ok: false, warnings, incrementalRefresh: null };
|
|
204
|
+
}
|
|
205
|
+
return { ...result, ok: true, warnings, incrementalRefresh: parsed.evidence };
|
|
93
206
|
}
|
|
94
207
|
/**
|
|
95
208
|
* Runs `<kit-command> --version` once through the shared measured-command runner and returns
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ExperimentPluginRegistry } from "./registry.js";
|
|
2
2
|
import { contextStrategyComparisonPlugin } from "./plugins/contextStrategyComparison/index.js";
|
|
3
|
+
import { contextWindowScalingPlugin } from "./plugins/contextWindowScaling/index.js";
|
|
3
4
|
import { incrementalChangeStalenessPlugin } from "./plugins/incrementalChangeStaleness/index.js";
|
|
4
5
|
import { warmIndexReusePlugin } from "./plugins/warmIndexReuse/index.js";
|
|
5
6
|
export function createDefaultExperimentPluginRegistry() {
|
|
@@ -7,5 +8,6 @@ export function createDefaultExperimentPluginRegistry() {
|
|
|
7
8
|
registry.register(contextStrategyComparisonPlugin);
|
|
8
9
|
registry.register(warmIndexReusePlugin);
|
|
9
10
|
registry.register(incrementalChangeStalenessPlugin);
|
|
11
|
+
registry.register(contextWindowScalingPlugin);
|
|
10
12
|
return registry;
|
|
11
13
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { validateContextBudgets } from "./config.js";
|
|
2
|
+
import { CONTEXT_BUDGET_16K, CONTEXT_BUDGET_32K, CONTEXT_BUDGET_64K, CONTEXT_BUDGET_8K } from "./contextBudget.js";
|
|
3
|
+
/** Closed, lowercase CLI vocabulary. "8k" is 8192 (binary), never 8000. */
|
|
4
|
+
const SYMBOLIC_CONTEXT_BUDGETS = Object.freeze({
|
|
5
|
+
"8k": CONTEXT_BUDGET_8K,
|
|
6
|
+
"16k": CONTEXT_BUDGET_16K,
|
|
7
|
+
"32k": CONTEXT_BUDGET_32K,
|
|
8
|
+
"64k": CONTEXT_BUDGET_64K,
|
|
9
|
+
});
|
|
10
|
+
const CANONICAL_POSITIVE_INTEGER = /^[1-9][0-9]*$/;
|
|
11
|
+
/**
|
|
12
|
+
* Converts the comma-separated --context-budgets value to numbers (symbolic or canonical base-10
|
|
13
|
+
* integers only), then delegates all domain rules (positive safe integer, no duplicates, ascending
|
|
14
|
+
* order) to validateContextBudgets. Throws with the CLI flag name on any invalid input.
|
|
15
|
+
*/
|
|
16
|
+
export function parseContextBudgetsCliValue(value) {
|
|
17
|
+
const tokens = value.split(",").map((token) => token.trim());
|
|
18
|
+
const numbers = tokens.map((token) => {
|
|
19
|
+
const symbolic = Object.hasOwn(SYMBOLIC_CONTEXT_BUDGETS, token) ? SYMBOLIC_CONTEXT_BUDGETS[token] : undefined;
|
|
20
|
+
if (symbolic !== undefined)
|
|
21
|
+
return symbolic;
|
|
22
|
+
if (CANONICAL_POSITIVE_INTEGER.test(token))
|
|
23
|
+
return Number(token);
|
|
24
|
+
throw new Error(`--context-budgets value ${JSON.stringify(token.length > 20 ? `${token.slice(0, 20)}...` : token)} is invalid; use 8k, 16k, 32k, 64k, or a positive base-10 integer.`);
|
|
25
|
+
});
|
|
26
|
+
const validated = validateContextBudgets(numbers);
|
|
27
|
+
if (validated.errors.length > 0) {
|
|
28
|
+
throw new Error(`--context-budgets is invalid: ${validated.errors.join(" ")}`);
|
|
29
|
+
}
|
|
30
|
+
return validated.budgets;
|
|
31
|
+
}
|