nexgenk 1.3.0 → 1.5.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/dist/main.mjs +936 -387
- package/package.json +1 -1
package/dist/main.mjs
CHANGED
|
@@ -119809,10 +119809,10 @@ function globSegmentsMatchPrefix(globSegments, relSegments) {
|
|
|
119809
119809
|
}
|
|
119810
119810
|
function compileGrepPattern(req) {
|
|
119811
119811
|
const flags = req.case_sensitive ? "g" : "gi";
|
|
119812
|
-
const body = req.regex ? req.pattern : escapeRegExp$
|
|
119812
|
+
const body = req.regex ? req.pattern : escapeRegExp$3(req.pattern);
|
|
119813
119813
|
return new RegExp(body, flags);
|
|
119814
119814
|
}
|
|
119815
|
-
function escapeRegExp$
|
|
119815
|
+
function escapeRegExp$3(s) {
|
|
119816
119816
|
return s.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
119817
119817
|
}
|
|
119818
119818
|
function stripTrailingNewline(s) {
|
|
@@ -123382,8 +123382,8 @@ var init_env$1 = __esmMin((() => {
|
|
|
123382
123382
|
]);
|
|
123383
123383
|
}));
|
|
123384
123384
|
// ../../packages/agent-core-v2/src/workspace/workspaceTrust/trustEnv.ts
|
|
123385
|
-
function
|
|
123386
|
-
return parseBooleanEnv(getEnv(TRUST_WORKSPACE_ENV))
|
|
123385
|
+
function workspaceTrustOverride(getEnv) {
|
|
123386
|
+
return parseBooleanEnv(getEnv(TRUST_WORKSPACE_ENV));
|
|
123387
123387
|
}
|
|
123388
123388
|
var TRUST_WORKSPACE_ENV;
|
|
123389
123389
|
var init_trustEnv = __esmMin((() => {
|
|
@@ -123483,7 +123483,7 @@ var init_workspaceTrustStore = __esmMin((() => {
|
|
|
123483
123483
|
initialization;
|
|
123484
123484
|
initializationFailed = false;
|
|
123485
123485
|
root;
|
|
123486
|
-
|
|
123486
|
+
envOverride;
|
|
123487
123487
|
trusted = false;
|
|
123488
123488
|
mutationTail = Promise.resolve();
|
|
123489
123489
|
changeEmitter = this._register(new Emitter());
|
|
@@ -123493,7 +123493,7 @@ var init_workspaceTrustStore = __esmMin((() => {
|
|
|
123493
123493
|
this.docs = docs;
|
|
123494
123494
|
this.telemetry = telemetry;
|
|
123495
123495
|
this.root = root;
|
|
123496
|
-
this.
|
|
123496
|
+
this.envOverride = workspaceTrustOverride((name) => bootstrap.getEnv(name));
|
|
123497
123497
|
}
|
|
123498
123498
|
get ready() {
|
|
123499
123499
|
if (this.initialization !== void 0) return this.initialization;
|
|
@@ -123514,7 +123514,7 @@ var init_workspaceTrustStore = __esmMin((() => {
|
|
|
123514
123514
|
return this.trusted;
|
|
123515
123515
|
}
|
|
123516
123516
|
isTrusted() {
|
|
123517
|
-
return this.
|
|
123517
|
+
return this.trusted || (this.envOverride ?? true);
|
|
123518
123518
|
}
|
|
123519
123519
|
async get() {
|
|
123520
123520
|
await this.ready;
|
|
@@ -123627,7 +123627,7 @@ var init_workspaceTrustService = __esmMin((() => {
|
|
|
123627
123627
|
}
|
|
123628
123628
|
async initialize() {
|
|
123629
123629
|
await this.inner.ready;
|
|
123630
|
-
this.trusted = this.inner.
|
|
123630
|
+
this.trusted = this.inner.isTrusted();
|
|
123631
123631
|
}
|
|
123632
123632
|
};
|
|
123633
123633
|
WorkspaceTrustService = __decorate([
|
|
@@ -125726,7 +125726,7 @@ function expandSkillParameters(body, rawArgs, context) {
|
|
|
125726
125726
|
for (let index = 0; index < (context.argumentNames?.length ?? 0); index++) {
|
|
125727
125727
|
const name = context.argumentNames?.[index];
|
|
125728
125728
|
if (name === void 0) continue;
|
|
125729
|
-
const escaped = escapeRegExp$
|
|
125729
|
+
const escaped = escapeRegExp$2(name);
|
|
125730
125730
|
content = content.replaceAll(new RegExp(`\\$${escaped}(?![\\[\\w])`, "g"), escapeXmlTags(tokens[index] ?? ""));
|
|
125731
125731
|
}
|
|
125732
125732
|
content = content.replaceAll(/\$ARGUMENTS\[(\d+)\]/g, (_match, indexText) => {
|
|
@@ -125816,7 +125816,7 @@ function tokenizeArgs(raw) {
|
|
|
125816
125816
|
if (hasContent) out.push(current);
|
|
125817
125817
|
return out;
|
|
125818
125818
|
}
|
|
125819
|
-
function escapeRegExp$
|
|
125819
|
+
function escapeRegExp$2(value) {
|
|
125820
125820
|
return value.replaceAll(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
125821
125821
|
}
|
|
125822
125822
|
var LISTING_DESC_MAX, InMemorySkillCatalog, SOURCE_GROUPS, graphemeSegmenter$3;
|
|
@@ -219297,6 +219297,26 @@ var init_decide$1 = __esmMin((() => {
|
|
|
219297
219297
|
IWaveDecideTool = createDecorator("waveDecideTool");
|
|
219298
219298
|
}));
|
|
219299
219299
|
// ../../packages/agent-core-v2/src/features/wave/core/config.ts
|
|
219300
|
+
function seats(prefix, count) {
|
|
219301
|
+
return Array.from({ length: Math.max(0, count) }, (_, index) => `${prefix}${index + 1}`);
|
|
219302
|
+
}
|
|
219303
|
+
function waveRoundSeats(roles, round) {
|
|
219304
|
+
if (round === "propose") return seats("P", roles.proponents);
|
|
219305
|
+
if (round === "defend") return seats("D", roles.defenders);
|
|
219306
|
+
if (round === "attack") return seats("A", roles.adversaries);
|
|
219307
|
+
if (round === "judge") return seats("J", roles.judges);
|
|
219308
|
+
const refiners = seats("R", roles.refiners);
|
|
219309
|
+
return round === "refine" ? refiners.slice(0, 1) : refiners.slice(1);
|
|
219310
|
+
}
|
|
219311
|
+
function waveConfigState(config) {
|
|
219312
|
+
const state = config;
|
|
219313
|
+
return {
|
|
219314
|
+
...config,
|
|
219315
|
+
version: state.version ?? 1,
|
|
219316
|
+
wavesOpen: state.wavesOpen ?? [],
|
|
219317
|
+
raw: state.raw ?? {}
|
|
219318
|
+
};
|
|
219319
|
+
}
|
|
219300
219320
|
function record$2(value) {
|
|
219301
219321
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
219302
219322
|
}
|
|
@@ -219317,6 +219337,9 @@ function makeWaveConfig(raw, loadedFrom) {
|
|
|
219317
219337
|
const roles = record$2(base["roles"]);
|
|
219318
219338
|
const quorum = record$2(base["quorum"]);
|
|
219319
219339
|
return {
|
|
219340
|
+
version: num(base["version"], 1),
|
|
219341
|
+
wavesOpen: strArray$1(base["wavesOpen"], []),
|
|
219342
|
+
raw: base,
|
|
219320
219343
|
layout: {
|
|
219321
219344
|
waves: text(layout["waves"], DEFAULT_LAYOUT.waves),
|
|
219322
219345
|
backlog: text(layout["backlog"], DEFAULT_LAYOUT.backlog),
|
|
@@ -219378,8 +219401,24 @@ function containedPath(root, candidate) {
|
|
|
219378
219401
|
if (resolved !== resolvedRoot && !resolved.startsWith(`${resolvedRoot}${sep}`)) throw new Error(`ruta fuera del workspace: ${candidate}`);
|
|
219379
219402
|
return resolved;
|
|
219380
219403
|
}
|
|
219381
|
-
var DEFAULT_LAYOUT, DEFAULT_THRESHOLDS, DEFAULT_VOCABULARY, DEFAULT_ROLES, DEFAULT_QUORUM;
|
|
219404
|
+
var WAVE_ROUNDS, WAVE_ROUND_DIRS, DEFAULT_LAYOUT, DEFAULT_THRESHOLDS, DEFAULT_VOCABULARY, DEFAULT_ROLES, DEFAULT_QUORUM;
|
|
219382
219405
|
var init_config$6 = __esmMin((() => {
|
|
219406
|
+
WAVE_ROUNDS = [
|
|
219407
|
+
"propose",
|
|
219408
|
+
"defend",
|
|
219409
|
+
"attack",
|
|
219410
|
+
"judge",
|
|
219411
|
+
"refine",
|
|
219412
|
+
"audit"
|
|
219413
|
+
];
|
|
219414
|
+
WAVE_ROUND_DIRS = {
|
|
219415
|
+
propose: "01-proposals",
|
|
219416
|
+
defend: "02-defenses",
|
|
219417
|
+
attack: "03-attacks",
|
|
219418
|
+
judge: "04-verdicts",
|
|
219419
|
+
refine: "05-refined",
|
|
219420
|
+
audit: "05-refined"
|
|
219421
|
+
};
|
|
219383
219422
|
DEFAULT_LAYOUT = {
|
|
219384
219423
|
waves: "design/waves",
|
|
219385
219424
|
backlog: "backlog",
|
|
@@ -219559,23 +219598,16 @@ function evaluateQuorum(input) {
|
|
|
219559
219598
|
const winner = ranked[0];
|
|
219560
219599
|
const second = ranked[1];
|
|
219561
219600
|
if (winner === void 0) throw new Error("no hay propuestas que comparar");
|
|
219562
|
-
if (second === void 0) {
|
|
219563
|
-
|
|
219564
|
-
|
|
219565
|
-
|
|
219566
|
-
|
|
219567
|
-
|
|
219568
|
-
|
|
219569
|
-
|
|
219570
|
-
|
|
219571
|
-
|
|
219572
|
-
medians,
|
|
219573
|
-
medianMargin: 0,
|
|
219574
|
-
judgesHoldingMargin: perJudge.length,
|
|
219575
|
-
perJudge,
|
|
219576
|
-
reason: `solo hay una propuesta: ${winner}`
|
|
219577
|
-
};
|
|
219578
|
-
}
|
|
219601
|
+
if (second === void 0) return {
|
|
219602
|
+
verdict: "refine",
|
|
219603
|
+
winner,
|
|
219604
|
+
second: void 0,
|
|
219605
|
+
medians,
|
|
219606
|
+
medianMargin: 0,
|
|
219607
|
+
judgesHoldingMargin: 0,
|
|
219608
|
+
perJudge: [],
|
|
219609
|
+
reason: `sin comparacion no hay quorum: solo hay una propuesta (${winner})`
|
|
219610
|
+
};
|
|
219579
219611
|
const winnerMedian = medians[winner] ?? 0;
|
|
219580
219612
|
const secondMedian = medians[second] ?? 0;
|
|
219581
219613
|
const medianMargin = Number((winnerMedian - secondMedian).toFixed(6));
|
|
@@ -219645,6 +219677,7 @@ function runWaveDecideForRoot(input) {
|
|
|
219645
219677
|
isError: true
|
|
219646
219678
|
};
|
|
219647
219679
|
}
|
|
219680
|
+
const holding = result.perJudge.length === 0 ? "sin comparacion" : `${result.judgesHoldingMargin}/${result.perJudge.length}`;
|
|
219648
219681
|
const lines = [
|
|
219649
219682
|
`QUORUM — ${result.verdict}`,
|
|
219650
219683
|
"",
|
|
@@ -219652,8 +219685,9 @@ function runWaveDecideForRoot(input) {
|
|
|
219652
219685
|
"",
|
|
219653
219686
|
` ganador: ${result.winner ?? "(empate)"}`,
|
|
219654
219687
|
` margen: ${result.medianMargin} (minimo ${input.minPoints ?? config.quorum.minPoints})`,
|
|
219655
|
-
` jueces con margen: ${
|
|
219688
|
+
` jueces con margen: ${holding} (minimo ${input.minAxes ?? config.quorum.minAxes})`,
|
|
219656
219689
|
...result.perJudge.map((entry) => ` ${entry.judge}: ${entry.margin}${entry.holds ? " ok" : " NO"}`),
|
|
219690
|
+
...result.perJudge.filter((entry) => entry.margin < 0).map((entry) => ` disidencia: ${entry.judge} ${entry.margin}`),
|
|
219657
219691
|
"",
|
|
219658
219692
|
` motivo: ${result.reason}`
|
|
219659
219693
|
];
|
|
@@ -219671,7 +219705,7 @@ var init_decideRunner = __esmMin((() => {
|
|
|
219671
219705
|
// ../../packages/agent-core-v2/src/features/wave/tools/decide/decide.md?raw
|
|
219672
219706
|
var decide_default;
|
|
219673
219707
|
var init_decide = __esmMin((() => {
|
|
219674
|
-
decide_default = "Compute the wave quorum from the judges' totals and say what may happen next.\n\nPass one entry per judge with its totals per proposal (`{ judge: \"J1\", scores: { P1: 17, P2: 15, P3: 14 } }`). The tool takes the **median** per proposal
|
|
219708
|
+
decide_default = "Compute the wave quorum from the judges' totals and say what may happen next.\n\nPass one entry per judge with its totals per proposal (`{ judge: \"J1\", scores: { P1: 17, P2: 15, P3: 14 } }`). The tool takes the **median** per proposal and applies both conditions of `core/quorum.ts`: the winner's median must beat the second's by `minPoints` (**margen de medianas**), and at least `minAxes` judges must give the winner that margin or more over the second (**mayoría de jueces**). Thresholds default to `workflow.config.json`.\n\nAnswers `adopt`, `refine` (no quorum yet, compose R1 and audit with R2) or `deadlock` (two rounds without quorum: adopt R1 with written dissent). A tie in the median, or a single proposal with nothing to compare, never crowns a winner and never counts as quorum.\n";
|
|
219675
219709
|
}));
|
|
219676
219710
|
// ../../packages/agent-core-v2/src/features/wave/tools/decide/decideTool.ts
|
|
219677
219711
|
var WaveDecideTool;
|
|
@@ -219767,6 +219801,18 @@ function walk$1(fs, dir, accept, acc = []) {
|
|
|
219767
219801
|
}
|
|
219768
219802
|
var init_fsJson = __esmMin((() => {}));
|
|
219769
219803
|
// ../../packages/agent-core-v2/src/features/wave/tools/open/openRunner.ts
|
|
219804
|
+
function briefTemplate(root) {
|
|
219805
|
+
const fs = nodeWaveFs;
|
|
219806
|
+
const local = join(root, BRIEF_TEMPLATE$1);
|
|
219807
|
+
if (fs.exists(local)) return { file: local };
|
|
219808
|
+
if (fs.isDirectory(join(root, "workflow"))) return { missing: BRIEF_TEMPLATE$1 };
|
|
219809
|
+
return fs.exists(BUNDLED_BRIEF_TEMPLATE) ? { file: BUNDLED_BRIEF_TEMPLATE } : { missing: BRIEF_TEMPLATE$1 };
|
|
219810
|
+
}
|
|
219811
|
+
function nextEpic(backlogDir) {
|
|
219812
|
+
const numbers = asArray$2(asRecord$2(readJson$2(nodeWaveFs, join(backlogDir, "epics.json")) ?? {})["epics"]).map((epic) => /^E(\d{2,})$/.exec(String(asRecord$2(epic)["id"]))?.[1]).filter((value) => value !== void 0).map(Number);
|
|
219813
|
+
const next = numbers.length > 0 ? Math.max(...numbers) + 1 : 1;
|
|
219814
|
+
return `E${String(next).padStart(2, "0")}`;
|
|
219815
|
+
}
|
|
219770
219816
|
function slugify(name) {
|
|
219771
219817
|
return name.normalize("NFD").replaceAll(/[\u0300-\u036F]/g, "").toLowerCase().replaceAll(/[^a-z0-9-]+/g, "-").replaceAll(/^-+|-+$/g, "");
|
|
219772
219818
|
}
|
|
@@ -219780,15 +219826,29 @@ function runWaveOpenForRoot(input) {
|
|
|
219780
219826
|
};
|
|
219781
219827
|
const layout = asRecord$2(asRecord$2(rawConfig)["layout"]);
|
|
219782
219828
|
const wavesRel = typeof layout["waves"] === "string" ? layout["waves"] : "design/waves";
|
|
219829
|
+
const backlogRel = typeof layout["backlog"] === "string" ? layout["backlog"] : "backlog";
|
|
219830
|
+
const minimum = makeWaveConfig(rawConfig).thresholds.minBriefSections;
|
|
219783
219831
|
let wavesDir;
|
|
219832
|
+
let backlogDir;
|
|
219784
219833
|
try {
|
|
219785
219834
|
wavesDir = containedPath(input.root, wavesRel);
|
|
219835
|
+
backlogDir = containedPath(input.root, backlogRel);
|
|
219786
219836
|
} catch (error) {
|
|
219787
219837
|
return {
|
|
219788
219838
|
output: error instanceof Error ? error.message : String(error),
|
|
219789
219839
|
isError: true
|
|
219790
219840
|
};
|
|
219791
219841
|
}
|
|
219842
|
+
const template = briefTemplate(input.root);
|
|
219843
|
+
if (template.file === void 0) return {
|
|
219844
|
+
output: `falta ${template.missing ?? BRIEF_TEMPLATE$1}: no se genera un brief sin la plantilla unica`,
|
|
219845
|
+
isError: true
|
|
219846
|
+
};
|
|
219847
|
+
const source = fs.read(template.file);
|
|
219848
|
+
if (source === void 0) return {
|
|
219849
|
+
output: `no se pudo leer ${template.file}`,
|
|
219850
|
+
isError: true
|
|
219851
|
+
};
|
|
219792
219852
|
const existing = fs.list(wavesDir).filter((name) => fs.isDirectory(join(wavesDir, name))).map((name) => Number(/^W(\d+)/.exec(name)?.[1] ?? NaN)).filter((value) => !Number.isNaN(value));
|
|
219793
219853
|
const next = input.id ?? `W${existing.length > 0 ? Math.max(...existing) + 1 : 0}`;
|
|
219794
219854
|
if (!/^W\d{1,2}$/.test(next)) return {
|
|
@@ -219805,8 +219865,9 @@ function runWaveOpenForRoot(input) {
|
|
|
219805
219865
|
isError: true
|
|
219806
219866
|
};
|
|
219807
219867
|
const dir = join(wavesDir, `${next}-${slug}`);
|
|
219868
|
+
const brief = source.replaceAll("{{WAVE}}", next).replaceAll("{{NAME}}", slug).replaceAll("{{NEXT_EPIC}}", nextEpic(backlogDir));
|
|
219808
219869
|
for (const sub of SUBDIRS) fs.mkdir(join(dir, sub));
|
|
219809
|
-
fs.write(join(dir, "00-brief.md"),
|
|
219870
|
+
fs.write(join(dir, "00-brief.md"), brief);
|
|
219810
219871
|
const declared = asArray$2(asRecord$2(rawConfig)["waves"]).map(String);
|
|
219811
219872
|
if (!declared.includes(next)) writeJson(fs, configFile, {
|
|
219812
219873
|
...asRecord$2(rawConfig),
|
|
@@ -219814,11 +219875,11 @@ function runWaveOpenForRoot(input) {
|
|
|
219814
219875
|
});
|
|
219815
219876
|
return { output: [
|
|
219816
219877
|
`oleada creada: ${next}-${slug}`,
|
|
219817
|
-
` brief: ${wavesRel}/${next}-${slug}/00-brief.md (rellena las
|
|
219878
|
+
` brief: ${wavesRel}/${next}-${slug}/00-brief.md (rellena las ${minimum} secciones antes de lanzar asientos)`,
|
|
219818
219879
|
` config: ${next} declarada en workflow.config.json (el gate la exige desde ahora)`
|
|
219819
219880
|
].join("\n") };
|
|
219820
219881
|
}
|
|
219821
|
-
var SUBDIRS,
|
|
219882
|
+
var SUBDIRS, BRIEF_TEMPLATE$1, BUNDLED_BRIEF_TEMPLATE;
|
|
219822
219883
|
var init_openRunner = __esmMin((() => {
|
|
219823
219884
|
init_config$6();
|
|
219824
219885
|
init_fsJson();
|
|
@@ -219830,24 +219891,8 @@ var init_openRunner = __esmMin((() => {
|
|
|
219830
219891
|
"04-verdicts",
|
|
219831
219892
|
"05-refined"
|
|
219832
219893
|
];
|
|
219833
|
-
|
|
219834
|
-
|
|
219835
|
-
"",
|
|
219836
|
-
"## 1. Contexto vinculante",
|
|
219837
|
-
"",
|
|
219838
|
-
"## 2. Alcance",
|
|
219839
|
-
"",
|
|
219840
|
-
"## 3. Evidencia disponible",
|
|
219841
|
-
"",
|
|
219842
|
-
"## 4. Preguntas que esta oleada resuelve",
|
|
219843
|
-
"",
|
|
219844
|
-
"## 5. Formato de salida",
|
|
219845
|
-
"",
|
|
219846
|
-
"## 6. Reglas duras",
|
|
219847
|
-
"",
|
|
219848
|
-
"## 7. Rúbrica (0-5)",
|
|
219849
|
-
""
|
|
219850
|
-
].join("\n");
|
|
219894
|
+
BRIEF_TEMPLATE$1 = "workflow/templates/brief.md";
|
|
219895
|
+
BUNDLED_BRIEF_TEMPLATE = resolve(import.meta.dirname, "../../../../../../../workflow/templates/brief.md");
|
|
219851
219896
|
}));
|
|
219852
219897
|
// ../../packages/agent-core-v2/src/features/wave/tools/open/open.md?raw
|
|
219853
219898
|
var open_default;
|
|
@@ -219905,6 +219950,85 @@ var init_round$1 = __esmMin((() => {
|
|
|
219905
219950
|
}).strict();
|
|
219906
219951
|
IWaveRoundTool = createDecorator("waveRoundTool");
|
|
219907
219952
|
}));
|
|
219953
|
+
// ../../packages/agent-core-v2/src/features/wave/tools/submit/submitRunner.ts
|
|
219954
|
+
function seatTicketHash(ticket) {
|
|
219955
|
+
return createHash("sha256").update(ticket).digest("hex");
|
|
219956
|
+
}
|
|
219957
|
+
function findWaveDir(root, wavesRel, wave) {
|
|
219958
|
+
const fs = nodeWaveFs;
|
|
219959
|
+
const wavesDir = containedPath(root, wavesRel);
|
|
219960
|
+
const name = fs.list(wavesDir).filter((entry) => fs.isDirectory(join(wavesDir, entry))).find((entry) => entry === wave || entry.startsWith(`${wave}-`));
|
|
219961
|
+
return name === void 0 ? void 0 : join(wavesDir, name);
|
|
219962
|
+
}
|
|
219963
|
+
function runWaveSubmitForRoot(input) {
|
|
219964
|
+
const fs = nodeWaveFs;
|
|
219965
|
+
const rawConfig = readJson$2(fs, join(input.root, "workflow.config.json"));
|
|
219966
|
+
if (rawConfig === void 0) return {
|
|
219967
|
+
output: `no hay workflow.config.json en ${input.root}`,
|
|
219968
|
+
isError: true
|
|
219969
|
+
};
|
|
219970
|
+
const config = makeWaveConfig(rawConfig);
|
|
219971
|
+
const wavesRel = config.layout.waves;
|
|
219972
|
+
const seats = waveRoundSeats(config.roles, input.round);
|
|
219973
|
+
if (!seats.includes(input.role)) return {
|
|
219974
|
+
output: `seats.unknown_seat: el rol "${input.role}" no pertenece a la ronda ${input.round} (esperado ${seats.join(", ")})`,
|
|
219975
|
+
isError: true
|
|
219976
|
+
};
|
|
219977
|
+
let base;
|
|
219978
|
+
try {
|
|
219979
|
+
base = findWaveDir(input.root, wavesRel, input.wave);
|
|
219980
|
+
} catch (error) {
|
|
219981
|
+
return {
|
|
219982
|
+
output: error instanceof Error ? error.message : String(error),
|
|
219983
|
+
isError: true
|
|
219984
|
+
};
|
|
219985
|
+
}
|
|
219986
|
+
if (base === void 0) return {
|
|
219987
|
+
output: `no existe la oleada ${input.wave} en ${wavesRel}`,
|
|
219988
|
+
isError: true
|
|
219989
|
+
};
|
|
219990
|
+
const dirName = WAVE_ROUND_DIRS[input.round];
|
|
219991
|
+
const dir = join(base, dirName);
|
|
219992
|
+
if (!fs.isDirectory(dir)) return {
|
|
219993
|
+
output: `falta el directorio ${dirName} en la oleada ${input.wave}`,
|
|
219994
|
+
isError: true
|
|
219995
|
+
};
|
|
219996
|
+
const seatsDir = join(base, WAVE_SEATS_DIR);
|
|
219997
|
+
if (fs.isDirectory(seatsDir) && fs.list(seatsDir).length > 0) {
|
|
219998
|
+
const presented = (input.ticket ?? "").trim();
|
|
219999
|
+
if (presented === "") return {
|
|
220000
|
+
output: `seats.foreign_replace: el asiento ${input.role} no presento el ticket que emitio la ronda`,
|
|
220001
|
+
isError: true
|
|
220002
|
+
};
|
|
220003
|
+
const stored = (fs.read(join(seatsDir, input.role)) ?? "").trim();
|
|
220004
|
+
if (stored === "" || stored !== seatTicketHash(presented)) return {
|
|
220005
|
+
output: `seats.foreign_replace: el ticket presentado no es el del asiento ${input.role}`,
|
|
220006
|
+
isError: true
|
|
220007
|
+
};
|
|
220008
|
+
if (input.replace === true && (input.reason ?? "").trim() === "") return {
|
|
220009
|
+
output: `seats.replace_without_reason: reescribir el artefacto del asiento ${input.role} exige un motivo no vacio`,
|
|
220010
|
+
isError: true
|
|
220011
|
+
};
|
|
220012
|
+
}
|
|
220013
|
+
const file = join(dir, `${input.role}.md`);
|
|
220014
|
+
if (fs.exists(file) && input.replace !== true) return {
|
|
220015
|
+
output: `el asiento ${input.role} ya entrego su artefacto; un asiento escribe una vez (usa replace solo para relanzar un fallo)`,
|
|
220016
|
+
isError: true
|
|
220017
|
+
};
|
|
220018
|
+
if (input.artifact.trim() === "") return {
|
|
220019
|
+
output: "el artefacto esta vacio: un asiento que no escribe, fallo",
|
|
220020
|
+
isError: true
|
|
220021
|
+
};
|
|
220022
|
+
fs.write(file, input.artifact.endsWith("\n") ? input.artifact : `${input.artifact}\n`);
|
|
220023
|
+
return { output: `escrito ${wavesRel}/${base.split("/").pop()}/${dirName}/${input.role}.md` };
|
|
220024
|
+
}
|
|
220025
|
+
var WAVE_SEATS_DIR;
|
|
220026
|
+
var init_submitRunner = __esmMin((() => {
|
|
220027
|
+
init_config$6();
|
|
220028
|
+
init_fsJson();
|
|
220029
|
+
init_nodeFs();
|
|
220030
|
+
WAVE_SEATS_DIR = ".seats";
|
|
220031
|
+
}));
|
|
219908
220032
|
// ../../packages/agent-core-v2/src/features/wave/tools/round/prompts.ts
|
|
219909
220033
|
var SEAT_PRELUDE, ROLE_PROMPTS, JUDGE_BIASES;
|
|
219910
220034
|
var init_prompts$2 = __esmMin((() => {
|
|
@@ -219932,16 +220056,6 @@ var init_prompts$2 = __esmMin((() => {
|
|
|
219932
220056
|
];
|
|
219933
220057
|
}));
|
|
219934
220058
|
// ../../packages/agent-core-v2/src/features/wave/tools/round/roundRunner.ts
|
|
219935
|
-
function range(prefix, count) {
|
|
219936
|
-
return Array.from({ length: Math.max(1, count) }, (_, index) => `${prefix}${index + 1}`);
|
|
219937
|
-
}
|
|
219938
|
-
function roleOf(cfg, round) {
|
|
219939
|
-
if (round === "propose") return cfg.proponents;
|
|
219940
|
-
if (round === "defend") return cfg.defenders;
|
|
219941
|
-
if (round === "attack") return cfg.adversaries;
|
|
219942
|
-
if (round === "judge") return cfg.judges;
|
|
219943
|
-
return 1;
|
|
219944
|
-
}
|
|
219945
220059
|
function runWaveRoundForRoot(input) {
|
|
219946
220060
|
const fs = nodeWaveFs;
|
|
219947
220061
|
const rawConfig = readJson$2(fs, join(input.root, "workflow.config.json"));
|
|
@@ -219950,9 +220064,8 @@ function runWaveRoundForRoot(input) {
|
|
|
219950
220064
|
seats: [],
|
|
219951
220065
|
isError: true
|
|
219952
220066
|
};
|
|
219953
|
-
const config =
|
|
219954
|
-
const
|
|
219955
|
-
const wavesRel = typeof layout["waves"] === "string" ? layout["waves"] : "design/waves";
|
|
220067
|
+
const config = makeWaveConfig(rawConfig);
|
|
220068
|
+
const wavesRel = config.layout.waves;
|
|
219956
220069
|
let wavesDir;
|
|
219957
220070
|
try {
|
|
219958
220071
|
wavesDir = containedPath(input.root, wavesRel);
|
|
@@ -219977,35 +220090,35 @@ function runWaveRoundForRoot(input) {
|
|
|
219977
220090
|
isError: true
|
|
219978
220091
|
};
|
|
219979
220092
|
const sections = brief.match(/^##\s+\S/gm)?.length ?? 0;
|
|
219980
|
-
|
|
219981
|
-
|
|
220093
|
+
const minimum = config.thresholds.minBriefSections;
|
|
220094
|
+
if (sections < minimum) return {
|
|
220095
|
+
output: `el brief tiene ${sections} secciones < ${minimum}: rellena las ${minimum} antes de lanzar la ronda`,
|
|
219982
220096
|
seats: [],
|
|
219983
220097
|
isError: true
|
|
219984
220098
|
};
|
|
219985
|
-
const
|
|
219986
|
-
const
|
|
219987
|
-
|
|
219988
|
-
defenders: typeof roles["defenders"] === "number" ? roles["defenders"] : 3,
|
|
219989
|
-
adversaries: typeof roles["adversaries"] === "number" ? roles["adversaries"] : 3,
|
|
219990
|
-
judges: typeof roles["judges"] === "number" ? roles["judges"] : 3
|
|
219991
|
-
};
|
|
219992
|
-
const shape = ROUNDS[input.round];
|
|
219993
|
-
const seats = shape.roles(roleOf(counts, input.round)).map((role) => {
|
|
220099
|
+
const dir = WAVE_ROUND_DIRS[input.round];
|
|
220100
|
+
const seatsDir = join(wavesDir, waveDir, WAVE_SEATS_DIR);
|
|
220101
|
+
const seats = waveRoundSeats(config.roles, input.round).map((role) => {
|
|
219994
220102
|
const bias = input.round === "judge" ? JUDGE_BIASES[(Number(role.slice(1)) - 1) % JUDGE_BIASES.length] : void 0;
|
|
219995
|
-
const file = `${wavesRel}/${waveDir}/${
|
|
220103
|
+
const file = `${wavesRel}/${waveDir}/${dir}/${role}.md`;
|
|
220104
|
+
const ticket = randomBytes(16).toString("hex");
|
|
220105
|
+
fs.write(join(seatsDir, role), `${seatTicketHash(ticket)}\n`);
|
|
219996
220106
|
const lines = [
|
|
219997
220107
|
SEAT_PRELUDE,
|
|
219998
220108
|
"",
|
|
219999
220109
|
ROLE_PROMPTS[input.round] ?? "",
|
|
220000
220110
|
"",
|
|
220111
|
+
`Perfil: ${WAVE_SEAT_PROFILE}`,
|
|
220001
220112
|
`Oleada: ${input.wave}. Brief: ${briefRel}.`,
|
|
220002
220113
|
`Escribe: ${file}.`,
|
|
220003
|
-
`
|
|
220114
|
+
`Ticket de asiento: ${ticket}. Es capacidad, no identidad: la ronda lo emitio para este asiento y WaveSubmit lo exige.`,
|
|
220115
|
+
`Entrega con WaveSubmit({ wave: "${input.wave}", round: "${input.round}", role: "${role}", ticket: "${ticket}", artifact: "..." }).`
|
|
220004
220116
|
];
|
|
220005
220117
|
if (bias !== void 0) lines.push(`Tu sesgo declarado es ${bias}: puntua CON el, no contra el.`);
|
|
220006
220118
|
return {
|
|
220007
220119
|
role,
|
|
220008
220120
|
file,
|
|
220121
|
+
ticket,
|
|
220009
220122
|
prompt: lines.join("\n")
|
|
220010
220123
|
};
|
|
220011
220124
|
});
|
|
@@ -220014,38 +220127,13 @@ function runWaveRoundForRoot(input) {
|
|
|
220014
220127
|
seats
|
|
220015
220128
|
};
|
|
220016
220129
|
}
|
|
220017
|
-
var ROUNDS;
|
|
220018
220130
|
var init_roundRunner = __esmMin((() => {
|
|
220019
220131
|
init_config$6();
|
|
220020
220132
|
init_fsJson();
|
|
220021
220133
|
init_nodeFs();
|
|
220134
|
+
init_wave$3();
|
|
220135
|
+
init_submitRunner();
|
|
220022
220136
|
init_prompts$2();
|
|
220023
|
-
ROUNDS = {
|
|
220024
|
-
propose: {
|
|
220025
|
-
dir: "01-proposals",
|
|
220026
|
-
roles: (count) => range("P", count)
|
|
220027
|
-
},
|
|
220028
|
-
defend: {
|
|
220029
|
-
dir: "02-defenses",
|
|
220030
|
-
roles: (count) => range("D", count)
|
|
220031
|
-
},
|
|
220032
|
-
attack: {
|
|
220033
|
-
dir: "03-attacks",
|
|
220034
|
-
roles: (count) => range("A", count)
|
|
220035
|
-
},
|
|
220036
|
-
judge: {
|
|
220037
|
-
dir: "04-verdicts",
|
|
220038
|
-
roles: (count) => range("J", count)
|
|
220039
|
-
},
|
|
220040
|
-
refine: {
|
|
220041
|
-
dir: "05-refined",
|
|
220042
|
-
roles: () => ["R1"]
|
|
220043
|
-
},
|
|
220044
|
-
audit: {
|
|
220045
|
-
dir: "05-refined",
|
|
220046
|
-
roles: () => ["R2"]
|
|
220047
|
-
}
|
|
220048
|
-
};
|
|
220049
220137
|
}));
|
|
220050
220138
|
// ../../packages/agent-core-v2/src/features/wave/tools/round/round.md?raw
|
|
220051
220139
|
var round_default;
|
|
@@ -220101,120 +220189,17 @@ var init_submit$1 = __esmMin((() => {
|
|
|
220101
220189
|
]),
|
|
220102
220190
|
role: string().min(2),
|
|
220103
220191
|
artifact: string().min(1),
|
|
220192
|
+
ticket: string().optional(),
|
|
220193
|
+
reason: string().optional(),
|
|
220104
220194
|
replace: boolean$1().optional(),
|
|
220105
220195
|
root: string().optional()
|
|
220106
220196
|
}).strict();
|
|
220107
220197
|
IWaveSubmitTool = createDecorator("waveSubmitTool");
|
|
220108
220198
|
}));
|
|
220109
|
-
// ../../packages/agent-core-v2/src/features/wave/tools/submit/submitRunner.ts
|
|
220110
|
-
function findWaveDir(root, wavesRel, wave) {
|
|
220111
|
-
const fs = nodeWaveFs;
|
|
220112
|
-
const wavesDir = containedPath(root, wavesRel);
|
|
220113
|
-
const name = fs.list(wavesDir).filter((entry) => fs.isDirectory(join(wavesDir, entry))).find((entry) => entry === wave || entry.startsWith(`${wave}-`));
|
|
220114
|
-
return name === void 0 ? void 0 : join(wavesDir, name);
|
|
220115
|
-
}
|
|
220116
|
-
function runWaveSubmitForRoot(input) {
|
|
220117
|
-
const fs = nodeWaveFs;
|
|
220118
|
-
const rawConfig = readJson$2(fs, join(input.root, "workflow.config.json"));
|
|
220119
|
-
if (rawConfig === void 0) return {
|
|
220120
|
-
output: `no hay workflow.config.json en ${input.root}`,
|
|
220121
|
-
isError: true
|
|
220122
|
-
};
|
|
220123
|
-
const layout = asRecord$2(asRecord$2(rawConfig)["layout"]);
|
|
220124
|
-
const wavesRel = typeof layout["waves"] === "string" ? layout["waves"] : "design/waves";
|
|
220125
|
-
const slot = ROUND_SLOTS[input.round];
|
|
220126
|
-
if (!slot.pattern.test(input.role)) return {
|
|
220127
|
-
output: `el rol "${input.role}" no pertenece a la ronda ${input.round} (esperado ${slot.names.join(", ")})`,
|
|
220128
|
-
isError: true
|
|
220129
|
-
};
|
|
220130
|
-
let base;
|
|
220131
|
-
try {
|
|
220132
|
-
base = findWaveDir(input.root, wavesRel, input.wave);
|
|
220133
|
-
} catch (error) {
|
|
220134
|
-
return {
|
|
220135
|
-
output: error instanceof Error ? error.message : String(error),
|
|
220136
|
-
isError: true
|
|
220137
|
-
};
|
|
220138
|
-
}
|
|
220139
|
-
if (base === void 0) return {
|
|
220140
|
-
output: `no existe la oleada ${input.wave} en ${wavesRel}`,
|
|
220141
|
-
isError: true
|
|
220142
|
-
};
|
|
220143
|
-
const dir = join(base, slot.dir);
|
|
220144
|
-
if (!fs.isDirectory(dir)) return {
|
|
220145
|
-
output: `falta el directorio ${slot.dir} en la oleada ${input.wave}`,
|
|
220146
|
-
isError: true
|
|
220147
|
-
};
|
|
220148
|
-
const file = join(dir, `${input.role}.md`);
|
|
220149
|
-
if (fs.exists(file) && input.replace !== true) return {
|
|
220150
|
-
output: `el asiento ${input.role} ya entrego su artefacto; un asiento escribe una vez (usa replace solo para relanzar un fallo)`,
|
|
220151
|
-
isError: true
|
|
220152
|
-
};
|
|
220153
|
-
if (input.artifact.trim() === "") return {
|
|
220154
|
-
output: "el artefacto esta vacio: un asiento que no escribe, fallo",
|
|
220155
|
-
isError: true
|
|
220156
|
-
};
|
|
220157
|
-
fs.write(file, input.artifact.endsWith("\n") ? input.artifact : `${input.artifact}\n`);
|
|
220158
|
-
return { output: `escrito ${wavesRel}/${base.split("/").pop()}/${slot.dir}/${input.role}.md` };
|
|
220159
|
-
}
|
|
220160
|
-
var ROUND_SLOTS;
|
|
220161
|
-
var init_submitRunner = __esmMin((() => {
|
|
220162
|
-
init_config$6();
|
|
220163
|
-
init_fsJson();
|
|
220164
|
-
init_nodeFs();
|
|
220165
|
-
ROUND_SLOTS = {
|
|
220166
|
-
propose: {
|
|
220167
|
-
dir: "01-proposals",
|
|
220168
|
-
pattern: /^P\d+$/,
|
|
220169
|
-
names: [
|
|
220170
|
-
"P1",
|
|
220171
|
-
"P2",
|
|
220172
|
-
"P3"
|
|
220173
|
-
]
|
|
220174
|
-
},
|
|
220175
|
-
defend: {
|
|
220176
|
-
dir: "02-defenses",
|
|
220177
|
-
pattern: /^D\d+$/,
|
|
220178
|
-
names: [
|
|
220179
|
-
"D1",
|
|
220180
|
-
"D2",
|
|
220181
|
-
"D3"
|
|
220182
|
-
]
|
|
220183
|
-
},
|
|
220184
|
-
attack: {
|
|
220185
|
-
dir: "03-attacks",
|
|
220186
|
-
pattern: /^A\d+$/,
|
|
220187
|
-
names: [
|
|
220188
|
-
"A1",
|
|
220189
|
-
"A2",
|
|
220190
|
-
"A3"
|
|
220191
|
-
]
|
|
220192
|
-
},
|
|
220193
|
-
judge: {
|
|
220194
|
-
dir: "04-verdicts",
|
|
220195
|
-
pattern: /^J\d+$/,
|
|
220196
|
-
names: [
|
|
220197
|
-
"J1",
|
|
220198
|
-
"J2",
|
|
220199
|
-
"J3"
|
|
220200
|
-
]
|
|
220201
|
-
},
|
|
220202
|
-
refine: {
|
|
220203
|
-
dir: "05-refined",
|
|
220204
|
-
pattern: /^R1$/,
|
|
220205
|
-
names: ["R1"]
|
|
220206
|
-
},
|
|
220207
|
-
audit: {
|
|
220208
|
-
dir: "05-refined",
|
|
220209
|
-
pattern: /^R2$/,
|
|
220210
|
-
names: ["R2"]
|
|
220211
|
-
}
|
|
220212
|
-
};
|
|
220213
|
-
}));
|
|
220214
220199
|
// ../../packages/agent-core-v2/src/features/wave/tools/submit/submit.md?raw
|
|
220215
220200
|
var submit_default;
|
|
220216
220201
|
var init_submit = __esmMin((() => {
|
|
220217
|
-
submit_default = "Deliver the artifact for your seat. This is the only way a seat writes: the tool binds the role to its slot and refuses anything else.\n\nRole and round must match — `propose` accepts P1..Pn, `defend` D1..Dn, `attack` A1..An, `judge` J1..Jn, `refine` R1, `audit` R2. A seat writes once; use `replace` only to relaunch a failed seat after its artifact was already written.\n\nPass the artifact as the text/JSON body. An empty artifact is rejected: a seat that did not write has failed, and the round must be relaunched rather than summarized by the orchestrator.\n";
|
|
220202
|
+
submit_default = "Deliver the artifact for your seat. This is the only way a seat writes: the tool binds the role to its slot and refuses anything else.\n\nRole and round must match — `propose` accepts P1..Pn, `defend` D1..Dn, `attack` A1..An, `judge` J1..Jn, `refine` R1, `audit` R2..Rn. A seat writes once; use `replace` only to relaunch a failed seat after its artifact was already written.\n\nPass the `ticket` the round gave you: the tool hashes it and compares it with the sha256 the round left in `design/waves/<W>/.seats/<role>`. A missing ticket, or the ticket of another seat, is refused as `seats.foreign_replace`. The ticket is capacity, not identity (capacidad, no identidad): it proves the orchestrator issued this seat, it does not say who wrote the artifact. `replace` also needs a non-empty `reason`, or the tool refuses it as `seats.replace_without_reason`: a silent overwrite is the substitution this tool exists to prevent.\n\nPass the artifact as the text/JSON body. An empty artifact is rejected: a seat that did not write has failed, and the round must be relaunched rather than summarized by the orchestrator.\n";
|
|
220218
220203
|
}));
|
|
220219
220204
|
// ../../packages/agent-core-v2/src/features/wave/tools/submit/submitTool.ts
|
|
220220
220205
|
var WaveSubmitTool;
|
|
@@ -220244,6 +220229,8 @@ var init_submitTool = __esmMin((() => {
|
|
|
220244
220229
|
round: args.round,
|
|
220245
220230
|
role: args.role,
|
|
220246
220231
|
artifact: args.artifact,
|
|
220232
|
+
ticket: args.ticket,
|
|
220233
|
+
reason: args.reason,
|
|
220247
220234
|
replace: args.replace
|
|
220248
220235
|
}))
|
|
220249
220236
|
};
|
|
@@ -220251,7 +220238,196 @@ var init_submitTool = __esmMin((() => {
|
|
|
220251
220238
|
};
|
|
220252
220239
|
WaveSubmitTool = __decorate([__decorateParam(0, ISessionContext)], WaveSubmitTool);
|
|
220253
220240
|
}));
|
|
220241
|
+
// ../../packages/agent-core-v2/src/features/wave/core/verify/runner.ts
|
|
220242
|
+
function splitCommand(command) {
|
|
220243
|
+
const tokens = [];
|
|
220244
|
+
let current = "";
|
|
220245
|
+
let quote;
|
|
220246
|
+
for (const char of command) {
|
|
220247
|
+
if (quote !== void 0) {
|
|
220248
|
+
if (char === quote) quote = void 0;
|
|
220249
|
+
else current += char;
|
|
220250
|
+
continue;
|
|
220251
|
+
}
|
|
220252
|
+
if (char === "\"" || char === "'") {
|
|
220253
|
+
quote = char;
|
|
220254
|
+
continue;
|
|
220255
|
+
}
|
|
220256
|
+
if (SHELL_METACHARACTERS.has(char)) throw new Error(`metacaracter de shell prohibido en: ${command}`);
|
|
220257
|
+
if (char === " " || char === " ") {
|
|
220258
|
+
if (current !== "") {
|
|
220259
|
+
tokens.push(current);
|
|
220260
|
+
current = "";
|
|
220261
|
+
}
|
|
220262
|
+
continue;
|
|
220263
|
+
}
|
|
220264
|
+
current += char;
|
|
220265
|
+
}
|
|
220266
|
+
if (quote !== void 0) throw new Error(`comillas sin cerrar en: ${command}`);
|
|
220267
|
+
if (current !== "") tokens.push(current);
|
|
220268
|
+
if (tokens.length === 0) throw new Error("comando vacio");
|
|
220269
|
+
return tokens;
|
|
220270
|
+
}
|
|
220271
|
+
function containPaths(argv, root) {
|
|
220272
|
+
for (const token of argv) {
|
|
220273
|
+
if (token.startsWith("-")) continue;
|
|
220274
|
+
if (!token.includes("/") && !/\.(mjs|cjs|js|ts|sh)$/.test(token)) continue;
|
|
220275
|
+
containedPath(root, token);
|
|
220276
|
+
}
|
|
220277
|
+
}
|
|
220278
|
+
function runCommand$2(command, options) {
|
|
220279
|
+
let argv;
|
|
220280
|
+
try {
|
|
220281
|
+
argv = splitCommand(command);
|
|
220282
|
+
const binary = (argv[0] ?? "").replace(/\.exe$/i, "");
|
|
220283
|
+
const allowed = options.allowBinaries.map((item) => item.replace(/\.exe$/i, ""));
|
|
220284
|
+
if (!allowed.includes(binary)) throw new Error(`binario no permitido: ${binary} (permitidos: ${allowed.join(", ")})`);
|
|
220285
|
+
containPaths(argv, options.root);
|
|
220286
|
+
} catch (error) {
|
|
220287
|
+
return {
|
|
220288
|
+
ok: false,
|
|
220289
|
+
output: `rechazado: ${error instanceof Error ? error.message : String(error)}`,
|
|
220290
|
+
rejected: true
|
|
220291
|
+
};
|
|
220292
|
+
}
|
|
220293
|
+
const result = spawnSync(argv[0] ?? "", argv.slice(1), {
|
|
220294
|
+
cwd: options.cwd ?? options.root,
|
|
220295
|
+
encoding: "utf8",
|
|
220296
|
+
timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS$1,
|
|
220297
|
+
stdio: "pipe",
|
|
220298
|
+
shell: false
|
|
220299
|
+
});
|
|
220300
|
+
const output = `${result.stdout ?? ""}${result.stderr ?? ""}${result.error === void 0 ? "" : result.error.message}`.replaceAll(/\s+/g, " ").trim().slice(0, 300);
|
|
220301
|
+
if (result.error !== void 0) return {
|
|
220302
|
+
ok: false,
|
|
220303
|
+
output: `no se pudo ejecutar: ${output}`,
|
|
220304
|
+
rejected: false
|
|
220305
|
+
};
|
|
220306
|
+
return {
|
|
220307
|
+
ok: result.status === 0,
|
|
220308
|
+
output,
|
|
220309
|
+
rejected: false,
|
|
220310
|
+
status: result.status ?? void 0
|
|
220311
|
+
};
|
|
220312
|
+
}
|
|
220313
|
+
function exitDetail(outcome) {
|
|
220314
|
+
return outcome.status === void 0 ? outcome.output : `exit ${outcome.status}: ${outcome.output}`;
|
|
220315
|
+
}
|
|
220316
|
+
function evaluateMutant(ac, verifyCommand, options) {
|
|
220317
|
+
const script = asText$1(asRecord$2(ac["falsifier"])["script"]);
|
|
220318
|
+
if (script === "") return {
|
|
220319
|
+
state: "declarado",
|
|
220320
|
+
detail: "sin falsifier.script: el AC queda declarado y cuenta como FALLO"
|
|
220321
|
+
};
|
|
220322
|
+
const acId = asText$1(ac["id"]);
|
|
220323
|
+
const apply = runCommand$2(`${script} apply`, options);
|
|
220324
|
+
if (apply.rejected) return {
|
|
220325
|
+
state: "rechazado",
|
|
220326
|
+
detail: `apply rechazado (${script}, ${acId}): ${apply.output}`
|
|
220327
|
+
};
|
|
220328
|
+
let mutated;
|
|
220329
|
+
let restore;
|
|
220330
|
+
try {
|
|
220331
|
+
if (apply.ok) mutated = runCommand$2(verifyCommand, options);
|
|
220332
|
+
} finally {
|
|
220333
|
+
restore = runCommand$2(`${script} restore`, options);
|
|
220334
|
+
}
|
|
220335
|
+
const failures = [];
|
|
220336
|
+
if (!apply.ok) failures.push(`apply fallo (${script}, ${acId}) ${exitDetail(apply)}`);
|
|
220337
|
+
if (restore.rejected || !restore.ok) failures.push(`restore fallo (${script}, ${acId}), el arbol puede estar sucio: ${restore.output}`);
|
|
220338
|
+
if (failures.length > 0) return {
|
|
220339
|
+
state: "error",
|
|
220340
|
+
detail: failures.join(" · ")
|
|
220341
|
+
};
|
|
220342
|
+
if (mutated === void 0) return {
|
|
220343
|
+
state: "error",
|
|
220344
|
+
detail: `no se ejecuto el verify con la mutacion de ${acId}`
|
|
220345
|
+
};
|
|
220346
|
+
if (mutated.ok) return {
|
|
220347
|
+
state: "sobrevive",
|
|
220348
|
+
detail: "el verify pasa con la mutacion aplicada: el AC no muerde"
|
|
220349
|
+
};
|
|
220350
|
+
if (!runCommand$2(verifyCommand, options).ok) return {
|
|
220351
|
+
state: "error",
|
|
220352
|
+
detail: "el verify no vuelve a verde tras restaurar"
|
|
220353
|
+
};
|
|
220354
|
+
return {
|
|
220355
|
+
state: "muerto",
|
|
220356
|
+
detail: "rojo con la mutacion, verde tras restaurar"
|
|
220357
|
+
};
|
|
220358
|
+
}
|
|
220359
|
+
function selectTaskCriteria(fs, root, cfg, taskId, ac) {
|
|
220360
|
+
const tasksDir = containedPath(root, cfg.layout.backlog);
|
|
220361
|
+
const file = walk$1(fs, join(tasksDir, "tasks"), (path) => path.endsWith(`${taskId}.json`))[0];
|
|
220362
|
+
if (file === void 0) throw new Error(`no encuentro la task ${taskId} en ${cfg.layout.backlog}/tasks/`);
|
|
220363
|
+
const criteria = asArray$2(asRecord$2(readJson$2(fs, file))["ac"]).map(asRecord$2);
|
|
220364
|
+
if (ac === void 0) return {
|
|
220365
|
+
taskId,
|
|
220366
|
+
criteria
|
|
220367
|
+
};
|
|
220368
|
+
const selected = criteria.filter((entry) => asText$1(entry["id"]) === ac);
|
|
220369
|
+
if (selected.length === 0) throw new Error(`no existe el criterio ${ac} en la task ${taskId}`);
|
|
220370
|
+
return {
|
|
220371
|
+
taskId,
|
|
220372
|
+
criteria: selected
|
|
220373
|
+
};
|
|
220374
|
+
}
|
|
220375
|
+
function verifyTask(fs, root, cfg, taskId, options) {
|
|
220376
|
+
const { criteria } = selectTaskCriteria(fs, root, cfg, taskId, options?.ac);
|
|
220377
|
+
const runOptions = {
|
|
220378
|
+
root,
|
|
220379
|
+
allowBinaries: cfg.vocabulary.verifyCommands,
|
|
220380
|
+
cwd: options?.cwd,
|
|
220381
|
+
timeoutMs: options?.timeoutMs
|
|
220382
|
+
};
|
|
220383
|
+
const acs = [];
|
|
220384
|
+
let declared = 0;
|
|
220385
|
+
for (const ac of criteria) {
|
|
220386
|
+
const verifyCommand = asText$1(ac["verify"]);
|
|
220387
|
+
const verify = runCommand$2(verifyCommand, runOptions);
|
|
220388
|
+
const mutant = evaluateMutant(ac, verifyCommand, runOptions);
|
|
220389
|
+
if (mutant.state === "declarado") declared++;
|
|
220390
|
+
const declaredOk = options?.allowDeclared === true && mutant.state === "declarado";
|
|
220391
|
+
const ok = verify.ok && (mutant.state === "muerto" || declaredOk);
|
|
220392
|
+
acs.push({
|
|
220393
|
+
acId: asText$1(ac["id"]),
|
|
220394
|
+
verify,
|
|
220395
|
+
mutant,
|
|
220396
|
+
ok
|
|
220397
|
+
});
|
|
220398
|
+
}
|
|
220399
|
+
return {
|
|
220400
|
+
taskId,
|
|
220401
|
+
acs,
|
|
220402
|
+
declared,
|
|
220403
|
+
ok: acs.length > 0 && acs.every((ac) => ac.ok)
|
|
220404
|
+
};
|
|
220405
|
+
}
|
|
220406
|
+
var SHELL_METACHARACTERS, DEFAULT_TIMEOUT_MS$1;
|
|
220407
|
+
var init_runner = __esmMin((() => {
|
|
220408
|
+
init_config$6();
|
|
220409
|
+
init_fsJson();
|
|
220410
|
+
SHELL_METACHARACTERS = /* @__PURE__ */ new Set([
|
|
220411
|
+
"|",
|
|
220412
|
+
"&",
|
|
220413
|
+
";",
|
|
220414
|
+
"<",
|
|
220415
|
+
">",
|
|
220416
|
+
"`",
|
|
220417
|
+
"$",
|
|
220418
|
+
"\n",
|
|
220419
|
+
"\r"
|
|
220420
|
+
]);
|
|
220421
|
+
DEFAULT_TIMEOUT_MS$1 = 6e5;
|
|
220422
|
+
}));
|
|
220254
220423
|
// ../../packages/agent-core-v2/src/features/wave/core/gate/checks.ts
|
|
220424
|
+
function measurableThreshold(text, units) {
|
|
220425
|
+
const low = normalize$1(text);
|
|
220426
|
+
if (OPERATOR_WITH_NUMBER.test(low)) return true;
|
|
220427
|
+
if (EXACT_VALUE.test(low)) return true;
|
|
220428
|
+
if (units.some((unit) => new RegExp(`\\d\\s*${escapeRegExp$1(unit)}\\b`).test(low))) return true;
|
|
220429
|
+
return low.split(/\s*(?:,|;|\by\b)\s*/).filter(Boolean).length >= 3;
|
|
220430
|
+
}
|
|
220255
220431
|
function record$1(value) {
|
|
220256
220432
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
220257
220433
|
}
|
|
@@ -220281,13 +220457,349 @@ function walk(fs, dir, accept, acc = []) {
|
|
|
220281
220457
|
}
|
|
220282
220458
|
function requiredArtifacts(cfg) {
|
|
220283
220459
|
const required = ["00-brief.md"];
|
|
220284
|
-
for (
|
|
220285
|
-
|
|
220286
|
-
for (let i = 1; i <= cfg.roles.adversaries; i++) required.push(`03-attacks/A${i}.md`);
|
|
220287
|
-
for (let i = 1; i <= cfg.roles.judges; i++) required.push(`04-verdicts/J${i}.md`);
|
|
220288
|
-
required.push("05-refined/R1.md", "05-refined/R2.md", DECISION_FILE, "07-epics.json");
|
|
220460
|
+
for (const round of WAVE_ROUNDS) for (const seat of waveRoundSeats(cfg.roles, round)) required.push(`${WAVE_ROUND_DIRS[round]}/${seat}.md`);
|
|
220461
|
+
required.push(DECISION_FILE, "07-epics.json");
|
|
220289
220462
|
return required;
|
|
220290
220463
|
}
|
|
220464
|
+
function briefSections(text) {
|
|
220465
|
+
const sections = [];
|
|
220466
|
+
let current;
|
|
220467
|
+
for (const line of text.split("\n")) {
|
|
220468
|
+
const heading = /^##\s+(.+?)\s*$/.exec(line);
|
|
220469
|
+
if (heading !== null) {
|
|
220470
|
+
current = {
|
|
220471
|
+
title: heading[1] ?? "",
|
|
220472
|
+
body: []
|
|
220473
|
+
};
|
|
220474
|
+
sections.push(current);
|
|
220475
|
+
continue;
|
|
220476
|
+
}
|
|
220477
|
+
if (/^#\s+/.test(line)) {
|
|
220478
|
+
current = void 0;
|
|
220479
|
+
continue;
|
|
220480
|
+
}
|
|
220481
|
+
current?.body.push(line);
|
|
220482
|
+
}
|
|
220483
|
+
return sections.map((section) => ({
|
|
220484
|
+
title: section.title,
|
|
220485
|
+
body: section.body.join("\n").trim()
|
|
220486
|
+
}));
|
|
220487
|
+
}
|
|
220488
|
+
function sectionKeyword(title) {
|
|
220489
|
+
return normalize$1(title).replace(/^\d+\.?\s*/, "").match(/[a-z0-9]+/)?.[0] ?? "";
|
|
220490
|
+
}
|
|
220491
|
+
function decisionStrip(value) {
|
|
220492
|
+
return (value ?? "").replaceAll("*", "").trim();
|
|
220493
|
+
}
|
|
220494
|
+
function decisionSplitRow(line) {
|
|
220495
|
+
return line.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((cell) => cell.trim());
|
|
220496
|
+
}
|
|
220497
|
+
function isDecisionSeparator(row) {
|
|
220498
|
+
return row.length > 0 && row.every((cell) => DECISION_SEPARATOR.test(decisionStrip(cell)));
|
|
220499
|
+
}
|
|
220500
|
+
function decisionTables(text) {
|
|
220501
|
+
const blocks = [];
|
|
220502
|
+
let current = [];
|
|
220503
|
+
for (const line of text.split("\n")) {
|
|
220504
|
+
if (line.trim().startsWith("|")) {
|
|
220505
|
+
current.push(decisionSplitRow(line));
|
|
220506
|
+
continue;
|
|
220507
|
+
}
|
|
220508
|
+
if (current.length > 0) blocks.push(current);
|
|
220509
|
+
current = [];
|
|
220510
|
+
}
|
|
220511
|
+
if (current.length > 0) blocks.push(current);
|
|
220512
|
+
return blocks.filter((block) => block.length >= 2).map((block) => ({
|
|
220513
|
+
header: block[0] ?? [],
|
|
220514
|
+
body: block.slice(1).filter((row) => !isDecisionSeparator(row) && row.length === (block[0] ?? []).length)
|
|
220515
|
+
}));
|
|
220516
|
+
}
|
|
220517
|
+
function decisionNumber(cell) {
|
|
220518
|
+
const value = decisionStrip(cell);
|
|
220519
|
+
if (value === "") return void 0;
|
|
220520
|
+
const match = DECISION_LEADING_NUMBER.exec(value);
|
|
220521
|
+
return match === null ? void 0 : Number(match[0].replace(",", "."));
|
|
220522
|
+
}
|
|
220523
|
+
function decisionProposal(cell) {
|
|
220524
|
+
const value = decisionStrip(cell);
|
|
220525
|
+
if (value === "") return void 0;
|
|
220526
|
+
return DECISION_PROPOSAL.test(value.toLowerCase()) ? value.toUpperCase() : void 0;
|
|
220527
|
+
}
|
|
220528
|
+
function decisionAxis(row, axes) {
|
|
220529
|
+
const low = normalize$1(decisionStrip(row));
|
|
220530
|
+
if (low === "") return void 0;
|
|
220531
|
+
const exact = axes.find((axis) => normalize$1(axis) === low);
|
|
220532
|
+
if (exact !== void 0) return exact;
|
|
220533
|
+
return axes.find((axis) => low.includes(normalize$1(axis)));
|
|
220534
|
+
}
|
|
220535
|
+
function isDecisionTotal(cell) {
|
|
220536
|
+
return /\btotal\b/.test(normalize$1(decisionStrip(cell)));
|
|
220537
|
+
}
|
|
220538
|
+
function isDecisionMedian(cell) {
|
|
220539
|
+
return /\bmedian/.test(normalize$1(decisionStrip(cell)));
|
|
220540
|
+
}
|
|
220541
|
+
function decisionColumn(header, predicate) {
|
|
220542
|
+
return header.findIndex((cell) => predicate(cell));
|
|
220543
|
+
}
|
|
220544
|
+
function findDecisionMatrix(blocks, axes) {
|
|
220545
|
+
let best;
|
|
220546
|
+
for (const block of blocks) {
|
|
220547
|
+
const header = block.header.map(decisionStrip);
|
|
220548
|
+
const columnProposals = header.filter((cell) => decisionProposal(cell) !== void 0);
|
|
220549
|
+
const rowProposals = block.body.filter((row) => decisionProposal(row[0]) !== void 0);
|
|
220550
|
+
const axisColumns = header.filter((cell) => decisionAxis(cell, axes) !== void 0 && !isDecisionTotal(cell) && !isDecisionMedian(cell));
|
|
220551
|
+
const axisRows = block.body.filter((row) => decisionAxis(row[0], axes) !== void 0);
|
|
220552
|
+
const byColumn = columnProposals.length >= 2 && axisRows.length > 0;
|
|
220553
|
+
const byRow = rowProposals.length >= 2 && axisColumns.length > 0;
|
|
220554
|
+
if (!byColumn && !byRow) continue;
|
|
220555
|
+
const score = Math.max(axisRows.length, axisColumns.length) * 10 + Math.max(columnProposals.length, rowProposals.length);
|
|
220556
|
+
if (best === void 0 || score > best.score) best = {
|
|
220557
|
+
block,
|
|
220558
|
+
orientation: byColumn ? "columns" : "rows",
|
|
220559
|
+
score
|
|
220560
|
+
};
|
|
220561
|
+
}
|
|
220562
|
+
return best;
|
|
220563
|
+
}
|
|
220564
|
+
function readDecisionColumns(block, axes, proposals, found) {
|
|
220565
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
220566
|
+
for (const [index, cell] of block.header.entries()) {
|
|
220567
|
+
const proposal = decisionProposal(cell);
|
|
220568
|
+
if (proposal !== void 0 && !indexes.has(proposal)) indexes.set(proposal, index);
|
|
220569
|
+
}
|
|
220570
|
+
for (const row of block.body) {
|
|
220571
|
+
const axis = decisionAxis(row[0], axes);
|
|
220572
|
+
if (axis === void 0 || found.has(axis)) continue;
|
|
220573
|
+
const cells = {};
|
|
220574
|
+
found.set(axis, {
|
|
220575
|
+
label: decisionStrip(row[0]),
|
|
220576
|
+
cells
|
|
220577
|
+
});
|
|
220578
|
+
for (const proposal of proposals) {
|
|
220579
|
+
const index = indexes.get(proposal);
|
|
220580
|
+
cells[proposal] = index === void 0 ? void 0 : decisionNumber(row[index]);
|
|
220581
|
+
}
|
|
220582
|
+
}
|
|
220583
|
+
return indexes;
|
|
220584
|
+
}
|
|
220585
|
+
function readDecisionRows(block, axes, found) {
|
|
220586
|
+
const columns = [];
|
|
220587
|
+
for (const [index, cell] of block.header.entries()) {
|
|
220588
|
+
const axis = decisionAxis(cell, axes);
|
|
220589
|
+
if (axis === void 0 || isDecisionTotal(cell) || isDecisionMedian(cell)) continue;
|
|
220590
|
+
columns.push({
|
|
220591
|
+
axis,
|
|
220592
|
+
index,
|
|
220593
|
+
label: decisionStrip(cell)
|
|
220594
|
+
});
|
|
220595
|
+
}
|
|
220596
|
+
const seen = [];
|
|
220597
|
+
for (const row of block.body) {
|
|
220598
|
+
const proposal = decisionProposal(row[0]);
|
|
220599
|
+
if (proposal === void 0) continue;
|
|
220600
|
+
if (!seen.includes(proposal)) seen.push(proposal);
|
|
220601
|
+
for (const column of columns) {
|
|
220602
|
+
const existing = found.get(column.axis);
|
|
220603
|
+
const entry = existing ?? {
|
|
220604
|
+
label: column.label,
|
|
220605
|
+
cells: {}
|
|
220606
|
+
};
|
|
220607
|
+
if (existing === void 0) found.set(column.axis, entry);
|
|
220608
|
+
if (entry.cells[proposal] !== void 0) continue;
|
|
220609
|
+
entry.cells[proposal] = decisionNumber(row[column.index]);
|
|
220610
|
+
}
|
|
220611
|
+
}
|
|
220612
|
+
return seen;
|
|
220613
|
+
}
|
|
220614
|
+
function decisionDeclarations(blocks, matrix, proposals) {
|
|
220615
|
+
const totals = {};
|
|
220616
|
+
const medians = {};
|
|
220617
|
+
const take = (target, proposal, value) => {
|
|
220618
|
+
if (proposal === void 0 || value === void 0 || target[proposal] !== void 0) return;
|
|
220619
|
+
target[proposal] = value;
|
|
220620
|
+
};
|
|
220621
|
+
if (matrix !== void 0) {
|
|
220622
|
+
const header = matrix.block.header.map(decisionStrip);
|
|
220623
|
+
const totalColumn = matrix.orientation === "rows" ? decisionColumn(header, isDecisionTotal) : -1;
|
|
220624
|
+
const medianColumn = matrix.orientation === "rows" ? decisionColumn(header, isDecisionMedian) : -1;
|
|
220625
|
+
for (const row of matrix.block.body) {
|
|
220626
|
+
const proposal = decisionProposal(row[0]);
|
|
220627
|
+
if (proposal !== void 0) {
|
|
220628
|
+
if (totalColumn !== -1) take(totals, proposal, decisionNumber(row[totalColumn]));
|
|
220629
|
+
if (medianColumn !== -1) take(medians, proposal, decisionNumber(row[medianColumn]));
|
|
220630
|
+
continue;
|
|
220631
|
+
}
|
|
220632
|
+
if (isDecisionTotal(row[0]) || isDecisionMedian(row[0])) {
|
|
220633
|
+
const target = isDecisionTotal(row[0]) ? totals : medians;
|
|
220634
|
+
for (const item of proposals) {
|
|
220635
|
+
const index = header.findIndex((cell) => decisionProposal(cell) === item);
|
|
220636
|
+
take(target, item, index === -1 ? void 0 : decisionNumber(row[index]));
|
|
220637
|
+
}
|
|
220638
|
+
}
|
|
220639
|
+
}
|
|
220640
|
+
}
|
|
220641
|
+
for (const block of blocks) {
|
|
220642
|
+
const header = block.header.map(decisionStrip);
|
|
220643
|
+
const totalColumn = decisionColumn(header, isDecisionTotal);
|
|
220644
|
+
const medianColumn = decisionColumn(header, isDecisionMedian);
|
|
220645
|
+
if (totalColumn === -1 && medianColumn === -1) continue;
|
|
220646
|
+
for (const row of block.body) {
|
|
220647
|
+
const proposal = decisionProposal(row[0]);
|
|
220648
|
+
if (proposal === void 0) continue;
|
|
220649
|
+
if (totalColumn !== -1) take(totals, proposal, decisionNumber(row[totalColumn]));
|
|
220650
|
+
if (medianColumn !== -1) take(medians, proposal, decisionNumber(row[medianColumn]));
|
|
220651
|
+
}
|
|
220652
|
+
}
|
|
220653
|
+
return {
|
|
220654
|
+
totals,
|
|
220655
|
+
medians
|
|
220656
|
+
};
|
|
220657
|
+
}
|
|
220658
|
+
function decisionMargins(blocks) {
|
|
220659
|
+
for (const block of blocks) {
|
|
220660
|
+
const header = block.header.map(decisionStrip);
|
|
220661
|
+
const judgeColumn = decisionColumn(header, (cell) => normalize$1(cell).includes("juez"));
|
|
220662
|
+
const marginColumn = decisionColumn(header, (cell) => normalize$1(cell).includes("margen"));
|
|
220663
|
+
if (judgeColumn === -1 || marginColumn === -1) continue;
|
|
220664
|
+
const preferColumn = decisionColumn(header, (cell) => normalize$1(cell).includes("prefer"));
|
|
220665
|
+
const rows = [];
|
|
220666
|
+
for (const row of block.body) {
|
|
220667
|
+
const judge = decisionStrip(row[judgeColumn]);
|
|
220668
|
+
if (!DECISION_JUDGE.test(judge)) continue;
|
|
220669
|
+
const margin = DECISION_SIGNED_MARGIN.exec(decisionStrip(row[marginColumn]));
|
|
220670
|
+
if (margin === null) continue;
|
|
220671
|
+
rows.push({
|
|
220672
|
+
judge,
|
|
220673
|
+
margin: Number((margin[1] ?? "0").replace(",", ".")),
|
|
220674
|
+
prefers: preferColumn === -1 ? void 0 : decisionProposal(row[preferColumn])
|
|
220675
|
+
});
|
|
220676
|
+
}
|
|
220677
|
+
if (rows.length > 0) return rows;
|
|
220678
|
+
}
|
|
220679
|
+
return [];
|
|
220680
|
+
}
|
|
220681
|
+
function decisionDissent(text) {
|
|
220682
|
+
const lines = text.split("\n");
|
|
220683
|
+
const start = lines.findIndex((line) => /^#{1,3}\s+\d*\.?\s*disidencias/i.test(line));
|
|
220684
|
+
if (start === -1) return void 0;
|
|
220685
|
+
const level = /^(#{1,3})/.exec(lines[start] ?? "")?.[1]?.length ?? 1;
|
|
220686
|
+
const collected = [];
|
|
220687
|
+
for (const line of lines.slice(start + 1)) {
|
|
220688
|
+
const heading = /^(#{1,3})\s+\S/.exec(line);
|
|
220689
|
+
if (heading !== null && (heading[1] ?? "").length <= level) break;
|
|
220690
|
+
collected.push(line);
|
|
220691
|
+
}
|
|
220692
|
+
return collected.join("\n").trim();
|
|
220693
|
+
}
|
|
220694
|
+
function parseDecisionMatrix(text, options) {
|
|
220695
|
+
const axes = options.axes.map(String);
|
|
220696
|
+
const blocks = decisionTables(text);
|
|
220697
|
+
const matrix = findDecisionMatrix(blocks, axes);
|
|
220698
|
+
const found = /* @__PURE__ */ new Map();
|
|
220699
|
+
let proposals = options.proposals.map(String);
|
|
220700
|
+
let present = [];
|
|
220701
|
+
if (matrix !== void 0) {
|
|
220702
|
+
if (matrix.orientation === "columns") {
|
|
220703
|
+
if (proposals.length === 0) proposals = matrix.block.header.map(decisionStrip).map(decisionProposal).filter((label) => label !== void 0);
|
|
220704
|
+
const indexes = readDecisionColumns(matrix.block, axes, proposals, found);
|
|
220705
|
+
present = proposals.filter((proposal) => indexes.has(proposal));
|
|
220706
|
+
} else {
|
|
220707
|
+
if (proposals.length === 0) proposals = matrix.block.body.map((row) => decisionProposal(row[0])).filter((label) => label !== void 0);
|
|
220708
|
+
const seen = readDecisionRows(matrix.block, axes, found);
|
|
220709
|
+
present = proposals.filter((proposal) => seen.includes(proposal));
|
|
220710
|
+
}
|
|
220711
|
+
}
|
|
220712
|
+
const axisRows = [];
|
|
220713
|
+
const cells = [];
|
|
220714
|
+
const missing = [];
|
|
220715
|
+
for (const axis of axes) {
|
|
220716
|
+
const row = found.get(axis);
|
|
220717
|
+
if (row === void 0) continue;
|
|
220718
|
+
axisRows.push({
|
|
220719
|
+
axis,
|
|
220720
|
+
label: row.label,
|
|
220721
|
+
cells: row.cells
|
|
220722
|
+
});
|
|
220723
|
+
for (const proposal of present) {
|
|
220724
|
+
const value = row.cells[proposal];
|
|
220725
|
+
if (typeof value === "number") cells.push({
|
|
220726
|
+
axis,
|
|
220727
|
+
proposal,
|
|
220728
|
+
value
|
|
220729
|
+
});
|
|
220730
|
+
else missing.push({
|
|
220731
|
+
axis,
|
|
220732
|
+
proposal
|
|
220733
|
+
});
|
|
220734
|
+
}
|
|
220735
|
+
}
|
|
220736
|
+
const declarations = decisionDeclarations(blocks, matrix, proposals);
|
|
220737
|
+
const axesFound = axisRows.map((row) => row.axis);
|
|
220738
|
+
return {
|
|
220739
|
+
present: matrix !== void 0,
|
|
220740
|
+
orientation: matrix?.orientation,
|
|
220741
|
+
header: matrix === void 0 ? [] : matrix.block.header.map(decisionStrip),
|
|
220742
|
+
proposals,
|
|
220743
|
+
presentProposals: present,
|
|
220744
|
+
axisRows,
|
|
220745
|
+
cells,
|
|
220746
|
+
missing,
|
|
220747
|
+
axesFound,
|
|
220748
|
+
axesMissing: axes.filter((axis) => !axesFound.includes(axis)),
|
|
220749
|
+
totals: declarations.totals,
|
|
220750
|
+
medians: declarations.medians,
|
|
220751
|
+
margins: decisionMargins(blocks),
|
|
220752
|
+
dissent: decisionDissent(text)
|
|
220753
|
+
};
|
|
220754
|
+
}
|
|
220755
|
+
function decisionProposalSum(matrix, proposal) {
|
|
220756
|
+
const values = matrix.axisRows.map((row) => row.cells[proposal]);
|
|
220757
|
+
if (values.length === 0) return void 0;
|
|
220758
|
+
let total = 0;
|
|
220759
|
+
for (const value of values) {
|
|
220760
|
+
if (typeof value !== "number") return void 0;
|
|
220761
|
+
total += value;
|
|
220762
|
+
}
|
|
220763
|
+
return total;
|
|
220764
|
+
}
|
|
220765
|
+
function decisionMedian(values) {
|
|
220766
|
+
if (values.length === 0) return void 0;
|
|
220767
|
+
const sorted = [...values].toSorted((left, right) => left - right);
|
|
220768
|
+
const middle = Math.floor(sorted.length / 2);
|
|
220769
|
+
const current = sorted[middle];
|
|
220770
|
+
if (current === void 0) return void 0;
|
|
220771
|
+
if (sorted.length % 2 === 1) return current;
|
|
220772
|
+
const previous = sorted[middle - 1];
|
|
220773
|
+
return previous === void 0 ? void 0 : (previous + current) / 2;
|
|
220774
|
+
}
|
|
220775
|
+
function decisionRecalculateMedians(verdicts, options) {
|
|
220776
|
+
const tables = [];
|
|
220777
|
+
const missing = [];
|
|
220778
|
+
for (const verdict of verdicts) {
|
|
220779
|
+
const matrix = parseDecisionMatrix(verdict.text, options);
|
|
220780
|
+
if (!(matrix.present && matrix.axesMissing.length === 0 && matrix.missing.length === 0)) {
|
|
220781
|
+
missing.push(verdict.file);
|
|
220782
|
+
continue;
|
|
220783
|
+
}
|
|
220784
|
+
const totals = {};
|
|
220785
|
+
for (const proposal of matrix.proposals) totals[proposal] = decisionProposalSum(matrix, proposal) ?? NaN;
|
|
220786
|
+
tables.push({
|
|
220787
|
+
file: verdict.file,
|
|
220788
|
+
totals
|
|
220789
|
+
});
|
|
220790
|
+
}
|
|
220791
|
+
const medians = {};
|
|
220792
|
+
if (missing.length === 0 && tables.length > 0) for (const proposal of options.proposals) {
|
|
220793
|
+
const values = tables.map((entry) => entry.totals[proposal]).filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
220794
|
+
if (values.length !== tables.length) continue;
|
|
220795
|
+
const value = decisionMedian(values);
|
|
220796
|
+
if (value !== void 0) medians[proposal] = value;
|
|
220797
|
+
}
|
|
220798
|
+
return {
|
|
220799
|
+
medians,
|
|
220800
|
+
missing
|
|
220801
|
+
};
|
|
220802
|
+
}
|
|
220291
220803
|
function runWaveGate(fs, root, cfg) {
|
|
220292
220804
|
const findings = [];
|
|
220293
220805
|
const blocks = [];
|
|
@@ -220315,8 +220827,24 @@ function runWaveGate(fs, root, cfg) {
|
|
|
220315
220827
|
let epics = [];
|
|
220316
220828
|
let tasks = [];
|
|
220317
220829
|
let totalAc = 0;
|
|
220830
|
+
const state = waveConfigState(cfg);
|
|
220318
220831
|
block("config", () => {
|
|
220319
220832
|
if (cfg.loadedFrom === void 0) add("config.missing", null, "no se encontro workflow.config.json");
|
|
220833
|
+
const raw = state.raw;
|
|
220834
|
+
const version = typeof raw["version"] === "number" ? raw["version"] : state.version;
|
|
220835
|
+
for (const key of [
|
|
220836
|
+
"version",
|
|
220837
|
+
"layout",
|
|
220838
|
+
"waves",
|
|
220839
|
+
"thresholds",
|
|
220840
|
+
"vocabulary"
|
|
220841
|
+
]) if (raw[key] === void 0) add("config.missing_key", null, `falta la clave "${key}"`);
|
|
220842
|
+
if (version !== 1 && version !== 2) add("config.version_unknown", null, `version "${String(version)}" fuera de uno y dos: el gate no sabe leerla`);
|
|
220843
|
+
if (version === 2) {
|
|
220844
|
+
if (raw["wavesOpen"] === void 0) add("config.missing_key", null, "falta la clave \"wavesOpen\"");
|
|
220845
|
+
if (raw["vocabulary"] === void 0 || record$1(raw["vocabulary"])["units"] === void 0) add("config.missing_key", null, "falta la clave \"vocabulary.units\"");
|
|
220846
|
+
if (raw["falsifier"] === void 0) add("config.missing_key", null, "falta la clave \"falsifier\"");
|
|
220847
|
+
}
|
|
220320
220848
|
if (cfg.waves.length === 0) add("config.bad_waves", null, "waves debe ser un array no vacio");
|
|
220321
220849
|
if (vocabulary.verifyCommands.length === 0) add("config.bad_vocabulary", null, "vocabulary.verifyCommands vacio");
|
|
220322
220850
|
if (vocabulary.verifyPrefixes.length === 0) add("config.bad_vocabulary", null, "vocabulary.verifyPrefixes vacio");
|
|
@@ -220352,19 +220880,89 @@ function runWaveGate(fs, root, cfg) {
|
|
|
220352
220880
|
}
|
|
220353
220881
|
}
|
|
220354
220882
|
});
|
|
220883
|
+
block("brief", () => {
|
|
220884
|
+
const templateFile = join(root, BRIEF_TEMPLATE);
|
|
220885
|
+
if (!fs.exists(templateFile)) return;
|
|
220886
|
+
const template = briefSections(fs.read(templateFile) ?? "");
|
|
220887
|
+
if (wavesDir === void 0 || !fs.isDirectory(wavesDir)) return;
|
|
220888
|
+
for (const wave of cfg.waves) {
|
|
220889
|
+
const match = waveDirs.find((name) => name === wave || name.startsWith(`${wave}-`));
|
|
220890
|
+
if (match === void 0) continue;
|
|
220891
|
+
const file = join(wavesDir, match, "00-brief.md");
|
|
220892
|
+
const text = fs.read(file);
|
|
220893
|
+
if (text === void 0) continue;
|
|
220894
|
+
const at = relative$1(root, file);
|
|
220895
|
+
const sections = briefSections(text);
|
|
220896
|
+
if (sections.length !== template.length) add("waves.brief_template_drift", at, `${sections.length} secciones frente a ${template.length} de ${BRIEF_TEMPLATE}: el brief ya no sigue la plantilla`);
|
|
220897
|
+
for (const [index, expected] of template.entries()) {
|
|
220898
|
+
const section = sections[index];
|
|
220899
|
+
if (section === void 0) continue;
|
|
220900
|
+
if (sectionKeyword(section.title) !== sectionKeyword(expected.title)) add("waves.brief_template_drift", at, `la seccion ${index + 1} se titula "${section.title}" y ${BRIEF_TEMPLATE} exige "${expected.title}"`);
|
|
220901
|
+
}
|
|
220902
|
+
for (const section of sections) if (section.body === "") add("waves.brief_empty_section", at, `la seccion "${section.title}" no tiene contenido`);
|
|
220903
|
+
}
|
|
220904
|
+
});
|
|
220355
220905
|
block("decision", () => {
|
|
220356
220906
|
const dir = wavesDir;
|
|
220357
220907
|
if (dir === void 0 || !fs.isDirectory(dir)) return;
|
|
220908
|
+
const axes = cfg.quorum.axes;
|
|
220909
|
+
const proposals = Array.from({ length: cfg.roles.proponents }, (_, index) => `P${index + 1}`);
|
|
220910
|
+
const judges = cfg.roles.judges;
|
|
220358
220911
|
for (const wave of cfg.waves) {
|
|
220359
220912
|
const match = waveDirs.find((name) => name === wave || name.startsWith(`${wave}-`));
|
|
220360
220913
|
if (match === void 0) continue;
|
|
220361
|
-
const
|
|
220914
|
+
const base = join(dir, match);
|
|
220915
|
+
const file = join(base, DECISION_FILE);
|
|
220362
220916
|
const text = fs.read(file);
|
|
220363
220917
|
if (text === void 0) continue;
|
|
220364
220918
|
const low = normalize$1(text);
|
|
220365
220919
|
const at = relative$1(root, file);
|
|
220366
|
-
|
|
220367
|
-
|
|
220920
|
+
const matrix = parseDecisionMatrix(text, {
|
|
220921
|
+
axes,
|
|
220922
|
+
proposals
|
|
220923
|
+
});
|
|
220924
|
+
for (const proposal of proposals) if (!matrix.presentProposals.includes(proposal)) add("waves.decision_missing_role", at, `no hay columna ${proposal} en la matriz de la ronda`);
|
|
220925
|
+
if (!matrix.present) add("waves.decision_without_quorum", at, "sin tabla de la matriz: la ronda no trae puntuaciones que auditar");
|
|
220926
|
+
else {
|
|
220927
|
+
for (const axis of axes) if (!matrix.axesFound.includes(axis)) add("waves.decision_missing_axis", at, `sin eje "${axis}" en la matriz`);
|
|
220928
|
+
for (const item of matrix.missing) add("waves.decision_matrix_incomplete", at, `eje "${item.axis}" · propuesta ${item.proposal}: celda vacia`);
|
|
220929
|
+
for (const proposal of proposals) {
|
|
220930
|
+
const declared = matrix.totals[proposal];
|
|
220931
|
+
const sum = decisionProposalSum(matrix, proposal);
|
|
220932
|
+
if (declared === void 0 || sum === void 0 || declared === sum) continue;
|
|
220933
|
+
add("waves.decision_total_mismatch", at, `${proposal}: total declarado ${declared} y recalculado ${sum} desde las celdas de la matriz`);
|
|
220934
|
+
}
|
|
220935
|
+
if (proposals.some((proposal) => matrix.medians[proposal] !== void 0)) {
|
|
220936
|
+
const verdictsDir = join(base, "04-verdicts");
|
|
220937
|
+
const recalc = decisionRecalculateMedians(Array.from({ length: judges }, (_, index) => {
|
|
220938
|
+
const name = `J${index + 1}.md`;
|
|
220939
|
+
return {
|
|
220940
|
+
file: `${relative$1(root, verdictsDir)}/${name}`,
|
|
220941
|
+
text: fs.read(join(verdictsDir, name)) ?? ""
|
|
220942
|
+
};
|
|
220943
|
+
}), {
|
|
220944
|
+
axes,
|
|
220945
|
+
proposals
|
|
220946
|
+
});
|
|
220947
|
+
for (const missing of recalc.missing) add("waves.decision_matrix_incomplete", missing, `sin tabla de ${axes.length} ejes por propuesta: no hay de donde recalcular la mediana`);
|
|
220948
|
+
if (recalc.missing.length === 0) {
|
|
220949
|
+
const citation = Array.from({ length: judges }, (_, index) => `04-verdicts/J${index + 1}.md`).join(", ");
|
|
220950
|
+
for (const proposal of proposals) {
|
|
220951
|
+
const declared = matrix.medians[proposal];
|
|
220952
|
+
const value = recalc.medians[proposal];
|
|
220953
|
+
if (declared === void 0 || value === void 0 || declared === value) continue;
|
|
220954
|
+
add("waves.decision_median_mismatch", at, `${proposal}: mediana declarada ${declared} y recalculada ${value} desde ${citation}`);
|
|
220955
|
+
}
|
|
220956
|
+
}
|
|
220957
|
+
}
|
|
220958
|
+
if (matrix.margins.length > 0) {
|
|
220959
|
+
const dissent = normalize$1(matrix.dissent ?? "");
|
|
220960
|
+
for (const row of matrix.margins) {
|
|
220961
|
+
if (row.margin >= 0 || dissent.includes(normalize$1(row.judge))) continue;
|
|
220962
|
+
add("waves.decision_undisclosed_dissent", at, `${row.judge}: margen ${row.margin} y no aparece en "## Disidencias"`);
|
|
220963
|
+
}
|
|
220964
|
+
}
|
|
220965
|
+
}
|
|
220368
220966
|
if (!/^#{1,3}\s+\d*\.?\s*disidencias/im.test(text)) add("waves.decision_without_dissent", at, "falta la seccion \"## Disidencias\"");
|
|
220369
220967
|
if (text.length < thresholds.minDecisionBytes) add("waves.decision_thin", at, `${text.length} B < ${thresholds.minDecisionBytes} B minimos`);
|
|
220370
220968
|
const numbers = text.match(/\b\d+(?:[.,]\d+)?\b/g)?.length ?? 0;
|
|
@@ -220453,8 +221051,16 @@ function runWaveGate(fs, root, cfg) {
|
|
|
220453
221051
|
if (tasks.length < thresholds.minTasks) add("tasks.count", null, `${tasks.length} tasks < ${thresholds.minTasks} minimas`);
|
|
220454
221052
|
});
|
|
220455
221053
|
block("ac", () => {
|
|
220456
|
-
const vague = vocabulary.vagueWords.map((word) => normalize$1(word)).filter(Boolean)
|
|
221054
|
+
const vague = vocabulary.vagueWords.map((word) => normalize$1(word)).filter(Boolean).map((word) => ({
|
|
221055
|
+
word,
|
|
221056
|
+
root: word.replace(/[aeiou]$/, "")
|
|
221057
|
+
})).filter((entry) => entry.root !== "");
|
|
221058
|
+
const units = asArray$1(record$1(state.raw["vocabulary"])["units"]).map(str$2).map(normalize$1).filter(Boolean);
|
|
221059
|
+
const falsifierLexicon = record$1(state.raw["falsifier"]);
|
|
221060
|
+
const stateVerbs = asArray$1(falsifierLexicon["stateVerbs"]).map(str$2).map(normalize$1).filter(Boolean);
|
|
221061
|
+
const stateObjects = asArray$1(falsifierLexicon["stateObjects"]).map(str$2).map(normalize$1).filter(Boolean);
|
|
220457
221062
|
const withFalsifier = /* @__PURE__ */ new Set();
|
|
221063
|
+
const openWaves = new Set(state.wavesOpen);
|
|
220458
221064
|
for (const task of tasks) {
|
|
220459
221065
|
const taskId = str$2(task["id"]);
|
|
220460
221066
|
for (const raw of asArray$1(task["ac"])) {
|
|
@@ -220474,17 +221080,53 @@ function runWaveGate(fs, root, cfg) {
|
|
|
220474
221080
|
}
|
|
220475
221081
|
const metric = str$2(ac["metric"]);
|
|
220476
221082
|
if (metric !== "" && metric.length < thresholds.minMetricChars) add("ac.short_metric", at, `"metric" < ${thresholds.minMetricChars} caracteres`);
|
|
220477
|
-
const
|
|
220478
|
-
|
|
220479
|
-
|
|
221083
|
+
const threshold = str$2(ac["threshold"]);
|
|
221084
|
+
if (threshold !== "" && !measurableThreshold(threshold, units)) add("ac.threshold_not_measurable", at, `"${threshold}" no compara ninguna magnitud: falta operador con numero, numero con unidad o conjunto enumerable`);
|
|
221085
|
+
const prose = normalize$1(`${str$2(ac["then"])} ${threshold} ${metric}`);
|
|
221086
|
+
const vagueHit = vague.find((entry) => new RegExp(`\\b${escapeRegExp$1(entry.root)}[a-z]{0,10}\\b`).test(prose));
|
|
221087
|
+
if (vagueHit !== void 0) {
|
|
221088
|
+
const matched = new RegExp(`\\b${escapeRegExp$1(vagueHit.root)}[a-z]{0,10}\\b`).exec(prose)?.[0] ?? vagueHit.root;
|
|
221089
|
+
add("ac.vague_language", at, `"${matched}" contiene la raiz "${vagueHit.root}" de "${vagueHit.word}": no es medible`);
|
|
221090
|
+
}
|
|
220480
221091
|
const verify = str$2(ac["verify"]).trim();
|
|
220481
221092
|
if (verify !== "") {
|
|
220482
221093
|
const command = verify.split(/\s+/)[0] ?? "";
|
|
220483
221094
|
if (!vocabulary.verifyCommands.includes(command)) add("ac.verify_not_command", at, `"${command}" no es un comando de la lista permitida`);
|
|
220484
221095
|
else {
|
|
220485
|
-
|
|
220486
|
-
|
|
220487
|
-
|
|
221096
|
+
let argv;
|
|
221097
|
+
try {
|
|
221098
|
+
argv = splitCommand(verify);
|
|
221099
|
+
} catch (error) {
|
|
221100
|
+
add("ac.verify_command_unsafe", at, error instanceof Error ? error.message : String(error));
|
|
221101
|
+
}
|
|
221102
|
+
if (argv !== void 0) {
|
|
221103
|
+
let escaped;
|
|
221104
|
+
for (const token of argv) {
|
|
221105
|
+
if (token.startsWith("-") || !token.includes("/")) continue;
|
|
221106
|
+
try {
|
|
221107
|
+
containedPath(root, token);
|
|
221108
|
+
} catch {
|
|
221109
|
+
escaped = token;
|
|
221110
|
+
break;
|
|
221111
|
+
}
|
|
221112
|
+
}
|
|
221113
|
+
if (escaped !== void 0) add("ac.verify_command_unsafe", at, `el token "${escaped}" escapa de la raiz del paquete`);
|
|
221114
|
+
else {
|
|
221115
|
+
const token = argv.slice(1).find((item) => !item.startsWith("-") && item.includes("/"));
|
|
221116
|
+
if (token === void 0) add("ac.verify_outside_test_plan", at, "el comando no apunta a ningun fichero o directorio verificable");
|
|
221117
|
+
else {
|
|
221118
|
+
const target = token.replace(/^\.\//, "");
|
|
221119
|
+
if (!vocabulary.verifyPrefixes.some((prefix) => target.startsWith(prefix))) add("ac.verify_outside_test_plan", at, `"${target}" fuera del test plan declarado`);
|
|
221120
|
+
else if (state.version >= 2 && !openWaves.has(str$2(task["wave"])) && !fs.exists(join(root, target))) add("ac.verify_target_missing", at, `el destino "${target}" no existe bajo la raiz del paquete`);
|
|
221121
|
+
const destination = join(root, target);
|
|
221122
|
+
const isTest = /(^|\/)test\//.test(target) || /\.test\./.test(target);
|
|
221123
|
+
const exempt = /(^|\/)scripts\//.test(target);
|
|
221124
|
+
if (isTest && !exempt && fs.exists(destination) && fs.isDirectory(destination) === false) {
|
|
221125
|
+
if ((fs.read(destination) ?? "").match(ASSERTION) === null) add("ac.verify_stub", at, `el destino "${target}" no tiene ninguna asercion: el verify no mide nada`);
|
|
221126
|
+
}
|
|
221127
|
+
}
|
|
221128
|
+
}
|
|
221129
|
+
}
|
|
220488
221130
|
}
|
|
220489
221131
|
}
|
|
220490
221132
|
const falsifier = record$1(ac["falsifier"]);
|
|
@@ -220494,6 +221136,11 @@ function runWaveGate(fs, root, cfg) {
|
|
|
220494
221136
|
if (mutation.length < thresholds.minFieldChars) add("ac.falsifier_thin", at, "falsifier.mutation insuficiente");
|
|
220495
221137
|
else if (expect.length < thresholds.minFieldChars) add("ac.falsifier_thin", at, "falsifier.expect insuficiente");
|
|
220496
221138
|
else withFalsifier.add(taskId);
|
|
221139
|
+
const normalizedMutation = normalize$1(mutation);
|
|
221140
|
+
const verb = stateVerbs.find((entry) => new RegExp(`\\b${escapeRegExp$1(entry)}[a-z]{0,4}\\b`).test(normalizedMutation));
|
|
221141
|
+
const object = stateObjects.find((entry) => new RegExp(`\\b${escapeRegExp$1(entry)}s?\\b`).test(normalizedMutation));
|
|
221142
|
+
const reversible = str$2(falsifier["script"]).trim() !== "" || str$2(falsifier["restore"]).trim() !== "";
|
|
221143
|
+
if (verb !== void 0 && object !== void 0 && !reversible) add("ac.falsifier_not_reversible", at, `la mutacion "${verb} ... ${object}" toca estado sin falsifier.script ni falsifier.restore`);
|
|
220497
221144
|
}
|
|
220498
221145
|
}
|
|
220499
221146
|
}
|
|
@@ -220555,14 +221202,17 @@ function runWaveGate(fs, root, cfg) {
|
|
|
220555
221202
|
waves: cfg.waves.length,
|
|
220556
221203
|
epics: epics.length,
|
|
220557
221204
|
tasks: tasks.length,
|
|
220558
|
-
ac: totalAc
|
|
221205
|
+
ac: totalAc,
|
|
221206
|
+
notRun: NOT_RUN_BLOCKS
|
|
220559
221207
|
}
|
|
220560
221208
|
};
|
|
220561
221209
|
}
|
|
220562
|
-
var DECISION_FILE, AC_FIELDS, normalize$1, relative$1;
|
|
221210
|
+
var DECISION_FILE, BRIEF_TEMPLATE, AC_FIELDS, OPERATOR_WITH_NUMBER, EXACT_VALUE, ASSERTION, escapeRegExp$1, NOT_RUN_BLOCKS, normalize$1, relative$1, DECISION_SEPARATOR, DECISION_PROPOSAL, DECISION_LEADING_NUMBER, DECISION_JUDGE, DECISION_SIGNED_MARGIN;
|
|
220563
221211
|
var init_checks = __esmMin((() => {
|
|
220564
221212
|
init_config$6();
|
|
221213
|
+
init_runner();
|
|
220565
221214
|
DECISION_FILE = "06-DECISION.md";
|
|
221215
|
+
BRIEF_TEMPLATE = "workflow/templates/brief.md";
|
|
220566
221216
|
AC_FIELDS = [
|
|
220567
221217
|
"id",
|
|
220568
221218
|
"given",
|
|
@@ -220573,8 +221223,24 @@ var init_checks = __esmMin((() => {
|
|
|
220573
221223
|
"verify",
|
|
220574
221224
|
"falsifier"
|
|
220575
221225
|
];
|
|
221226
|
+
OPERATOR_WITH_NUMBER = /[=<>≥≤]\s*\d|\b(?:mayor|menor|igual|al menos|como maximo|como minimo)\b[^0-9]{0,20}\d/;
|
|
221227
|
+
EXACT_VALUE = /\b\d+(?:[.,]\d+)?\s+(?:exacto|exacta|exactos|exactas|fijo|fija|justo|justa)\b/;
|
|
221228
|
+
ASSERTION = /\bassert\b|\bexpect\s*\(|\bit\s*\(|\btest\s*\(|\bfailures\b|process\.exit\s*\(\s*(?!0\b)/g;
|
|
221229
|
+
escapeRegExp$1 = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
221230
|
+
NOT_RUN_BLOCKS = [{
|
|
221231
|
+
block: "regression",
|
|
221232
|
+
closedBy: "oracle"
|
|
221233
|
+
}, {
|
|
221234
|
+
block: "schemas",
|
|
221235
|
+
closedBy: "oracle"
|
|
221236
|
+
}];
|
|
220576
221237
|
normalize$1 = (value) => value.normalize("NFD").replaceAll(/[\u0300-\u036F]/g, "").toLowerCase();
|
|
220577
221238
|
relative$1 = (root, path) => path.startsWith(root) ? path.slice(root.length).replaceAll("\\", "/").replace(/^\/+/, "") : path;
|
|
221239
|
+
DECISION_SEPARATOR = /^:?-{2,}:?$/;
|
|
221240
|
+
DECISION_PROPOSAL = /^p\d+$/;
|
|
221241
|
+
DECISION_LEADING_NUMBER = /^[+-]?\d+(?:[.,]\d+)?/;
|
|
221242
|
+
DECISION_JUDGE = /^J\d+$/;
|
|
221243
|
+
DECISION_SIGNED_MARGIN = /^([+-]?\d+(?:[.,]\d+)?)$/;
|
|
220578
221244
|
}));
|
|
220579
221245
|
// ../../packages/agent-core-v2/src/features/wave/tools/gate/gateRunner.ts
|
|
220580
221246
|
function runWaveGateForRoot(input) {
|
|
@@ -220596,6 +221262,7 @@ function runWaveGateForRoot(input) {
|
|
|
220596
221262
|
};
|
|
220597
221263
|
const lines = [`GATE — ${report.ok ? "verde" : "con hallazgos"}`, ""];
|
|
220598
221264
|
for (const block of report.blocks) lines.push(`${block.ok ? "OK " : "FAIL"} ${block.name}`);
|
|
221265
|
+
for (const entry of report.summary.notRun) lines.push(`NO EJECUTADO ${entry.block} — cerrado por ${entry.closedBy}`);
|
|
220599
221266
|
if (report.findings.length > 0) {
|
|
220600
221267
|
lines.push("", `PENDIENTE: ${report.findings.length} hallazgo(s)`, "");
|
|
220601
221268
|
for (const finding of report.findings) lines.push(` - ${finding.code}${finding.path === null ? "" : ` ${finding.path}`} — ${finding.message}`);
|
|
@@ -220654,168 +221321,37 @@ var init_verify$1 = __esmMin((() => {
|
|
|
220654
221321
|
init_instantiation();
|
|
220655
221322
|
WaveVerifyToolInputSchema = object$1({
|
|
220656
221323
|
task: string().min(3),
|
|
220657
|
-
root: string().optional()
|
|
221324
|
+
root: string().optional(),
|
|
221325
|
+
ac: string().min(3).optional(),
|
|
221326
|
+
dryRun: boolean$1().optional(),
|
|
221327
|
+
allowDeclared: boolean$1().optional()
|
|
220658
221328
|
}).strict();
|
|
220659
221329
|
IWaveVerifyTool = createDecorator("waveVerifyTool");
|
|
220660
221330
|
}));
|
|
220661
|
-
// ../../packages/agent-core-v2/src/features/wave/
|
|
220662
|
-
function
|
|
220663
|
-
|
|
220664
|
-
|
|
220665
|
-
|
|
220666
|
-
|
|
220667
|
-
if (quote !== void 0) {
|
|
220668
|
-
if (char === quote) quote = void 0;
|
|
220669
|
-
else current += char;
|
|
220670
|
-
continue;
|
|
220671
|
-
}
|
|
220672
|
-
if (char === "\"" || char === "'") {
|
|
220673
|
-
quote = char;
|
|
220674
|
-
continue;
|
|
220675
|
-
}
|
|
220676
|
-
if (SHELL_METACHARACTERS.has(char)) throw new Error(`metacaracter de shell prohibido en: ${command}`);
|
|
220677
|
-
if (char === " " || char === " ") {
|
|
220678
|
-
if (current !== "") {
|
|
220679
|
-
tokens.push(current);
|
|
220680
|
-
current = "";
|
|
220681
|
-
}
|
|
220682
|
-
continue;
|
|
220683
|
-
}
|
|
220684
|
-
current += char;
|
|
220685
|
-
}
|
|
220686
|
-
if (quote !== void 0) throw new Error(`comillas sin cerrar en: ${command}`);
|
|
220687
|
-
if (current !== "") tokens.push(current);
|
|
220688
|
-
if (tokens.length === 0) throw new Error("comando vacio");
|
|
220689
|
-
return tokens;
|
|
220690
|
-
}
|
|
220691
|
-
function containPaths(argv, root) {
|
|
220692
|
-
for (const token of argv) {
|
|
220693
|
-
if (token.startsWith("-")) continue;
|
|
220694
|
-
if (!token.includes("/") && !/\.(mjs|cjs|js|ts|sh)$/.test(token)) continue;
|
|
220695
|
-
containedPath(root, token);
|
|
220696
|
-
}
|
|
221331
|
+
// ../../packages/agent-core-v2/src/features/wave/tools/verify/verifyRunner.ts
|
|
221332
|
+
function failure$1(error) {
|
|
221333
|
+
return {
|
|
221334
|
+
output: error instanceof Error ? error.message : String(error),
|
|
221335
|
+
isError: true
|
|
221336
|
+
};
|
|
220697
221337
|
}
|
|
220698
|
-
function
|
|
220699
|
-
let
|
|
221338
|
+
function runDry(root, config, input) {
|
|
221339
|
+
let selected;
|
|
220700
221340
|
try {
|
|
220701
|
-
|
|
220702
|
-
const binary = (argv[0] ?? "").replace(/\.exe$/i, "");
|
|
220703
|
-
const allowed = options.allowBinaries.map((item) => item.replace(/\.exe$/i, ""));
|
|
220704
|
-
if (!allowed.includes(binary)) throw new Error(`binario no permitido: ${binary} (permitidos: ${allowed.join(", ")})`);
|
|
220705
|
-
containPaths(argv, options.root);
|
|
221341
|
+
selected = selectTaskCriteria(nodeWaveFs, root, config, input.task, input.ac);
|
|
220706
221342
|
} catch (error) {
|
|
220707
|
-
return
|
|
220708
|
-
ok: false,
|
|
220709
|
-
output: `rechazado: ${error instanceof Error ? error.message : String(error)}`,
|
|
220710
|
-
rejected: true
|
|
220711
|
-
};
|
|
221343
|
+
return failure$1(error);
|
|
220712
221344
|
}
|
|
220713
|
-
const
|
|
220714
|
-
|
|
220715
|
-
|
|
220716
|
-
|
|
220717
|
-
|
|
220718
|
-
|
|
220719
|
-
});
|
|
220720
|
-
const output = `${result.stdout ?? ""}${result.stderr ?? ""}${result.error === void 0 ? "" : result.error.message}`.replaceAll(/\s+/g, " ").trim().slice(0, 300);
|
|
220721
|
-
if (result.error !== void 0) return {
|
|
220722
|
-
ok: false,
|
|
220723
|
-
output: `no se pudo ejecutar: ${output}`,
|
|
220724
|
-
rejected: false
|
|
220725
|
-
};
|
|
220726
|
-
return {
|
|
220727
|
-
ok: result.status === 0,
|
|
220728
|
-
output,
|
|
220729
|
-
rejected: false
|
|
220730
|
-
};
|
|
220731
|
-
}
|
|
220732
|
-
function evaluateMutant(ac, verifyCommand, options) {
|
|
220733
|
-
const script = asText$1(asRecord$2(ac["falsifier"])["script"]);
|
|
220734
|
-
if (script === "") return {
|
|
220735
|
-
state: "declarado",
|
|
220736
|
-
detail: "sin falsifier.script: el AC queda declarado y cuenta como FALLO"
|
|
220737
|
-
};
|
|
220738
|
-
const apply = runCommand$2(`${script} apply`, options);
|
|
220739
|
-
if (apply.rejected) return {
|
|
220740
|
-
state: "rechazado",
|
|
220741
|
-
detail: `apply rechazado: ${apply.output}`
|
|
220742
|
-
};
|
|
220743
|
-
if (!apply.ok) return {
|
|
220744
|
-
state: "error",
|
|
220745
|
-
detail: `apply fallo: ${apply.output}`
|
|
220746
|
-
};
|
|
220747
|
-
const mutated = runCommand$2(verifyCommand, options);
|
|
220748
|
-
const restore = runCommand$2(`${script} restore`, options);
|
|
220749
|
-
const after = runCommand$2(verifyCommand, options);
|
|
220750
|
-
if (restore.rejected || !restore.ok) return {
|
|
220751
|
-
state: "error",
|
|
220752
|
-
detail: `restore fallo, el arbol puede estar sucio: ${restore.output}`
|
|
220753
|
-
};
|
|
220754
|
-
if (mutated.ok) return {
|
|
220755
|
-
state: "sobrevive",
|
|
220756
|
-
detail: "el verify pasa con la mutacion aplicada: el AC no muerde"
|
|
220757
|
-
};
|
|
220758
|
-
if (!after.ok) return {
|
|
220759
|
-
state: "error",
|
|
220760
|
-
detail: "el verify no vuelve a verde tras restaurar"
|
|
220761
|
-
};
|
|
220762
|
-
return {
|
|
220763
|
-
state: "muerto",
|
|
220764
|
-
detail: "rojo con la mutacion, verde tras restaurar"
|
|
220765
|
-
};
|
|
220766
|
-
}
|
|
220767
|
-
function verifyTask(fs, root, cfg, taskId, options) {
|
|
220768
|
-
const tasksDir = containedPath(root, cfg.layout.backlog);
|
|
220769
|
-
const file = walk$1(fs, join(tasksDir, "tasks"), (path) => path.endsWith(`${taskId}.json`))[0];
|
|
220770
|
-
if (file === void 0) throw new Error(`no encuentro la task ${taskId} en ${cfg.layout.backlog}/tasks/`);
|
|
220771
|
-
const task = asRecord$2(readJson$2(fs, file));
|
|
220772
|
-
const runOptions = {
|
|
220773
|
-
root,
|
|
220774
|
-
allowBinaries: cfg.vocabulary.verifyCommands,
|
|
220775
|
-
cwd: options?.cwd,
|
|
220776
|
-
timeoutMs: options?.timeoutMs
|
|
220777
|
-
};
|
|
220778
|
-
const acs = [];
|
|
220779
|
-
let declared = 0;
|
|
220780
|
-
for (const raw of asArray$2(task["ac"])) {
|
|
220781
|
-
const ac = asRecord$2(raw);
|
|
220782
|
-
const verifyCommand = asText$1(ac["verify"]);
|
|
220783
|
-
const verify = runCommand$2(verifyCommand, runOptions);
|
|
220784
|
-
const mutant = evaluateMutant(ac, verifyCommand, runOptions);
|
|
220785
|
-
if (mutant.state === "declarado") declared++;
|
|
220786
|
-
const ok = verify.ok && mutant.state === "muerto";
|
|
220787
|
-
acs.push({
|
|
220788
|
-
acId: asText$1(ac["id"]),
|
|
220789
|
-
verify,
|
|
220790
|
-
mutant,
|
|
220791
|
-
ok
|
|
220792
|
-
});
|
|
221345
|
+
const lines = [`TASK ${selected.taskId} · dryRun: no se ejecuta ningun comando`, ""];
|
|
221346
|
+
for (const ac of selected.criteria) {
|
|
221347
|
+
const falsifier = asRecord$2(ac["falsifier"]);
|
|
221348
|
+
lines.push(`dry ${asText$1(ac["id"])}`);
|
|
221349
|
+
lines.push(` verify: ${asText$1(ac["verify"])}`);
|
|
221350
|
+
lines.push(` mutacion: ${asText$1(falsifier["mutation"])}`);
|
|
220793
221351
|
}
|
|
220794
|
-
|
|
220795
|
-
|
|
220796
|
-
acs,
|
|
220797
|
-
declared,
|
|
220798
|
-
ok: acs.length > 0 && acs.every((ac) => ac.ok)
|
|
220799
|
-
};
|
|
221352
|
+
lines.push("", `criterios ${selected.criteria.length} · comandos 0`);
|
|
221353
|
+
return { output: lines.join("\n") };
|
|
220800
221354
|
}
|
|
220801
|
-
var SHELL_METACHARACTERS, DEFAULT_TIMEOUT_MS$1;
|
|
220802
|
-
var init_runner = __esmMin((() => {
|
|
220803
|
-
init_config$6();
|
|
220804
|
-
init_fsJson();
|
|
220805
|
-
SHELL_METACHARACTERS = /* @__PURE__ */ new Set([
|
|
220806
|
-
"|",
|
|
220807
|
-
"&",
|
|
220808
|
-
";",
|
|
220809
|
-
"<",
|
|
220810
|
-
">",
|
|
220811
|
-
"`",
|
|
220812
|
-
"$",
|
|
220813
|
-
"\n",
|
|
220814
|
-
"\r"
|
|
220815
|
-
]);
|
|
220816
|
-
DEFAULT_TIMEOUT_MS$1 = 6e5;
|
|
220817
|
-
}));
|
|
220818
|
-
// ../../packages/agent-core-v2/src/features/wave/tools/verify/verifyRunner.ts
|
|
220819
221355
|
function runWaveVerifyForRoot(input) {
|
|
220820
221356
|
const root = resolve(input.root);
|
|
220821
221357
|
const config = readWaveConfig(nodeWaveFs, root);
|
|
@@ -220823,7 +221359,16 @@ function runWaveVerifyForRoot(input) {
|
|
|
220823
221359
|
output: `no hay workflow.config.json en ${root}`,
|
|
220824
221360
|
isError: true
|
|
220825
221361
|
};
|
|
220826
|
-
|
|
221362
|
+
if (input.dryRun === true) return runDry(root, config, input);
|
|
221363
|
+
let result;
|
|
221364
|
+
try {
|
|
221365
|
+
result = verifyTask(nodeWaveFs, root, config, input.task, {
|
|
221366
|
+
ac: input.ac,
|
|
221367
|
+
allowDeclared: input.allowDeclared
|
|
221368
|
+
});
|
|
221369
|
+
} catch (error) {
|
|
221370
|
+
return failure$1(error);
|
|
221371
|
+
}
|
|
220827
221372
|
const lines = [`TASK ${result.taskId}`, ""];
|
|
220828
221373
|
for (const ac of result.acs) {
|
|
220829
221374
|
lines.push(`${ac.ok ? "ok " : "FAIL"} ${ac.acId} verify ${ac.verify.ok ? "verde" : "rojo"} mutante ${ac.mutant.state}`);
|
|
@@ -220839,13 +221384,14 @@ function runWaveVerifyForRoot(input) {
|
|
|
220839
221384
|
}
|
|
220840
221385
|
var init_verifyRunner = __esmMin((() => {
|
|
220841
221386
|
init_config$6();
|
|
221387
|
+
init_fsJson();
|
|
220842
221388
|
init_nodeFs();
|
|
220843
221389
|
init_runner();
|
|
220844
221390
|
}));
|
|
220845
221391
|
// ../../packages/agent-core-v2/src/features/wave/tools/verify/verify.md?raw
|
|
220846
221392
|
var verify_default;
|
|
220847
221393
|
var init_verify = __esmMin((() => {
|
|
220848
|
-
verify_default = "Close a wave task with evidence: run each acceptance criterion's `verify` command and its falsifier.\n\nFor every criterion the tool runs `verify`, then `apply` of `falsifier.script`, then `verify` again (which must now fail), then `restore`, then `verify` once more (which must pass again). A criterion whose falsifier is only declared, whose mutant survives, or whose tree does not return to green is a failure — never a pass with a note.\n\nThe task id (`E01-T01`) is looked up in `backlog/tasks/`. Commands run without a shell and only with the binaries allowed by `vocabulary.verifyCommands`.\n";
|
|
221394
|
+
verify_default = "Close a wave task with evidence: run each acceptance criterion's `verify` command and its falsifier.\n\nFor every criterion the tool runs `verify`, then `apply` of `falsifier.script`, then `verify` again (which must now fail), then `restore`, then `verify` once more (which must pass again). A criterion whose falsifier is only declared, whose mutant survives, or whose tree does not return to green is a failure — never a pass with a note.\n\nThe task id (`E01-T01`) is looked up in `backlog/tasks/`. Commands run without a shell and only with the binaries allowed by `vocabulary.verifyCommands`.\n\nArguments:\n- `task`: task id to verify.\n- `root`: workspace root. Defaults to the current working directory.\n- `ac`: verify only this acceptance criterion instead of every criterion of the task. An id the task does not declare is rejected.\n- `dryRun`: list the criteria and the command each one would run without executing anything, so a coordinator can review before spending the run.\n";
|
|
220849
221395
|
}));
|
|
220850
221396
|
// ../../packages/agent-core-v2/src/features/wave/tools/verify/verifyTool.ts
|
|
220851
221397
|
var WaveVerifyTool;
|
|
@@ -220871,7 +221417,10 @@ var init_verifyTool = __esmMin((() => {
|
|
|
220871
221417
|
approvalRule: this.name,
|
|
220872
221418
|
execute: () => Promise.resolve(runWaveVerifyForRoot({
|
|
220873
221419
|
root: args.root ?? this.sessionContext.cwd,
|
|
220874
|
-
task: args.task
|
|
221420
|
+
task: args.task,
|
|
221421
|
+
ac: args.ac,
|
|
221422
|
+
dryRun: args.dryRun,
|
|
221423
|
+
allowDeclared: args.allowDeclared
|
|
220875
221424
|
}))
|
|
220876
221425
|
};
|
|
220877
221426
|
}
|
|
@@ -228271,7 +228820,7 @@ var init_mcpRegistryService = __esmMin((() => {
|
|
|
228271
228820
|
}
|
|
228272
228821
|
} else {
|
|
228273
228822
|
const cwd = canonicalWorkspaceRoot(query.cwd);
|
|
228274
|
-
if (!(await readWorkspaceTrust(this.docs, cwd) ||
|
|
228823
|
+
if (!(await readWorkspaceTrust(this.docs, cwd) || (workspaceTrustOverride((name) => this.bootstrap.getEnv(name)) ?? true))) {
|
|
228275
228824
|
const userEntries = await this.store.list();
|
|
228276
228825
|
for (const server of userEntries) {
|
|
228277
228826
|
const { name, ...config } = server;
|
|
@@ -477531,8 +478080,8 @@ function buildWavePrompt(args) {
|
|
|
477531
478080
|
"",
|
|
477532
478081
|
"Reglas de la oleada:",
|
|
477533
478082
|
"- Usa las tools Wave: `WaveOpen` para abrirla, `WaveRound` para obtener el prompt de cada asiento, `WaveSubmit` para que cada asiento entregue su artefacto, `WaveDecide` para el quórum, `WaveGate` para el paquete y `WaveVerify` para cerrar tasks.",
|
|
477534
|
-
"- Lanza un agente por asiento con `Agent` (o `AgentSwarm` si el usuario activó swarm)
|
|
477535
|
-
"-
|
|
478083
|
+
"- Lanza un agente por asiento con `Agent` (o `AgentSwarm` si el usuario activó swarm) pasando `subagent_type: \"wave-seat\"` y el prompt que devuelve `WaveRound`. No inventes el prompt ni cambies el rol.",
|
|
478084
|
+
"- El asiento es de solo lectura: `Read`, `Glob`, `Grep` y `WaveSubmit`. Nunca escribe con Write/Edit: entrega con `WaveSubmit`, que ata rol y ruta.",
|
|
477536
478085
|
"- Si el brief no tiene las siete secciones, para y pide que se rellenen; no lo escribas tú.",
|
|
477537
478086
|
"- Sin `adopt` de `WaveDecide`, lanza `refine` y después `audit`; con dos rondas sin quórum, adopta R1 con disidencia escrita.",
|
|
477538
478087
|
"- La oleada no está cerrada hasta que `WaveGate` sale en verde. Si sale en rojo, dilo con los códigos de hallazgo."
|
|
@@ -501094,7 +501643,7 @@ var NexgenTUI = class {
|
|
|
501094
501643
|
const { startup } = this.options;
|
|
501095
501644
|
const config = await this.harness.getConfig({ reload: true });
|
|
501096
501645
|
const patch = includeModel ? lazyModelSelection(config, startup.model ?? config.defaultModel) : {};
|
|
501097
|
-
if (!startup.auto && !startup.yolo) patch.permissionMode = config.defaultPermissionMode ?? "
|
|
501646
|
+
if (!startup.auto && !startup.yolo) patch.permissionMode = config.defaultPermissionMode ?? "auto";
|
|
501098
501647
|
patch.configDefaultPlanMode = config.defaultPlanMode === true;
|
|
501099
501648
|
if (!startup.plan) patch.planMode = config.defaultPlanMode === true;
|
|
501100
501649
|
if (startup.agentProfile !== void 0 || startup.agentFiles !== void 0) {
|