nexgenk 1.4.1 → 1.6.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.
Files changed (2) hide show
  1. package/dist/main.mjs +1723 -999
  2. package/package.json +1 -1
package/dist/main.mjs CHANGED
@@ -47481,6 +47481,14 @@ var init_session$4 = __esmMin((() => {
47481
47481
  enabled: false
47482
47482
  });
47483
47483
  }
47484
+ async setWaveMode(enabled) {
47485
+ this.ensureOpen();
47486
+ if (typeof enabled !== "boolean") throw new NexgenError(ErrorCodes$1.REQUEST_INVALID, "Session wave mode must be a boolean");
47487
+ await this.rpc.setWaveMode({
47488
+ sessionId: this.id,
47489
+ enabled
47490
+ });
47491
+ }
47484
47492
  async setTowerMode(enabled, base) {
47485
47493
  this.ensureOpen();
47486
47494
  if (typeof enabled !== "boolean") throw new NexgenError(ErrorCodes$1.REQUEST_INVALID, "Session tower mode must be a boolean");
@@ -106094,6 +106102,12 @@ var init_statusReader = __esmMin((() => {
106094
106102
  INBOX_COUNT_LIMIT = 1e3;
106095
106103
  RECENT_LOG_LINES = 10;
106096
106104
  }));
106105
+ // ../../packages/agent-core-v2/src/features/wave/agent/waveMode.ts
106106
+ var IAgentWaveService;
106107
+ var init_waveMode = __esmMin((() => {
106108
+ init_instantiation();
106109
+ IAgentWaveService = createDecorator("agentWaveService");
106110
+ }));
106097
106111
  // ../../packages/agent-core-v2/src/_base/di/descriptors.ts
106098
106112
  var SyncDescriptor;
106099
106113
  var init_descriptors = __esmMin((() => {
@@ -111222,7 +111236,7 @@ function dump$1(input, options) {
111222
111236
  if (writeNode(state, 0, value, true, true)) return state.dump + "\n";
111223
111237
  return "";
111224
111238
  }
111225
- var common, exception, snippet, TYPE_CONSTRUCTOR_OPTIONS, YAML_NODE_KINDS, type$2, schema, str$3, seq, map, failsafe, _null, bool$1, int, YAML_FLOAT_PATTERN, SCIENTIFIC_WITHOUT_DOT, float, json, core, YAML_DATE_REGEXP, YAML_TIMESTAMP_REGEXP, timestamp$1, merge, BASE64_MAP, binary, _hasOwnProperty$3, _toString$2, omap, _toString$1, pairs, _hasOwnProperty$2, set$1, _default, _hasOwnProperty$1, CONTEXT_FLOW_IN, CONTEXT_FLOW_OUT, CONTEXT_BLOCK_IN, CONTEXT_BLOCK_OUT, CHOMPING_CLIP, CHOMPING_STRIP, CHOMPING_KEEP, PATTERN_NON_PRINTABLE, PATTERN_NON_ASCII_LINE_BREAKS, PATTERN_FLOW_INDICATORS, PATTERN_TAG_HANDLE, PATTERN_TAG_URI, simpleEscapeCheck, simpleEscapeMap, i$1, directiveHandlers, loader, _toString, _hasOwnProperty, CHAR_BOM, CHAR_TAB, CHAR_LINE_FEED, CHAR_CARRIAGE_RETURN, CHAR_SPACE, CHAR_EXCLAMATION, CHAR_DOUBLE_QUOTE, CHAR_SHARP, CHAR_PERCENT, CHAR_AMPERSAND, CHAR_SINGLE_QUOTE, CHAR_ASTERISK, CHAR_COMMA, CHAR_MINUS, CHAR_COLON, CHAR_EQUALS, CHAR_GREATER_THAN, CHAR_QUESTION, CHAR_COMMERCIAL_AT, CHAR_LEFT_SQUARE_BRACKET, CHAR_RIGHT_SQUARE_BRACKET, CHAR_GRAVE_ACCENT, CHAR_LEFT_CURLY_BRACKET, CHAR_VERTICAL_LINE, CHAR_RIGHT_CURLY_BRACKET, ESCAPE_SEQUENCES, DEPRECATED_BOOLEANS_SYNTAX, DEPRECATED_BASE60_SYNTAX, QUOTING_TYPE_SINGLE, QUOTING_TYPE_DOUBLE, STYLE_PLAIN, STYLE_SINGLE, STYLE_LITERAL, STYLE_FOLDED, STYLE_DOUBLE, dumper, load;
111239
+ var common, exception, snippet, TYPE_CONSTRUCTOR_OPTIONS, YAML_NODE_KINDS, type$2, schema, str$3, seq, map, failsafe, _null, bool, int, YAML_FLOAT_PATTERN, SCIENTIFIC_WITHOUT_DOT, float, json, core, YAML_DATE_REGEXP, YAML_TIMESTAMP_REGEXP, timestamp$1, merge, BASE64_MAP, binary, _hasOwnProperty$3, _toString$2, omap, _toString$1, pairs, _hasOwnProperty$2, set$1, _default, _hasOwnProperty$1, CONTEXT_FLOW_IN, CONTEXT_FLOW_OUT, CONTEXT_BLOCK_IN, CONTEXT_BLOCK_OUT, CHOMPING_CLIP, CHOMPING_STRIP, CHOMPING_KEEP, PATTERN_NON_PRINTABLE, PATTERN_NON_ASCII_LINE_BREAKS, PATTERN_FLOW_INDICATORS, PATTERN_TAG_HANDLE, PATTERN_TAG_URI, simpleEscapeCheck, simpleEscapeMap, i$1, directiveHandlers, loader, _toString, _hasOwnProperty, CHAR_BOM, CHAR_TAB, CHAR_LINE_FEED, CHAR_CARRIAGE_RETURN, CHAR_SPACE, CHAR_EXCLAMATION, CHAR_DOUBLE_QUOTE, CHAR_SHARP, CHAR_PERCENT, CHAR_AMPERSAND, CHAR_SINGLE_QUOTE, CHAR_ASTERISK, CHAR_COMMA, CHAR_MINUS, CHAR_COLON, CHAR_EQUALS, CHAR_GREATER_THAN, CHAR_QUESTION, CHAR_COMMERCIAL_AT, CHAR_LEFT_SQUARE_BRACKET, CHAR_RIGHT_SQUARE_BRACKET, CHAR_GRAVE_ACCENT, CHAR_LEFT_CURLY_BRACKET, CHAR_VERTICAL_LINE, CHAR_RIGHT_CURLY_BRACKET, ESCAPE_SEQUENCES, DEPRECATED_BOOLEANS_SYNTAX, DEPRECATED_BASE60_SYNTAX, QUOTING_TYPE_SINGLE, QUOTING_TYPE_DOUBLE, STYLE_PLAIN, STYLE_SINGLE, STYLE_LITERAL, STYLE_FOLDED, STYLE_DOUBLE, dumper, load;
111226
111240
  var init_js_yaml = __esmMin((() => {
111227
111241
  common = {
111228
111242
  isNothing,
@@ -111330,7 +111344,7 @@ var init_js_yaml = __esmMin((() => {
111330
111344
  },
111331
111345
  defaultStyle: "lowercase"
111332
111346
  });
111333
- bool$1 = new type$2("tag:yaml.org,2002:bool", {
111347
+ bool = new type$2("tag:yaml.org,2002:bool", {
111334
111348
  kind: "scalar",
111335
111349
  resolve: resolveYamlBoolean,
111336
111350
  construct: constructYamlBoolean,
@@ -111387,7 +111401,7 @@ var init_js_yaml = __esmMin((() => {
111387
111401
  });
111388
111402
  json = failsafe.extend({ implicit: [
111389
111403
  _null,
111390
- bool$1,
111404
+ bool,
111391
111405
  int,
111392
111406
  float
111393
111407
  ] });
@@ -125575,17 +125589,18 @@ var init_update_config = __esmMin((() => {
125575
125589
  };
125576
125590
  }));
125577
125591
  // ../../packages/agent-core-v2/src/features/wave/wave.ts
125578
- var WAVE_FLAG_ID$1, WAVE_FLAG_ENV, WAVE_SEAT_PROFILE, WAVE_TOOL_DOMAIN;
125592
+ var WAVE_FLAG_ID, WAVE_FLAG_ENV, WAVE_SEAT_PROFILE, WAVE_DIRECTOR_PROFILE, WAVE_TOOL_DOMAIN;
125579
125593
  var init_wave$3 = __esmMin((() => {
125580
- WAVE_FLAG_ID$1 = "wave";
125594
+ WAVE_FLAG_ID = "wave";
125581
125595
  WAVE_FLAG_ENV = "NEXGEN_EXPERIMENTAL_WAVE";
125582
125596
  WAVE_SEAT_PROFILE = "wave-seat";
125597
+ WAVE_DIRECTOR_PROFILE = "agent";
125583
125598
  WAVE_TOOL_DOMAIN = "wave";
125584
125599
  }));
125585
125600
  // ../../packages/agent-core-v2/src/features/skill/catalog/builtin/wave.md?raw
125586
125601
  var wave_default;
125587
125602
  var init_wave$2 = __esmMin((() => {
125588
- wave_default = "---\nname: wave\ndescription: Run one design wave end to end — brief, three isolated proposals, defences and attacks, three judges with distinct biases, refinement with mandatory patches, the package gate, and task-by-task execution. Use when the user wants a backlog built and executed with adversarial review instead of a single agent's opinion.\ndisableModelInvocation: true\n---\n\n# Wave (diseño adversarial → backlog verificable)\n\nUna oleada convierte un brief en un backlog que se puede ejecutar y auditar. El valor no está en la prosa: está en que cada paso deja un artefacto con esquema y en que el gate puede salir en rojo.\n\n## Qué hace falta antes de empezar\n\n- `workflow.config.json` en la raíz (layout, umbrales, vocabulario, quórum, roles).\n- Un brief real: **siete secciones**, alcance con claves contables, evidencia disponible y rúbrica.\n\nSi falta el config, no hay oleada: pide al usuario que lo cree desde la plantilla. Si el brief tiene menos de siete secciones, `WaveRound` se niega a planificar — no lo rodees escribiendo el brief tú.\n\n## El ciclo\n\n1. `WaveOpen({ name })` crea `design/waves/W<n>-<slug>/` con el esqueleto del brief y declara la oleada en el config.\n2. Rellena el brief. Las preguntas de diseño van ahí, no en el prompt de un asiento.\n3. `WaveRound({ wave, round: \"propose\" })` devuelve el prompt de P1..Pn. **Lanza un agente por asiento** con `Agent` (o `AgentSwarm` si el usuario activó swarm), pasando el prompt tal cual. Cada asiento entrega con `WaveSubmit`.\n4. `WaveRound({ wave, round: \"defend\" })` y `round: \"attack\"` en la misma tanda.\n5. `WaveRound({ wave, round: \"judge\" })`. Cada juez devuelve su tabla y su total por propuesta.\n6. `WaveDecide({ wave, verdicts })` con los totales de los jueces: `adopt`, `refine` o `deadlock`. Sin `adopt`, lanza `refine` (R1) y después `audit` (R2).\n7. Aplica los parches de R2 y recompón el backlog (`consolidate` → `backlog`) por script, nunca a mano.\n8. `WaveGate({ wave })`: si sale en rojo, la oleada no está cerrada, por mucho que la prosa diga que sí.\n9. Ejecución: una task por vez; antes de cerrarla, `WaveVerify({ task })` con su `verify` y su mutante.\n\n## Reglas que no se negocian\n\n- **Un asiento, un artefacto.** `WaveSubmit` ata rol y ruta: un asiento no puede escribir el artefacto de otro ni tocar el backlog.\n- **Aislamiento en la ronda 1.** Un proponente no ve las propuestas de los otros. Si se ven, no son tres propuestas: es una con tres firmas.\n- **Los ataques no puntúan.** Un adversario que dice cuál es mejor está gastando su asiento; su producto son hallazgos con id y una mutación que los demuestra.\n- **Ningún hallazgo entra como párrafo.** Entra como override, task nueva o retirada, aplicado por script. Un defecto que acaba en el acta y no en el backlog no está corregido: está decorado.\n- **Quórum por mediana y por juez.** Un empate en la mediana no corona a nadie. Dos rondas sin quórum se cierran adoptando R1 **con disidencia escrita**, nunca presentándolo como unánime.\n\n## Qué no decir a un asiento\n\nNo le cuentes qué dicen las otras propuestas, no le pidas consenso, no le des el número de hallazgos esperado y no le adelantes qué propuesta quieres que gane. Cualquiera de las cuatro convierte el swarm en teatro.\n\n## Cuándo parar\n\n- Brief que depende de evidencia que no existe: declara `UNKNOWN` con dueño, o trocea la oleada. No se rellena con invención plausible.\n- Gate rojo por causa externa: regístralo como bloqueo con nombre y sigue con lo que no depende de ella. Nunca marques en verde lo que no se ejecutó.\n";
125603
+ wave_default = "---\nname: wave\ndescription: Run one design wave end to end as its director — open the wave, contract one agent per seat, then decide, verify and close on the gate. Use when the user enables wave mode and gives an objective for a backlog built with adversarial review instead of a single agent's opinion.\ndisableModelInvocation: true\n---\n\n# Wave (director → asientos → gate)\n\nEl agente principal es el **director**: abre la oleada, contrata asientos y comprueba resultados. **No escribe artefactos.** Cada artefacto lo entrega un asiento `wave-seat` con `WaveSubmit`, que es la única tool que hereda el rol, la ruta y el ticket de su contrato.\n\nUn asiento ve `Read`, `Glob`, `Grep` y `WaveSubmit` — nada más. No tiene gate, ni quórum, ni puede lanzar agentes: si necesita un dato que no tiene, escribe UNKNOWN y lo nombra.\n\n## Qué hace falta antes de empezar\n\n- `workflow.config.json` en la raíz (layout, umbrales, vocabulario, quórum, roles).\n- Un brief real: **siete secciones**, alcance con claves contables, evidencia disponible y rúbrica.\n\nSi falta el config, no hay oleada: pide al usuario que lo cree desde la plantilla. Si el brief tiene menos de siete secciones, `WaveContract` se niega — no lo rodees escribiendo el brief tú.\n\n## El ciclo\n\n1. `WaveOpen({ name })` crea `design/waves/W<n>-<slug>/` con el esqueleto del brief y declara la oleada en el config.\n2. Rellena el brief. Las preguntas de diseño van ahí, no en el prompt de un asiento.\n3. `WaveContract({ wave, round: \"propose\" })` devuelve un contrato por asiento: rol, ruta, ticket y prompt. **Lanza un agente `wave-seat` por contrato** con `Agent` (o `AgentSwarm` si el usuario activó swarm), pasando el prompt tal cual. No lo reescribas: el ticket del prompt es lo que `WaveSubmit` acepta.\n4. `round: \"defend\"` y `round: \"attack\"` en la misma tanda.\n5. `round: \"judge\"`: cada juez devuelve su tabla y su total por propuesta.\n6. `WaveDecide({ wave, verdicts })` con los totales de los jueces: `adopt`, `refine` o `deadlock`. Sin `adopt`, contrata `refine` (R1) y después `audit` (R2).\n7. Aplica los parches de R2 y recompón el backlog (`consolidate` → `backlog`) por script, nunca a mano.\n8. `WaveGate({ wave })`: si sale en rojo, la oleada no está cerrada, por mucho que la prosa diga que sí.\n9. Ejecución: una task por vez; antes de cerrarla, `WaveVerify({ task })` con su `verify` y su mutante.\n\n`WaveContract({ wave, round, report: true })` lista qué asientos ya entregaron y cuáles faltan, sin emitir tickets: úsalo para decidir si relanzas o cierras.\n\n## Reglas que no se negocian\n\n- **Un asiento, un artefacto, un contrato.** El contrato fija rol y ruta; `WaveSubmit` los exige. Un asiento no escribe el artefacto de otro ni toca el backlog, y el director no escribe ninguno.\n- **Aislamiento en la ronda 1.** Un proponente no ve las propuestas de los otros. Si se ven, no son tres propuestas: es una con tres firmas.\n- **Los ataques no puntúan.** Un adversario que dice cuál es mejor está gastando su asiento; su producto son hallazgos con id y una mutación que los demuestra.\n- **Ningún hallazgo entra como párrafo.** Entra como override, task nueva o retirada, aplicado por script. Un defecto que acaba en el acta y no en el backlog no está corregido: está decorado.\n- **Quórum por mediana y por juez.** Un empate en la mediana no corona a nadie. Dos rondas sin quórum se cierran adoptando R1 **con disidencia escrita**, nunca presentándolo como unánime.\n\n## Qué no decir a un asiento\n\nNo le cuentes qué dicen las otras propuestas, no le pidas consenso, no le des el número de hallazgos esperado y no le adelantes qué propuesta quieres que gane. Cualquiera de las cuatro convierte el swarm en teatro.\n\n## Cuándo parar\n\n- Brief que depende de evidencia que no existe: declara `UNKNOWN` con dueño, o trocea la oleada. No se rellena con invención plausible.\n- Gate rojo por causa externa: regístralo como bloqueo con nombre y sigue con lo que no depende de ella. Nunca marques en verde lo que no se ejecutó.\n";
125589
125604
  }));
125590
125605
  // ../../packages/agent-core-v2/src/features/skill/catalog/builtin/wave.ts
125591
125606
  var PSEUDO_PATH$1, parsed$1, WAVE_SKILL;
@@ -125604,7 +125619,7 @@ var init_wave$1 = __esmMin((() => {
125604
125619
  ...parsed$1,
125605
125620
  path: PSEUDO_PATH$1,
125606
125621
  dir: PSEUDO_PATH$1,
125607
- experimentalFlag: WAVE_FLAG_ID$1,
125622
+ experimentalFlag: WAVE_FLAG_ID,
125608
125623
  metadata: {
125609
125624
  ...parsed$1.metadata,
125610
125625
  type: parsed$1.metadata.type ?? "inline"
@@ -192175,7 +192190,7 @@ var init_host_request_headers = __esmMin((() => {
192175
192190
  }));
192176
192191
  // ../../packages/agent-core-v2/src/human/llm/requester/bases/anthropic/contract.ts
192177
192192
  var CONTEXT_MANAGEMENT_BETA;
192178
- var init_contract$3 = __esmMin((() => {
192193
+ var init_contract$5 = __esmMin((() => {
192179
192194
  CONTEXT_MANAGEMENT_BETA = "context-management-2025-06-27";
192180
192195
  }));
192181
192196
  // ../../packages/agent-core-v2/src/human/llm/syntax-errors.ts
@@ -192598,7 +192613,7 @@ function nexgenkUnsetCompletionTokens(input) {
192598
192613
  var NEXGEN_API_KEY_ENV, NEXGEN_BASE_URL_ENV$1, NEXGEN_DEFAULT_BASE_URL, nexgenkEndpoint$1, nexgenkConnection, nexgenkAcceptedImageMimes, nexgenkResponsesTrait, nexgenkOpenAITrait, nexgenkAnthropicTrait;
192599
192614
  var init_trait = __esmMin((() => {
192600
192615
  init_image_formats();
192601
- init_contract$3();
192616
+ init_contract$5();
192602
192617
  init_schema$3();
192603
192618
  NEXGEN_API_KEY_ENV = "NEXGEN_API_KEY";
192604
192619
  NEXGEN_BASE_URL_ENV$1 = "NEXGEN_BASE_URL";
@@ -196108,7 +196123,7 @@ var init_format$4 = __esmMin((() => {
196108
196123
  init_syntax_errors();
196109
196124
  init_patterns$3();
196110
196125
  init_rewrite();
196111
- init_contract$3();
196126
+ init_contract$5();
196112
196127
  init_lower$3();
196113
196128
  init_patterns$2();
196114
196129
  init_profile();
@@ -219258,6 +219273,90 @@ var init_towerService = __esmMin((() => {
219258
219273
  ], AgentTowerService);
219259
219274
  registerScopedService("agent", IAgentTowerService, AgentTowerService, 0, "tower");
219260
219275
  }));
219276
+ // ../../packages/agent-core-v2/src/features/wave/waveOps.ts
219277
+ var waveModeEnterSchema, WaveModeEnter, waveModeExitSchema, WaveModeExit, waveKey;
219278
+ var init_waveOps = __esmMin((() => {
219279
+ init_zod$1();
219280
+ init_usageEvents();
219281
+ init_event2();
219282
+ init_state$1();
219283
+ waveModeEnterSchema = object$1({ agentId: string() });
219284
+ WaveModeEnter = class extends AgentEvent2 {
219285
+ static type = "wave_mode.enter";
219286
+ static durable = true;
219287
+ static schema = waveModeEnterSchema;
219288
+ };
219289
+ waveModeExitSchema = object$1({ agentId: string() });
219290
+ WaveModeExit = class extends AgentEvent2 {
219291
+ static type = "wave_mode.exit";
219292
+ static durable = true;
219293
+ static schema = waveModeExitSchema;
219294
+ };
219295
+ waveKey = defineState("wave", () => false).replayable({ schema: boolean$1() }).on(WaveModeEnter, (_s, e, ctx) => {
219296
+ ctx.emit(new AgentStatusUpdated({
219297
+ agentId: e.agentId,
219298
+ waveMode: true
219299
+ }));
219300
+ return true;
219301
+ }).on(WaveModeExit, (_s, e, ctx) => {
219302
+ ctx.emit(new AgentStatusUpdated({
219303
+ agentId: e.agentId,
219304
+ waveMode: false
219305
+ }));
219306
+ return false;
219307
+ });
219308
+ }));
219309
+ // ../../packages/agent-core-v2/src/features/wave/agent/waveService.ts
219310
+ var AgentWaveService;
219311
+ var init_waveService = __esmMin((() => {
219312
+ init_lifecycle$2();
219313
+ init_profile$1();
219314
+ init_scopeContext();
219315
+ init_agentState();
219316
+ init_eventBus();
219317
+ init_agentLifecycle();
219318
+ init_eventDispatcher();
219319
+ init_waveOps();
219320
+ init_decorateParam();
219321
+ init_decorate();
219322
+ AgentWaveService = class AgentWaveService extends Disposable {
219323
+ dispatcher;
219324
+ agentCtx;
219325
+ agentState;
219326
+ profile;
219327
+ constructor(dispatcher, agentCtx, agentState, profile, eventBus) {
219328
+ super();
219329
+ this.dispatcher = dispatcher;
219330
+ this.agentCtx = agentCtx;
219331
+ this.agentState = agentState;
219332
+ this.profile = profile;
219333
+ this.agentState.contributeState(waveKey);
219334
+ const republish = () => {
219335
+ if (this.agentCtx.agentId === "main") this.profile.republishStatus();
219336
+ };
219337
+ this._register(eventBus.subscribe(WaveModeEnter, republish));
219338
+ this._register(eventBus.subscribe(WaveModeExit, republish));
219339
+ }
219340
+ async enter() {
219341
+ if (this.agentState.get(waveKey)) return;
219342
+ await this.dispatcher.dispatch(new WaveModeEnter({ agentId: this.agentCtx.agentId }));
219343
+ }
219344
+ async exit() {
219345
+ if (!this.agentState.get(waveKey)) return;
219346
+ await this.dispatcher.dispatch(new WaveModeExit({ agentId: this.agentCtx.agentId }));
219347
+ }
219348
+ get isActive() {
219349
+ return this.agentState.get(waveKey);
219350
+ }
219351
+ };
219352
+ AgentWaveService = __decorate([
219353
+ __decorateParam(0, IEventDispatcher),
219354
+ __decorateParam(1, IAgentScopeContext),
219355
+ __decorateParam(2, IAgentStateService),
219356
+ __decorateParam(3, IAgentProfileService),
219357
+ __decorateParam(4, IEventBus)
219358
+ ], AgentWaveService);
219359
+ }));
219261
219360
  // ../../packages/agent-core-v2/src/features/wave/seatProfile.ts
219262
219361
  var WAVE_SEAT_TOOLS, WAVE_SEAT_ROLE, WAVE_SEAT_PROFILE_DEF;
219263
219362
  var init_seatProfile = __esmMin((() => {
@@ -219279,217 +219378,67 @@ var init_seatProfile = __esmMin((() => {
219279
219378
  renderSystemPrompt: (context) => renderSystemPromptResult(WAVE_SEAT_ROLE, context, { skillActive: skillActiveFor(WAVE_SEAT_TOOLS) })
219280
219379
  });
219281
219380
  }));
219282
- // ../../packages/agent-core-v2/src/features/wave/tools/decide/decide.ts
219283
- var WaveDecideToolInputSchema, IWaveDecideTool;
219284
- var init_decide$1 = __esmMin((() => {
219381
+ // ../../packages/agent-core-v2/src/features/wave/tools/contract/contract.ts
219382
+ var WAVE_CONTRACT_ROUNDS, WaveContractToolInputSchema, IWaveContractTool;
219383
+ var init_contract$4 = __esmMin((() => {
219285
219384
  init_zod$1();
219286
219385
  init_instantiation();
219287
- WaveDecideToolInputSchema = object$1({
219288
- root: string().optional(),
219289
- verdicts: array(object$1({
219290
- judge: string().min(1),
219291
- scores: record$3(string(), number$1())
219292
- }).strict()).min(1),
219293
- minPoints: number$1().optional(),
219294
- minAxes: number$1().optional(),
219295
- round: number$1().optional()
219386
+ WAVE_CONTRACT_ROUNDS = [
219387
+ "propose",
219388
+ "defend",
219389
+ "attack",
219390
+ "judge",
219391
+ "refine",
219392
+ "audit"
219393
+ ];
219394
+ WaveContractToolInputSchema = object$1({
219395
+ wave: string().min(2),
219396
+ round: _enum(WAVE_CONTRACT_ROUNDS),
219397
+ seats: array(object$1({
219398
+ role: string().min(1).optional(),
219399
+ artifact: string().min(1).optional()
219400
+ }).strict()).optional(),
219401
+ report: boolean$1().optional(),
219402
+ root: string().optional()
219296
219403
  }).strict();
219297
- IWaveDecideTool = createDecorator("waveDecideTool");
219404
+ IWaveContractTool = createDecorator("waveContractTool");
219298
219405
  }));
219299
- // ../../packages/agent-core-v2/src/features/wave/core/config.ts
219300
- function record$2(value) {
219301
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
219406
+ // ../../packages/agent-core-v2/src/features/wave/core/fsJson.ts
219407
+ function readJson$2(fs, path) {
219408
+ const text = fs.read(path);
219409
+ if (text === void 0) return void 0;
219410
+ try {
219411
+ return JSON.parse(text);
219412
+ } catch {
219413
+ return;
219414
+ }
219302
219415
  }
219303
- function num(value, fallback) {
219304
- return typeof value === "number" && Number.isFinite(value) ? value : fallback;
219416
+ function isRecord$16(value) {
219417
+ return typeof value === "object" && value !== null && !Array.isArray(value);
219305
219418
  }
219306
- function text(value, fallback) {
219307
- return typeof value === "string" ? value : fallback;
219419
+ function asRecord$2(value) {
219420
+ return isRecord$16(value) ? value : {};
219308
219421
  }
219309
- function bool(value, fallback) {
219310
- return typeof value === "boolean" ? value : fallback;
219422
+ function asArray$2(value) {
219423
+ return Array.isArray(value) ? value : [];
219311
219424
  }
219312
- function strArray$1(value, fallback) {
219313
- return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : fallback;
219425
+ function asText$1(value) {
219426
+ return typeof value === "string" ? value : "";
219314
219427
  }
219315
- function makeWaveConfig(raw, loadedFrom) {
219316
- const base = record$2(raw);
219317
- const layout = record$2(base["layout"]);
219318
- const thresholds = record$2(base["thresholds"]);
219319
- const vocabulary = record$2(base["vocabulary"]);
219320
- const roles = record$2(base["roles"]);
219321
- const quorum = record$2(base["quorum"]);
219322
- return {
219323
- layout: {
219324
- waves: text(layout["waves"], DEFAULT_LAYOUT.waves),
219325
- backlog: text(layout["backlog"], DEFAULT_LAYOUT.backlog),
219326
- adr: text(layout["adr"], DEFAULT_LAYOUT.adr),
219327
- inventory: text(layout["inventory"], DEFAULT_LAYOUT.inventory)
219328
- },
219329
- waves: strArray$1(base["waves"], ["W0"]),
219330
- thresholds: {
219331
- minEpics: num(thresholds["minEpics"], DEFAULT_THRESHOLDS.minEpics),
219332
- minTasks: num(thresholds["minTasks"], DEFAULT_THRESHOLDS.minTasks),
219333
- minAcPerTask: num(thresholds["minAcPerTask"], DEFAULT_THRESHOLDS.minAcPerTask),
219334
- minDecisionBytes: num(thresholds["minDecisionBytes"], DEFAULT_THRESHOLDS.minDecisionBytes),
219335
- minArtifactBytes: num(thresholds["minArtifactBytes"], DEFAULT_THRESHOLDS.minArtifactBytes),
219336
- minBriefSections: num(thresholds["minBriefSections"], DEFAULT_THRESHOLDS.minBriefSections),
219337
- minContextBytes: num(thresholds["minContextBytes"], DEFAULT_THRESHOLDS.minContextBytes),
219338
- minGoalChars: num(thresholds["minGoalChars"], DEFAULT_THRESHOLDS.minGoalChars),
219339
- minScopeChars: num(thresholds["minScopeChars"], DEFAULT_THRESHOLDS.minScopeChars),
219340
- minFieldChars: num(thresholds["minFieldChars"], DEFAULT_THRESHOLDS.minFieldChars),
219341
- minMetricChars: num(thresholds["minMetricChars"], DEFAULT_THRESHOLDS.minMetricChars),
219342
- allowVerifyTargetMissing: bool(thresholds["allowVerifyTargetMissing"], DEFAULT_THRESHOLDS.allowVerifyTargetMissing)
219343
- },
219344
- vocabulary: {
219345
- areas: strArray$1(vocabulary["areas"], DEFAULT_VOCABULARY.areas),
219346
- requiredAreas: strArray$1(vocabulary["requiredAreas"], DEFAULT_VOCABULARY.requiredAreas),
219347
- types: strArray$1(vocabulary["types"], DEFAULT_VOCABULARY.types),
219348
- estimates: strArray$1(vocabulary["estimates"], DEFAULT_VOCABULARY.estimates),
219349
- vagueWords: strArray$1(vocabulary["vagueWords"], DEFAULT_VOCABULARY.vagueWords),
219350
- verifyCommands: strArray$1(vocabulary["verifyCommands"], DEFAULT_VOCABULARY.verifyCommands),
219351
- verifyPrefixes: strArray$1(vocabulary["verifyPrefixes"], DEFAULT_VOCABULARY.verifyPrefixes)
219352
- },
219353
- secrets: strArray$1(base["secrets"], []),
219354
- roles: {
219355
- proponents: num(roles["proponents"], DEFAULT_ROLES.proponents),
219356
- defenders: num(roles["defenders"], DEFAULT_ROLES.defenders),
219357
- adversaries: num(roles["adversaries"], DEFAULT_ROLES.adversaries),
219358
- judges: num(roles["judges"], DEFAULT_ROLES.judges),
219359
- refiners: num(roles["refiners"], DEFAULT_ROLES.refiners)
219360
- },
219361
- quorum: {
219362
- minPoints: num(quorum["minPoints"], DEFAULT_QUORUM.minPoints),
219363
- minAxes: num(quorum["minAxes"], DEFAULT_QUORUM.minAxes),
219364
- axes: strArray$1(quorum["axes"], DEFAULT_QUORUM.axes)
219365
- },
219366
- loadedFrom,
219367
- missingKeys: CONFIG_REQUIRED_KEYS.filter((key) => base[key] === void 0)
219368
- };
219428
+ function writeJson(_fs, path, value) {
219429
+ mkdirSync(dirname(path), { recursive: true });
219430
+ writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
219369
219431
  }
219370
- function readWaveConfig(fs, root) {
219371
- const file = resolve(root, "workflow.config.json");
219372
- const raw = fs.read(file);
219373
- if (raw === void 0) return void 0;
219374
- try {
219375
- return makeWaveConfig(JSON.parse(raw), file);
219376
- } catch {
219377
- return;
219432
+ function walk$1(fs, dir, accept, acc = []) {
219433
+ if (!fs.isDirectory(dir)) return acc;
219434
+ for (const name of fs.list(dir)) {
219435
+ const full = join(dir, name);
219436
+ if (fs.isDirectory(full)) walk$1(fs, full, accept, acc);
219437
+ else if (accept(full)) acc.push(full);
219378
219438
  }
219439
+ return acc;
219379
219440
  }
219380
- function containedPath(root, candidate) {
219381
- const resolvedRoot = resolve(root);
219382
- const resolved = isAbsolute(candidate) ? resolve(candidate) : resolve(resolvedRoot, candidate);
219383
- if (resolved !== resolvedRoot && !resolved.startsWith(`${resolvedRoot}${sep}`)) throw new Error(`ruta fuera del workspace: ${candidate}`);
219384
- return resolved;
219385
- }
219386
- var DEFAULT_LAYOUT, DEFAULT_THRESHOLDS, DEFAULT_VOCABULARY, DEFAULT_ROLES, DEFAULT_QUORUM, CONFIG_REQUIRED_KEYS;
219387
- var init_config$6 = __esmMin((() => {
219388
- DEFAULT_LAYOUT = {
219389
- waves: "design/waves",
219390
- backlog: "backlog",
219391
- adr: "design/ADR",
219392
- inventory: "inventory"
219393
- };
219394
- DEFAULT_THRESHOLDS = {
219395
- minEpics: 1,
219396
- minTasks: 1,
219397
- minAcPerTask: 2,
219398
- minDecisionBytes: 200,
219399
- minArtifactBytes: 100,
219400
- minBriefSections: 7,
219401
- minContextBytes: 80,
219402
- minGoalChars: 40,
219403
- minScopeChars: 40,
219404
- minFieldChars: 10,
219405
- minMetricChars: 4,
219406
- allowVerifyTargetMissing: false
219407
- };
219408
- DEFAULT_VOCABULARY = {
219409
- areas: [
219410
- "cliente",
219411
- "seller",
219412
- "agent",
219413
- "admin",
219414
- "plataforma"
219415
- ],
219416
- requiredAreas: [],
219417
- types: [
219418
- "db",
219419
- "api",
219420
- "ui",
219421
- "domain",
219422
- "infra",
219423
- "test",
219424
- "docs",
219425
- "app",
219426
- "contract",
219427
- "ops",
219428
- "tooling"
219429
- ],
219430
- estimates: [
219431
- "XS",
219432
- "S",
219433
- "M",
219434
- "L",
219435
- "XL"
219436
- ],
219437
- vagueWords: [
219438
- "funciona",
219439
- "correcto",
219440
- "adecuado",
219441
- "rapido",
219442
- "robusto",
219443
- "bonito"
219444
- ],
219445
- verifyCommands: [
219446
- "pnpm",
219447
- "npm",
219448
- "node",
219449
- "bash",
219450
- "sh",
219451
- "make",
219452
- "python",
219453
- "go",
219454
- "cargo",
219455
- "dotnet"
219456
- ],
219457
- verifyPrefixes: [
219458
- "test/unit/",
219459
- "test/db/",
219460
- "test/domain/",
219461
- "test/api/",
219462
- "test/perf/",
219463
- "e2e/",
219464
- "scripts/checks/"
219465
- ]
219466
- };
219467
- DEFAULT_ROLES = {
219468
- proponents: 3,
219469
- defenders: 3,
219470
- adversaries: 3,
219471
- judges: 3,
219472
- refiners: 2
219473
- };
219474
- DEFAULT_QUORUM = {
219475
- minPoints: 1,
219476
- minAxes: 2,
219477
- axes: [
219478
- "cobertura",
219479
- "falsabilidad",
219480
- "riesgo",
219481
- "coste",
219482
- "encaje"
219483
- ]
219484
- };
219485
- CONFIG_REQUIRED_KEYS = [
219486
- "version",
219487
- "layout",
219488
- "waves",
219489
- "thresholds",
219490
- "vocabulary"
219491
- ];
219492
- }));
219441
+ var init_fsJson = __esmMin((() => {}));
219493
219442
  // ../../packages/agent-core-v2/src/features/wave/core/nodeFs.ts
219494
219443
  var nodeWaveFs;
219495
219444
  var init_nodeFs = __esmMin((() => {
@@ -219531,6 +219480,470 @@ var init_nodeFs = __esmMin((() => {
219531
219480
  }
219532
219481
  };
219533
219482
  }));
219483
+ // ../../packages/agent-core-v2/src/features/wave/core/config.ts
219484
+ function seats(prefix, count) {
219485
+ return Array.from({ length: Math.max(0, count) }, (_, index) => `${prefix}${index + 1}`);
219486
+ }
219487
+ function waveRoundSeats(roles, round) {
219488
+ if (round === "propose") return seats("P", roles.proponents);
219489
+ if (round === "defend") return seats("D", roles.defenders);
219490
+ if (round === "attack") return seats("A", roles.adversaries);
219491
+ if (round === "judge") return seats("J", roles.judges);
219492
+ const refiners = seats("R", roles.refiners);
219493
+ return round === "refine" ? refiners.slice(0, 1) : refiners.slice(1);
219494
+ }
219495
+ function waveConfigState(config) {
219496
+ const state = config;
219497
+ return {
219498
+ ...config,
219499
+ version: state.version ?? 1,
219500
+ wavesOpen: state.wavesOpen ?? [],
219501
+ raw: state.raw ?? {}
219502
+ };
219503
+ }
219504
+ function record$2(value) {
219505
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
219506
+ }
219507
+ function num(value, fallback) {
219508
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
219509
+ }
219510
+ function text(value, fallback) {
219511
+ return typeof value === "string" ? value : fallback;
219512
+ }
219513
+ function strArray$1(value, fallback) {
219514
+ return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : fallback;
219515
+ }
219516
+ function makeWaveConfig(raw, loadedFrom) {
219517
+ const base = record$2(raw);
219518
+ const layout = record$2(base["layout"]);
219519
+ const thresholds = record$2(base["thresholds"]);
219520
+ const vocabulary = record$2(base["vocabulary"]);
219521
+ const roles = record$2(base["roles"]);
219522
+ const quorum = record$2(base["quorum"]);
219523
+ return {
219524
+ version: num(base["version"], 1),
219525
+ wavesOpen: strArray$1(base["wavesOpen"], []),
219526
+ raw: base,
219527
+ layout: {
219528
+ waves: text(layout["waves"], DEFAULT_LAYOUT.waves),
219529
+ backlog: text(layout["backlog"], DEFAULT_LAYOUT.backlog),
219530
+ adr: text(layout["adr"], DEFAULT_LAYOUT.adr),
219531
+ inventory: text(layout["inventory"], DEFAULT_LAYOUT.inventory)
219532
+ },
219533
+ waves: strArray$1(base["waves"], ["W0"]),
219534
+ thresholds: {
219535
+ minEpics: num(thresholds["minEpics"], DEFAULT_THRESHOLDS.minEpics),
219536
+ minTasks: num(thresholds["minTasks"], DEFAULT_THRESHOLDS.minTasks),
219537
+ minAcPerTask: num(thresholds["minAcPerTask"], DEFAULT_THRESHOLDS.minAcPerTask),
219538
+ minDecisionBytes: num(thresholds["minDecisionBytes"], DEFAULT_THRESHOLDS.minDecisionBytes),
219539
+ minArtifactBytes: num(thresholds["minArtifactBytes"], DEFAULT_THRESHOLDS.minArtifactBytes),
219540
+ minBriefSections: num(thresholds["minBriefSections"], DEFAULT_THRESHOLDS.minBriefSections),
219541
+ minContextBytes: num(thresholds["minContextBytes"], DEFAULT_THRESHOLDS.minContextBytes),
219542
+ minGoalChars: num(thresholds["minGoalChars"], DEFAULT_THRESHOLDS.minGoalChars),
219543
+ minScopeChars: num(thresholds["minScopeChars"], DEFAULT_THRESHOLDS.minScopeChars),
219544
+ minFieldChars: num(thresholds["minFieldChars"], DEFAULT_THRESHOLDS.minFieldChars),
219545
+ minMetricChars: num(thresholds["minMetricChars"], DEFAULT_THRESHOLDS.minMetricChars)
219546
+ },
219547
+ vocabulary: {
219548
+ areas: strArray$1(vocabulary["areas"], DEFAULT_VOCABULARY.areas),
219549
+ requiredAreas: strArray$1(vocabulary["requiredAreas"], DEFAULT_VOCABULARY.requiredAreas),
219550
+ types: strArray$1(vocabulary["types"], DEFAULT_VOCABULARY.types),
219551
+ estimates: strArray$1(vocabulary["estimates"], DEFAULT_VOCABULARY.estimates),
219552
+ vagueWords: strArray$1(vocabulary["vagueWords"], DEFAULT_VOCABULARY.vagueWords),
219553
+ verifyCommands: strArray$1(vocabulary["verifyCommands"], DEFAULT_VOCABULARY.verifyCommands),
219554
+ verifyPrefixes: strArray$1(vocabulary["verifyPrefixes"], DEFAULT_VOCABULARY.verifyPrefixes)
219555
+ },
219556
+ secrets: strArray$1(base["secrets"], []),
219557
+ roles: {
219558
+ proponents: num(roles["proponents"], DEFAULT_ROLES.proponents),
219559
+ defenders: num(roles["defenders"], DEFAULT_ROLES.defenders),
219560
+ adversaries: num(roles["adversaries"], DEFAULT_ROLES.adversaries),
219561
+ judges: num(roles["judges"], DEFAULT_ROLES.judges),
219562
+ refiners: num(roles["refiners"], DEFAULT_ROLES.refiners)
219563
+ },
219564
+ quorum: {
219565
+ minPoints: num(quorum["minPoints"], DEFAULT_QUORUM.minPoints),
219566
+ minAxes: num(quorum["minAxes"], DEFAULT_QUORUM.minAxes),
219567
+ axes: strArray$1(quorum["axes"], DEFAULT_QUORUM.axes)
219568
+ },
219569
+ loadedFrom
219570
+ };
219571
+ }
219572
+ function readWaveConfig(fs, root) {
219573
+ const file = resolve(root, "workflow.config.json");
219574
+ const raw = fs.read(file);
219575
+ if (raw === void 0) return void 0;
219576
+ try {
219577
+ return makeWaveConfig(JSON.parse(raw), file);
219578
+ } catch {
219579
+ return;
219580
+ }
219581
+ }
219582
+ function containedPath(root, candidate) {
219583
+ const resolvedRoot = resolve(root);
219584
+ const resolved = isAbsolute(candidate) ? resolve(candidate) : resolve(resolvedRoot, candidate);
219585
+ if (resolved !== resolvedRoot && !resolved.startsWith(`${resolvedRoot}${sep}`)) throw new Error(`ruta fuera del workspace: ${candidate}`);
219586
+ return resolved;
219587
+ }
219588
+ var WAVE_ROUNDS, WAVE_ROUND_DIRS, DEFAULT_LAYOUT, DEFAULT_THRESHOLDS, DEFAULT_VOCABULARY, DEFAULT_ROLES, DEFAULT_QUORUM;
219589
+ var init_config$6 = __esmMin((() => {
219590
+ WAVE_ROUNDS = [
219591
+ "propose",
219592
+ "defend",
219593
+ "attack",
219594
+ "judge",
219595
+ "refine",
219596
+ "audit"
219597
+ ];
219598
+ WAVE_ROUND_DIRS = {
219599
+ propose: "01-proposals",
219600
+ defend: "02-defenses",
219601
+ attack: "03-attacks",
219602
+ judge: "04-verdicts",
219603
+ refine: "05-refined",
219604
+ audit: "05-refined"
219605
+ };
219606
+ DEFAULT_LAYOUT = {
219607
+ waves: "design/waves",
219608
+ backlog: "backlog",
219609
+ adr: "design/ADR",
219610
+ inventory: "inventory"
219611
+ };
219612
+ DEFAULT_THRESHOLDS = {
219613
+ minEpics: 1,
219614
+ minTasks: 1,
219615
+ minAcPerTask: 2,
219616
+ minDecisionBytes: 200,
219617
+ minArtifactBytes: 100,
219618
+ minBriefSections: 7,
219619
+ minContextBytes: 80,
219620
+ minGoalChars: 40,
219621
+ minScopeChars: 40,
219622
+ minFieldChars: 10,
219623
+ minMetricChars: 4
219624
+ };
219625
+ DEFAULT_VOCABULARY = {
219626
+ areas: [
219627
+ "cliente",
219628
+ "seller",
219629
+ "agent",
219630
+ "admin",
219631
+ "plataforma"
219632
+ ],
219633
+ requiredAreas: [],
219634
+ types: [
219635
+ "db",
219636
+ "api",
219637
+ "ui",
219638
+ "domain",
219639
+ "infra",
219640
+ "test",
219641
+ "docs",
219642
+ "app",
219643
+ "contract",
219644
+ "ops",
219645
+ "tooling"
219646
+ ],
219647
+ estimates: [
219648
+ "XS",
219649
+ "S",
219650
+ "M",
219651
+ "L",
219652
+ "XL"
219653
+ ],
219654
+ vagueWords: [
219655
+ "funciona",
219656
+ "correcto",
219657
+ "adecuado",
219658
+ "rapido",
219659
+ "robusto",
219660
+ "bonito"
219661
+ ],
219662
+ verifyCommands: [
219663
+ "pnpm",
219664
+ "npm",
219665
+ "node",
219666
+ "bash",
219667
+ "sh",
219668
+ "make",
219669
+ "python",
219670
+ "go",
219671
+ "cargo",
219672
+ "dotnet"
219673
+ ],
219674
+ verifyPrefixes: [
219675
+ "test/unit/",
219676
+ "test/db/",
219677
+ "test/domain/",
219678
+ "test/api/",
219679
+ "test/perf/",
219680
+ "e2e/",
219681
+ "scripts/checks/"
219682
+ ]
219683
+ };
219684
+ DEFAULT_ROLES = {
219685
+ proponents: 3,
219686
+ defenders: 3,
219687
+ adversaries: 3,
219688
+ judges: 3,
219689
+ refiners: 2
219690
+ };
219691
+ DEFAULT_QUORUM = {
219692
+ minPoints: 1,
219693
+ minAxes: 2,
219694
+ axes: [
219695
+ "cobertura",
219696
+ "falsabilidad",
219697
+ "riesgo",
219698
+ "coste",
219699
+ "encaje"
219700
+ ]
219701
+ };
219702
+ }));
219703
+ // ../../packages/agent-core-v2/src/features/wave/core/seats.ts
219704
+ function contractedSeats(fs, registryFile) {
219705
+ const raw = fs.read(registryFile);
219706
+ if (raw === void 0) return void 0;
219707
+ try {
219708
+ return (JSON.parse(raw).seats ?? []).filter((seat) => typeof seat["round"] === "string" && typeof seat["role"] === "string").map((seat) => ({
219709
+ round: String(seat["round"]),
219710
+ role: String(seat["role"])
219711
+ }));
219712
+ } catch {
219713
+ return;
219714
+ }
219715
+ }
219716
+ function seatTicketHash(ticket) {
219717
+ return createHash("sha256").update(ticket).digest("hex");
219718
+ }
219719
+ function waveBase(input) {
219720
+ const fs = nodeWaveFs;
219721
+ const rawConfig = readJson$2(fs, join(input.root, "workflow.config.json"));
219722
+ if (rawConfig === void 0) return { error: `no hay workflow.config.json en ${input.root}` };
219723
+ const wavesRel = makeWaveConfig(rawConfig).layout.waves;
219724
+ let wavesDir;
219725
+ try {
219726
+ wavesDir = containedPath(input.root, wavesRel);
219727
+ } catch (error) {
219728
+ return { error: error instanceof Error ? error.message : String(error) };
219729
+ }
219730
+ const name = fs.list(wavesDir).filter((entry) => fs.isDirectory(join(wavesDir, entry))).find((entry) => entry === input.wave || entry.startsWith(`${input.wave}-`));
219731
+ if (name === void 0) return { error: `no existe la oleada ${input.wave} en ${wavesRel}` };
219732
+ return {
219733
+ base: join(wavesDir, name),
219734
+ wavesRel
219735
+ };
219736
+ }
219737
+ function runWaveContract(input) {
219738
+ const fs = nodeWaveFs;
219739
+ const rawConfig = readJson$2(fs, join(input.root, "workflow.config.json"));
219740
+ if (rawConfig === void 0) return {
219741
+ output: `no hay workflow.config.json en ${input.root}`,
219742
+ seats: [],
219743
+ isError: true
219744
+ };
219745
+ const located = waveBase(input);
219746
+ if (located.base === void 0) return {
219747
+ output: located.error ?? "oleada no encontrada",
219748
+ seats: [],
219749
+ isError: true
219750
+ };
219751
+ const base = located.base;
219752
+ const roundDir = WAVE_ROUND_DIRS[input.round];
219753
+ const roles = waveRoundSeats(makeWaveConfig(rawConfig).roles, input.round);
219754
+ if (input.report === true) {
219755
+ const delivered = roles.filter((role) => fs.exists(join(base, roundDir, `${role}.md`)));
219756
+ const missing = roles.filter((role) => !delivered.includes(role));
219757
+ return {
219758
+ output: [
219759
+ `CONTRATOS ${input.round} de ${input.wave}: ${delivered.length}/${roles.length} entregados`,
219760
+ ...roles.map((role) => `${delivered.includes(role) ? "ok " : "FIJA"} ${role} ${roundDir}/${role}.md`),
219761
+ ...missing.length === 0 ? [] : ["", `faltan: ${missing.join(", ")}`]
219762
+ ].join("\n"),
219763
+ seats: [],
219764
+ isError: missing.length > 0
219765
+ };
219766
+ }
219767
+ const declared = input.seats ?? [];
219768
+ for (const seat of declared) {
219769
+ if (seat.role !== void 0 && !roles.includes(seat.role)) return {
219770
+ output: `rol desconocido "${seat.role}" para la ronda ${input.round}: ${roles.join(", ")}`,
219771
+ seats: [],
219772
+ isError: true
219773
+ };
219774
+ if (seat.artifact !== void 0 && !seat.artifact.startsWith(`${roundDir}/`)) return {
219775
+ output: `el artefacto "${seat.artifact}" queda fuera de ${roundDir}/`,
219776
+ seats: [],
219777
+ isError: true
219778
+ };
219779
+ }
219780
+ const requested = declared.length === 0 ? roles.map((role) => ({ role })) : declared;
219781
+ const resolved = [];
219782
+ for (const [index, seat] of requested.entries()) {
219783
+ const role = seat.role ?? roles[index];
219784
+ if (role === void 0) return {
219785
+ output: "se contrataron más asientos que roles tiene la ronda",
219786
+ seats: [],
219787
+ isError: true
219788
+ };
219789
+ resolved.push({
219790
+ role,
219791
+ file: seat.artifact ?? `${roundDir}/${role}.md`
219792
+ });
219793
+ }
219794
+ const seatsDir = join(base, WAVE_SEATS_DIR);
219795
+ const entries = asArray$2(asRecord$2(readJson$2(fs, join(seatsDir, "seats.json")) ?? {})["seats"]).map(asRecord$2).filter((entry) => !resolved.some((seat) => entry["round"] === input.round && entry["role"] === seat.role));
219796
+ const contracts = [];
219797
+ for (const seat of resolved) {
219798
+ const ticket = randomBytes(16).toString("hex");
219799
+ fs.write(join(seatsDir, seat.role), `${seatTicketHash(ticket)}\n`);
219800
+ entries.push({
219801
+ role: seat.role,
219802
+ round: input.round,
219803
+ file: seat.file,
219804
+ ticket: seatTicketHash(ticket)
219805
+ });
219806
+ contracts.push({
219807
+ ...seat,
219808
+ ticket,
219809
+ prompt: input.buildPrompt({
219810
+ wave: input.wave,
219811
+ round: input.round,
219812
+ ...seat,
219813
+ ticket
219814
+ })
219815
+ });
219816
+ }
219817
+ writeJson(fs, join(seatsDir, "seats.json"), { seats: entries });
219818
+ return {
219819
+ output: [`CONTRATOS ${input.round} de ${input.wave}: ${contracts.length} asiento(s)`, ...contracts.map((contract) => `\n=== ${contract.role} -> ${contract.file}\n${contract.prompt}`)].join("\n"),
219820
+ seats: contracts
219821
+ };
219822
+ }
219823
+ var WAVE_SEATS_DIR, WAVE_CONTRACTS_FILE;
219824
+ var init_seats = __esmMin((() => {
219825
+ init_config$6();
219826
+ init_fsJson();
219827
+ init_nodeFs();
219828
+ WAVE_SEATS_DIR = ".seats";
219829
+ WAVE_CONTRACTS_FILE = `${WAVE_SEATS_DIR}/seats.json`;
219830
+ }));
219831
+ // ../../packages/agent-core-v2/src/features/wave/tools/round/prompts.ts
219832
+ var SEAT_PRELUDE, ROLE_PROMPTS, JUDGE_BIASES;
219833
+ var init_prompts$2 = __esmMin((() => {
219834
+ SEAT_PRELUDE = [
219835
+ "Trabajas en una oleada de diseno con aislamiento de escritura.",
219836
+ "",
219837
+ "Reglas que no dependen de tu rol:",
219838
+ "- Escribe UN SOLO artefacto, entregado con WaveSubmit. No toques ningun otro fichero.",
219839
+ "- No modifiques el backlog, el codigo ni los artefactos de otros roles.",
219840
+ "- Todo lo que afirmes debe apoyarse en evidencia citables (ruta de fichero, dato del brief). Si no la tienes, escribe UNKNOWN con lo que falta. No lo rellenes con una invencion plausible.",
219841
+ "- Cada criterio de aceptacion que escribas debe poder fallar. Si no puedes describir el rojo esperado, el criterio no sirve."
219842
+ ].join("\n");
219843
+ ROLE_PROMPTS = {
219844
+ propose: "Rol: proponente. Resuelve el brief de la forma mas simple que cubra el alcance completo, y demuestra que cubre. No propongas alternativas: elige una y defiendela. Incluye alcance con claves exactas, mecanismo concreto, tabla de epics y tasks, tres criterios de aceptacion completos con falsificador, coste y seccion UNKNOWN. No leas las propuestas de los otros proponentes: no existen todavia.",
219845
+ defend: "Rol: defensor de la propuesta que te asignan. Sostienla frente a las otras dos con evidencia y declara sus tres puntos mas fragiles antes de que los encuentre un adversario. Prohibido introducir mecanismos nuevos: si lo haces, estas proponiendo, no defendiendo.",
219846
+ attack: "Rol: adversario. No puntuas, no eliges favorita, no propones una cuarta propuesta. Caza, por este orden: criterios que no pueden fallar, huecos sin dueno, contradicciones internas, estados imposibles y seguridad. Cada hallazgo lleva id, propuesta afectada, seccion, la mutacion que lo demuestra y gravedad (bloqueante/alta/media/baja). Un hallazgo sin demostracion es una opinion.",
219847
+ judge: "Rol: juez. Puntua de 0 a 5 cada propuesta en los cinco ejes del brief y declara una preferencia con su margen. No redisenes. Penaliza sin piedad la falsabilidad: un criterio que no puede fallar resta, aunque el diseno sea bonito.",
219848
+ refine: "Rol: refinador integrador. Compone, no elige: toma el mejor mecanismo de cada propuesta y cierra los hallazgos del adversario. Tabla hallazgo -> cerrado/mitigado/abierto con disparador, criterios reescritos con su nuevo rojo esperado, coste resultante y deuda aceptada.",
219849
+ audit: "Rol: refinador adversarial, segunda pasada sin cortesia. Audita el refinamiento, caza criterios que no muerden, contrasta las cifras declaradas contra las reales, re-puntua con la misma rubrica y emite los parches obligatorios que falten. Si un parche es necesario y no lo emites, se pierde."
219850
+ };
219851
+ JUDGE_BIASES = [
219852
+ "coste",
219853
+ "falsabilidad",
219854
+ "encaje"
219855
+ ];
219856
+ }));
219857
+ // ../../packages/agent-core-v2/src/features/wave/tools/contract/contractRunner.ts
219858
+ function briefRel(root, wave) {
219859
+ const wavesRel = readJson$2(nodeWaveFs, join(root, "workflow.config.json"))?.layout?.waves ?? "design/waves";
219860
+ return `${wavesRel}/${nodeWaveFs.list(join(root, wavesRel)).find((entry) => entry === wave || entry.startsWith(`${wave}-`)) ?? wave}/00-brief.md`;
219861
+ }
219862
+ function runWaveContractForRoot(input) {
219863
+ const brief = briefRel(input.root, input.wave);
219864
+ return runWaveContract({
219865
+ ...input,
219866
+ buildPrompt: (seat) => {
219867
+ const bias = input.round === "judge" ? JUDGE_BIASES[(Number(seat.role.slice(1)) - 1) % JUDGE_BIASES.length] : void 0;
219868
+ const lines = [
219869
+ SEAT_PRELUDE,
219870
+ "",
219871
+ ROLE_PROMPTS[input.round] ?? "",
219872
+ "",
219873
+ `Perfil: ${WAVE_SEAT_PROFILE}`,
219874
+ `Oleada: ${input.wave}. Brief: ${brief}.`,
219875
+ `Escribe: ${seat.file}.`,
219876
+ `Ticket de asiento: ${seat.ticket}. Es capacidad, no identidad: el contrato lo emitió para este asiento y WaveSubmit lo exige.`,
219877
+ `Entrega con WaveSubmit({ wave: "${input.wave}", round: "${input.round}", role: "${seat.role}", ticket: "${seat.ticket}", artifact: "..." }).`
219878
+ ];
219879
+ if (bias !== void 0) lines.push(`Tu sesgo declarado es ${bias}: puntúa CON él, no contra él.`);
219880
+ return lines.join("\n");
219881
+ }
219882
+ });
219883
+ }
219884
+ var init_contractRunner = __esmMin((() => {
219885
+ init_fsJson();
219886
+ init_nodeFs();
219887
+ init_seats();
219888
+ init_prompts$2();
219889
+ init_wave$3();
219890
+ }));
219891
+ // ../../packages/agent-core-v2/src/features/wave/tools/contract/contract.md?raw
219892
+ var contract_default;
219893
+ var init_contract$3 = __esmMin((() => {
219894
+ contract_default = "Create the round's contracts and hand each seat its exact prompt.\n\nReturns one contract per seat: `role`, `artifact` path, `ticket` and the ready-to-launch prompt. Launch one agent per contract with `Agent(subagent_type: \"wave-seat\")` (or `AgentSwarm` when the user enabled swarm) and pass the prompt unchanged — the ticket in it is what `WaveSubmit` accepts.\n\n- Seats and artifact paths come from `roles.*` in `workflow.config.json` and the round's directory. You may narrow them with `seats` (`role`, `artifact`), but an artifact must stay inside the round's directory.\n- You do not write artifacts: `WaveSubmit` is the seat's tool. Contract, launch, then read the results.\n- `report: true` lists which seats of the round have already delivered, without issuing tickets.\n\nClose the round with `WaveDecide` (judges), `WaveVerify` (tasks) and `WaveGate` (package). The wave is not closed until the gate is green.\n";
219895
+ }));
219896
+ // ../../packages/agent-core-v2/src/features/wave/tools/contract/contractTool.ts
219897
+ var WaveContractTool;
219898
+ var init_contractTool = __esmMin((() => {
219899
+ init_sessionContext();
219900
+ init_input_schema();
219901
+ init_contract$4();
219902
+ init_contractRunner();
219903
+ init_contract$3();
219904
+ init_decorateParam();
219905
+ init_decorate();
219906
+ WaveContractTool = class WaveContractTool {
219907
+ sessionContext;
219908
+ name = "WaveContract";
219909
+ description = contract_default;
219910
+ parameters = toInputJsonSchema(WaveContractToolInputSchema);
219911
+ constructor(sessionContext) {
219912
+ this.sessionContext = sessionContext;
219913
+ }
219914
+ resolveExecution(args) {
219915
+ return {
219916
+ description: `Contracting ${args.round} seats of ${args.wave}`,
219917
+ approvalRule: this.name,
219918
+ execute: () => Promise.resolve(runWaveContractForRoot({
219919
+ root: args.root ?? this.sessionContext.cwd,
219920
+ wave: args.wave,
219921
+ round: args.round,
219922
+ seats: args.seats,
219923
+ report: args.report
219924
+ }))
219925
+ };
219926
+ }
219927
+ };
219928
+ WaveContractTool = __decorate([__decorateParam(0, ISessionContext)], WaveContractTool);
219929
+ }));
219930
+ // ../../packages/agent-core-v2/src/features/wave/tools/decide/decide.ts
219931
+ var WaveDecideToolInputSchema, IWaveDecideTool;
219932
+ var init_decide$1 = __esmMin((() => {
219933
+ init_zod$1();
219934
+ init_instantiation();
219935
+ WaveDecideToolInputSchema = object$1({
219936
+ root: string().optional(),
219937
+ verdicts: array(object$1({
219938
+ judge: string().min(1),
219939
+ scores: record$3(string(), number$1())
219940
+ }).strict()).min(1),
219941
+ minPoints: number$1().optional(),
219942
+ minAxes: number$1().optional(),
219943
+ round: number$1().optional()
219944
+ }).strict();
219945
+ IWaveDecideTool = createDecorator("waveDecideTool");
219946
+ }));
219534
219947
  // ../../packages/agent-core-v2/src/features/wave/core/quorum.ts
219535
219948
  function median(values) {
219536
219949
  const sorted = [...values].toSorted((left, right) => left - right);
@@ -219574,17 +219987,13 @@ function evaluateQuorum(input) {
219574
219987
  if (winner === void 0) throw new Error("no hay propuestas que comparar");
219575
219988
  if (second === void 0) return {
219576
219989
  verdict: "refine",
219577
- winner: void 0,
219990
+ winner,
219578
219991
  second: void 0,
219579
219992
  medians,
219580
219993
  medianMargin: 0,
219581
219994
  judgesHoldingMargin: 0,
219582
- perJudge: input.verdicts.map((verdict) => ({
219583
- judge: verdict.judge,
219584
- margin: 0,
219585
- holds: false
219586
- })),
219587
- reason: `solo hay una propuesta (${winner}): sin comparacion no hay quorum`
219995
+ perJudge: [],
219996
+ reason: `sin comparacion no hay quorum: solo hay una propuesta (${winner})`
219588
219997
  };
219589
219998
  const winnerMedian = medians[winner] ?? 0;
219590
219999
  const secondMedian = medians[second] ?? 0;
@@ -219609,8 +220018,7 @@ function evaluateQuorum(input) {
219609
220018
  });
219610
220019
  const judgesHoldingMargin = perJudge.filter((entry) => entry.holds).length;
219611
220020
  const marginOk = medianMargin >= minPoints;
219612
- const requiredJudges = Math.min(minAxes, perJudge.length);
219613
- const majorityOk = judgesHoldingMargin >= requiredJudges;
220021
+ const majorityOk = judgesHoldingMargin >= minAxes;
219614
220022
  if (marginOk && majorityOk) return {
219615
220023
  verdict: "adopt",
219616
220024
  winner,
@@ -219619,9 +220027,9 @@ function evaluateQuorum(input) {
219619
220027
  medianMargin,
219620
220028
  judgesHoldingMargin,
219621
220029
  perJudge,
219622
- reason: `mediana ${winner} ${winnerMedian} vs ${second} ${secondMedian}: margen ${medianMargin} en ${judgesHoldingMargin}/${perJudge.length} jueces (minimo ${requiredJudges})`
220030
+ reason: `mediana ${winner} ${winnerMedian} vs ${second} ${secondMedian}: margen ${medianMargin} en ${judgesHoldingMargin}/${perJudge.length} jueces`
219623
220031
  };
219624
- const reason = [marginOk ? void 0 : `margen ${medianMargin} < ${minPoints}`, majorityOk ? void 0 : `solo ${judgesHoldingMargin}/${perJudge.length} jueces superan el margen (minimo ${requiredJudges})`].filter((part) => part !== void 0).join(" y ");
220032
+ const reason = [marginOk ? void 0 : `margen ${medianMargin} < ${minPoints}`, majorityOk ? void 0 : `solo ${judgesHoldingMargin}/${perJudge.length} jueces superan el margen (minimo ${minAxes})`].filter((part) => part !== void 0).join(" y ");
219625
220033
  return {
219626
220034
  verdict: round >= 2 ? "deadlock" : "refine",
219627
220035
  winner,
@@ -219656,6 +220064,7 @@ function runWaveDecideForRoot(input) {
219656
220064
  isError: true
219657
220065
  };
219658
220066
  }
220067
+ const holding = result.perJudge.length === 0 ? "sin comparacion" : `${result.judgesHoldingMargin}/${result.perJudge.length}`;
219659
220068
  const lines = [
219660
220069
  `QUORUM — ${result.verdict}`,
219661
220070
  "",
@@ -219663,8 +220072,9 @@ function runWaveDecideForRoot(input) {
219663
220072
  "",
219664
220073
  ` ganador: ${result.winner ?? "(empate)"}`,
219665
220074
  ` margen: ${result.medianMargin} (minimo ${input.minPoints ?? config.quorum.minPoints})`,
219666
- ` jueces con margen: ${result.judgesHoldingMargin}/${result.perJudge.length} (minimo ${input.minAxes ?? config.quorum.minAxes})`,
220075
+ ` jueces con margen: ${holding} (minimo ${input.minAxes ?? config.quorum.minAxes})`,
219667
220076
  ...result.perJudge.map((entry) => ` ${entry.judge}: ${entry.margin}${entry.holds ? " ok" : " NO"}`),
220077
+ ...result.perJudge.filter((entry) => entry.margin < 0).map((entry) => ` disidencia: ${entry.judge} ${entry.margin}`),
219668
220078
  "",
219669
220079
  ` motivo: ${result.reason}`
219670
220080
  ];
@@ -219682,7 +220092,7 @@ var init_decideRunner = __esmMin((() => {
219682
220092
  // ../../packages/agent-core-v2/src/features/wave/tools/decide/decide.md?raw
219683
220093
  var decide_default;
219684
220094
  var init_decide = __esmMin((() => {
219685
- 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, then checks the winner beats the second by `minPoints` in at least `minAxes` judges. 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 never crowns a winner.\n";
220095
+ 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";
219686
220096
  }));
219687
220097
  // ../../packages/agent-core-v2/src/features/wave/tools/decide/decideTool.ts
219688
220098
  var WaveDecideTool;
@@ -219729,531 +220139,196 @@ var init_gate$1 = __esmMin((() => {
219729
220139
  }).strict();
219730
220140
  IWaveGateTool = createDecorator("waveGateTool");
219731
220141
  }));
219732
- // ../../packages/agent-core-v2/src/features/wave/tools/open/open.ts
219733
- var WaveOpenToolInputSchema, IWaveOpenTool;
219734
- var init_open$1 = __esmMin((() => {
219735
- init_zod$1();
219736
- init_instantiation();
219737
- WaveOpenToolInputSchema = object$1({
219738
- name: string().min(2),
219739
- id: string().optional(),
219740
- root: string().optional()
219741
- }).strict();
219742
- IWaveOpenTool = createDecorator("waveOpenTool");
219743
- }));
219744
- // ../../packages/agent-core-v2/src/features/wave/core/fsJson.ts
219745
- function readJson$2(fs, path) {
219746
- const text = fs.read(path);
219747
- if (text === void 0) return void 0;
219748
- try {
219749
- return JSON.parse(text);
219750
- } catch {
219751
- return;
220142
+ // ../../packages/agent-core-v2/src/features/wave/core/verify/runner.ts
220143
+ function splitCommand(command) {
220144
+ const tokens = [];
220145
+ let current = "";
220146
+ let quote;
220147
+ for (const char of command) {
220148
+ if (quote !== void 0) {
220149
+ if (char === quote) quote = void 0;
220150
+ else current += char;
220151
+ continue;
220152
+ }
220153
+ if (char === "\"" || char === "'") {
220154
+ quote = char;
220155
+ continue;
220156
+ }
220157
+ if (SHELL_METACHARACTERS.has(char)) throw new Error(`metacaracter de shell prohibido en: ${command}`);
220158
+ if (char === " " || char === " ") {
220159
+ if (current !== "") {
220160
+ tokens.push(current);
220161
+ current = "";
220162
+ }
220163
+ continue;
220164
+ }
220165
+ current += char;
219752
220166
  }
220167
+ if (quote !== void 0) throw new Error(`comillas sin cerrar en: ${command}`);
220168
+ if (current !== "") tokens.push(current);
220169
+ if (tokens.length === 0) throw new Error("comando vacio");
220170
+ return tokens;
219753
220171
  }
219754
- function isRecord$16(value) {
219755
- return typeof value === "object" && value !== null && !Array.isArray(value);
219756
- }
219757
- function asRecord$2(value) {
219758
- return isRecord$16(value) ? value : {};
219759
- }
219760
- function asArray$2(value) {
219761
- return Array.isArray(value) ? value : [];
219762
- }
219763
- function asText$1(value) {
219764
- return typeof value === "string" ? value : "";
219765
- }
219766
- function writeJson(_fs, path, value) {
219767
- mkdirSync(dirname(path), { recursive: true });
219768
- writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
219769
- }
219770
- function walk$1(fs, dir, accept, acc = []) {
219771
- if (!fs.isDirectory(dir)) return acc;
219772
- for (const name of fs.list(dir)) {
219773
- const full = join(dir, name);
219774
- if (fs.isDirectory(full)) walk$1(fs, full, accept, acc);
219775
- else if (accept(full)) acc.push(full);
220172
+ function containPaths(argv, root) {
220173
+ for (const token of argv) {
220174
+ if (token.startsWith("-")) continue;
220175
+ if (!token.includes("/") && !/\.(mjs|cjs|js|ts|sh)$/.test(token)) continue;
220176
+ containedPath(root, token);
219776
220177
  }
219777
- return acc;
219778
- }
219779
- var init_fsJson = __esmMin((() => {}));
219780
- // ../../packages/agent-core-v2/src/features/wave/tools/open/openRunner.ts
219781
- function slugify(name) {
219782
- return name.normalize("NFD").replaceAll(/[\u0300-\u036F]/g, "").toLowerCase().replaceAll(/[^a-z0-9-]+/g, "-").replaceAll(/^-+|-+$/g, "");
219783
220178
  }
219784
- function runWaveOpenForRoot(input) {
219785
- const fs = nodeWaveFs;
219786
- const configFile = join(input.root, "workflow.config.json");
219787
- const rawConfig = readJson$2(fs, configFile);
219788
- if (rawConfig === void 0) return {
219789
- output: `no hay workflow.config.json en ${input.root}`,
219790
- isError: true
219791
- };
219792
- const layout = asRecord$2(asRecord$2(rawConfig)["layout"]);
219793
- const wavesRel = typeof layout["waves"] === "string" ? layout["waves"] : "design/waves";
219794
- let wavesDir;
220179
+ function runCommand$2(command, options) {
220180
+ let argv;
219795
220181
  try {
219796
- wavesDir = containedPath(input.root, wavesRel);
220182
+ argv = splitCommand(command);
220183
+ const binary = (argv[0] ?? "").replace(/\.exe$/i, "");
220184
+ const allowed = options.allowBinaries.map((item) => item.replace(/\.exe$/i, ""));
220185
+ if (!allowed.includes(binary)) throw new Error(`binario no permitido: ${binary} (permitidos: ${allowed.join(", ")})`);
220186
+ containPaths(argv, options.root);
219797
220187
  } catch (error) {
219798
220188
  return {
219799
- output: error instanceof Error ? error.message : String(error),
219800
- isError: true
220189
+ ok: false,
220190
+ output: `rechazado: ${error instanceof Error ? error.message : String(error)}`,
220191
+ rejected: true
219801
220192
  };
219802
220193
  }
219803
- 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));
219804
- const next = input.id ?? `W${existing.length > 0 ? Math.max(...existing) + 1 : 0}`;
219805
- if (!/^W\d{1,2}$/.test(next)) return {
219806
- output: `id de oleada invalido "${next}"`,
219807
- isError: true
219808
- };
219809
- const slug = slugify(input.name);
219810
- if (slug === "") return {
219811
- output: "el nombre de la oleada queda vacio al normalizarlo",
219812
- isError: true
219813
- };
219814
- if (fs.list(wavesDir).some((name) => name === next || name.startsWith(`${next}-`))) return {
219815
- output: `la oleada ${next} ya existe`,
219816
- isError: true
219817
- };
219818
- const dir = join(wavesDir, `${next}-${slug}`);
219819
- for (const sub of SUBDIRS) fs.mkdir(join(dir, sub));
219820
- fs.write(join(dir, "00-brief.md"), BRIEF_SKELETON.replaceAll("{{WAVE}}", next).replaceAll("{{NAME}}", slug));
219821
- const declared = asArray$2(asRecord$2(rawConfig)["waves"]).map(String);
219822
- if (!declared.includes(next)) writeJson(fs, configFile, {
219823
- ...asRecord$2(rawConfig),
219824
- waves: [...declared, next].toSorted()
220194
+ const result = spawnSync(argv[0] ?? "", argv.slice(1), {
220195
+ cwd: options.cwd ?? options.root,
220196
+ encoding: "utf8",
220197
+ timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS$1,
220198
+ stdio: "pipe",
220199
+ shell: false
219825
220200
  });
219826
- return { output: [
219827
- `oleada creada: ${next}-${slug}`,
219828
- ` brief: ${wavesRel}/${next}-${slug}/00-brief.md (rellena las 7 secciones antes de lanzar asientos)`,
219829
- ` config: ${next} declarada en workflow.config.json (el gate la exige desde ahora)`
219830
- ].join("\n") };
219831
- }
219832
- var SUBDIRS, BRIEF_SKELETON;
219833
- var init_openRunner = __esmMin((() => {
219834
- init_config$6();
219835
- init_fsJson();
219836
- init_nodeFs();
219837
- SUBDIRS = [
219838
- "01-proposals",
219839
- "02-defenses",
219840
- "03-attacks",
219841
- "04-verdicts",
219842
- "05-refined"
219843
- ];
219844
- BRIEF_SKELETON = [
219845
- "# {{WAVE}} — Brief: {{NAME}}",
219846
- "",
219847
- "## 1. Contexto vinculante",
219848
- "",
219849
- "## 2. Alcance",
219850
- "",
219851
- "## 3. Evidencia disponible",
219852
- "",
219853
- "## 4. Preguntas que esta oleada resuelve",
219854
- "",
219855
- "## 5. Formato de salida",
219856
- "",
219857
- "## 6. Reglas duras",
219858
- "",
219859
- "## 7. Rúbrica (0-5)",
219860
- ""
219861
- ].join("\n");
219862
- }));
219863
- // ../../packages/agent-core-v2/src/features/wave/tools/open/open.md?raw
219864
- var open_default;
219865
- var init_open = __esmMin((() => {
219866
- open_default = "Open a wave: create its artifact tree and a brief skeleton, and declare the wave in `workflow.config.json`.\n\nThe brief starts with the seven mandatory sections and nothing else — a brief that already contains the answer makes the twelve seats theatre. Fill it before launching any seat; the gate rejects a brief with fewer than seven sections.\n\nOpening a wave also declares it in the config, so the package gate will require its artifacts from then on.\n";
219867
- }));
219868
- // ../../packages/agent-core-v2/src/features/wave/tools/open/openTool.ts
219869
- var WaveOpenTool;
219870
- var init_openTool = __esmMin((() => {
219871
- init_sessionContext();
219872
- init_input_schema();
219873
- init_open$1();
219874
- init_openRunner();
219875
- init_open();
219876
- init_decorateParam();
219877
- init_decorate();
219878
- WaveOpenTool = class WaveOpenTool {
219879
- sessionContext;
219880
- name = "WaveOpen";
219881
- description = open_default;
219882
- parameters = toInputJsonSchema(WaveOpenToolInputSchema);
219883
- constructor(sessionContext) {
219884
- this.sessionContext = sessionContext;
219885
- }
219886
- resolveExecution(args) {
219887
- return {
219888
- description: `Opening wave ${args.name}`,
219889
- approvalRule: this.name,
219890
- execute: () => Promise.resolve(runWaveOpenForRoot({
219891
- root: args.root ?? this.sessionContext.cwd,
219892
- name: args.name,
219893
- id: args.id
219894
- }))
219895
- };
219896
- }
220201
+ const output = `${result.stdout ?? ""}${result.stderr ?? ""}${result.error === void 0 ? "" : result.error.message}`.replaceAll(/\s+/g, " ").trim().slice(0, 300);
220202
+ if (result.error !== void 0) return {
220203
+ ok: false,
220204
+ output: `no se pudo ejecutar: ${output}`,
220205
+ rejected: false
219897
220206
  };
219898
- WaveOpenTool = __decorate([__decorateParam(0, ISessionContext)], WaveOpenTool);
219899
- }));
219900
- // ../../packages/agent-core-v2/src/features/wave/tools/round/round.ts
219901
- var WaveRoundToolInputSchema, IWaveRoundTool;
219902
- var init_round$1 = __esmMin((() => {
219903
- init_zod$1();
219904
- init_instantiation();
219905
- WaveRoundToolInputSchema = object$1({
219906
- wave: string().min(2),
219907
- round: _enum([
219908
- "propose",
219909
- "defend",
219910
- "attack",
219911
- "judge",
219912
- "refine",
219913
- "audit"
219914
- ]),
219915
- root: string().optional()
219916
- }).strict();
219917
- IWaveRoundTool = createDecorator("waveRoundTool");
219918
- }));
219919
- // ../../packages/agent-core-v2/src/features/wave/tools/round/prompts.ts
219920
- var SEAT_PRELUDE, ROLE_PROMPTS, JUDGE_BIASES;
219921
- var init_prompts$2 = __esmMin((() => {
219922
- SEAT_PRELUDE = [
219923
- "Trabajas en una oleada de diseno con aislamiento de escritura.",
219924
- "",
219925
- "Reglas que no dependen de tu rol:",
219926
- "- Escribe UN SOLO artefacto, entregado con WaveSubmit. No toques ningun otro fichero.",
219927
- "- No modifiques el backlog, el codigo ni los artefactos de otros roles.",
219928
- "- Todo lo que afirmes debe apoyarse en evidencia citables (ruta de fichero, dato del brief). Si no la tienes, escribe UNKNOWN con lo que falta. No lo rellenes con una invencion plausible.",
219929
- "- Cada criterio de aceptacion que escribas debe poder fallar. Si no puedes describir el rojo esperado, el criterio no sirve."
219930
- ].join("\n");
219931
- ROLE_PROMPTS = {
219932
- propose: "Rol: proponente. Resuelve el brief de la forma mas simple que cubra el alcance completo, y demuestra que cubre. No propongas alternativas: elige una y defiendela. Incluye alcance con claves exactas, mecanismo concreto, tabla de epics y tasks, tres criterios de aceptacion completos con falsificador, coste y seccion UNKNOWN. No leas las propuestas de los otros proponentes: no existen todavia.",
219933
- defend: "Rol: defensor de la propuesta que te asignan. Sostienla frente a las otras dos con evidencia y declara sus tres puntos mas fragiles antes de que los encuentre un adversario. Prohibido introducir mecanismos nuevos: si lo haces, estas proponiendo, no defendiendo.",
219934
- attack: "Rol: adversario. No puntuas, no eliges favorita, no propones una cuarta propuesta. Caza, por este orden: criterios que no pueden fallar, huecos sin dueno, contradicciones internas, estados imposibles y seguridad. Cada hallazgo lleva id, propuesta afectada, seccion, la mutacion que lo demuestra y gravedad (bloqueante/alta/media/baja). Un hallazgo sin demostracion es una opinion.",
219935
- judge: "Rol: juez. Puntua de 0 a 5 cada propuesta en los cinco ejes del brief y declara una preferencia con su margen. No redisenes. Penaliza sin piedad la falsabilidad: un criterio que no puede fallar resta, aunque el diseno sea bonito.",
219936
- refine: "Rol: refinador integrador. Compone, no elige: toma el mejor mecanismo de cada propuesta y cierra los hallazgos del adversario. Tabla hallazgo -> cerrado/mitigado/abierto con disparador, criterios reescritos con su nuevo rojo esperado, coste resultante y deuda aceptada.",
219937
- audit: "Rol: refinador adversarial, segunda pasada sin cortesia. Audita el refinamiento, caza criterios que no muerden, contrasta las cifras declaradas contra las reales, re-puntua con la misma rubrica y emite los parches obligatorios que falten. Si un parche es necesario y no lo emites, se pierde."
220207
+ return {
220208
+ ok: result.status === 0,
220209
+ output,
220210
+ rejected: false,
220211
+ status: result.status ?? void 0
219938
220212
  };
219939
- JUDGE_BIASES = [
219940
- "coste",
219941
- "falsabilidad",
219942
- "encaje"
219943
- ];
219944
- }));
219945
- // ../../packages/agent-core-v2/src/features/wave/tools/round/roundRunner.ts
219946
- function range(prefix, count) {
219947
- return Array.from({ length: Math.max(1, count) }, (_, index) => `${prefix}${index + 1}`);
219948
- }
219949
- function roleOf(cfg, round) {
219950
- if (round === "propose") return cfg.proponents;
219951
- if (round === "defend") return cfg.defenders;
219952
- if (round === "attack") return cfg.adversaries;
219953
- if (round === "judge") return cfg.judges;
219954
- return 1;
219955
220213
  }
219956
- function runWaveRoundForRoot(input) {
219957
- const fs = nodeWaveFs;
219958
- const rawConfig = readJson$2(fs, join(input.root, "workflow.config.json"));
219959
- if (rawConfig === void 0) return {
219960
- output: `no hay workflow.config.json en ${input.root}`,
219961
- seats: [],
219962
- isError: true
220214
+ function exitDetail(outcome) {
220215
+ return outcome.status === void 0 ? outcome.output : `exit ${outcome.status}: ${outcome.output}`;
220216
+ }
220217
+ function evaluateMutant(ac, verifyCommand, options) {
220218
+ const script = asText$1(asRecord$2(ac["falsifier"])["script"]);
220219
+ if (script === "") return {
220220
+ state: "declarado",
220221
+ detail: "sin falsifier.script: el AC queda declarado y cuenta como FALLO"
219963
220222
  };
219964
- const config = asRecord$2(rawConfig);
219965
- const layout = asRecord$2(config["layout"]);
219966
- const wavesRel = typeof layout["waves"] === "string" ? layout["waves"] : "design/waves";
219967
- let wavesDir;
220223
+ const acId = asText$1(ac["id"]);
220224
+ const apply = runCommand$2(`${script} apply`, options);
220225
+ if (apply.rejected) return {
220226
+ state: "rechazado",
220227
+ detail: `apply rechazado (${script}, ${acId}): ${apply.output}`
220228
+ };
220229
+ let mutated;
220230
+ let restore;
219968
220231
  try {
219969
- wavesDir = containedPath(input.root, wavesRel);
219970
- } catch (error) {
219971
- return {
219972
- output: error instanceof Error ? error.message : String(error),
219973
- seats: [],
219974
- isError: true
219975
- };
220232
+ if (apply.ok) mutated = runCommand$2(verifyCommand, options);
220233
+ } finally {
220234
+ restore = runCommand$2(`${script} restore`, options);
219976
220235
  }
219977
- const waveDir = fs.list(wavesDir).filter((name) => fs.isDirectory(join(wavesDir, name))).find((name) => name === input.wave || name.startsWith(`${input.wave}-`));
219978
- if (waveDir === void 0) return {
219979
- output: `no existe la oleada ${input.wave} en ${wavesRel}`,
219980
- seats: [],
219981
- isError: true
220236
+ const failures = [];
220237
+ if (!apply.ok) failures.push(`apply fallo (${script}, ${acId}) ${exitDetail(apply)}`);
220238
+ if (restore.rejected || !restore.ok) failures.push(`restore fallo (${script}, ${acId}), el arbol puede estar sucio: ${restore.output}`);
220239
+ if (failures.length > 0) return {
220240
+ state: "error",
220241
+ detail: failures.join(" · ")
219982
220242
  };
219983
- const briefRel = `${wavesRel}/${waveDir}/00-brief.md`;
219984
- const brief = fs.read(join(wavesDir, waveDir, "00-brief.md"));
219985
- if (brief === void 0) return {
219986
- output: `falta ${briefRel}`,
219987
- seats: [],
219988
- isError: true
220243
+ if (mutated === void 0) return {
220244
+ state: "error",
220245
+ detail: `no se ejecuto el verify con la mutacion de ${acId}`
219989
220246
  };
219990
- const sections = brief.match(/^##\s+\S/gm)?.length ?? 0;
219991
- if (sections < 7) return {
219992
- output: `el brief tiene ${sections} secciones < 7: rellena las siete antes de lanzar la ronda`,
219993
- seats: [],
219994
- isError: true
220247
+ if (mutated.ok) return {
220248
+ state: "sobrevive",
220249
+ detail: "el verify pasa con la mutacion aplicada: el AC no muerde"
220250
+ };
220251
+ if (!runCommand$2(verifyCommand, options).ok) return {
220252
+ state: "error",
220253
+ detail: "el verify no vuelve a verde tras restaurar"
219995
220254
  };
219996
- const roles = asRecord$2(config["roles"]);
219997
- const counts = {
219998
- proponents: typeof roles["proponents"] === "number" ? roles["proponents"] : 3,
219999
- defenders: typeof roles["defenders"] === "number" ? roles["defenders"] : 3,
220000
- adversaries: typeof roles["adversaries"] === "number" ? roles["adversaries"] : 3,
220001
- judges: typeof roles["judges"] === "number" ? roles["judges"] : 3
220002
- };
220003
- const shape = ROUNDS[input.round];
220004
- const seats = shape.roles(roleOf(counts, input.round)).map((role) => {
220005
- const bias = input.round === "judge" ? JUDGE_BIASES[(Number(role.slice(1)) - 1) % JUDGE_BIASES.length] : void 0;
220006
- const file = `${wavesRel}/${waveDir}/${shape.dir}/${role}.md`;
220007
- const lines = [
220008
- SEAT_PRELUDE,
220009
- "",
220010
- ROLE_PROMPTS[input.round] ?? "",
220011
- "",
220012
- `Oleada: ${input.wave}. Brief: ${briefRel}.`,
220013
- `Escribe: ${file}.`,
220014
- `Entrega con WaveSubmit({ wave: "${input.wave}", round: "${input.round}", role: "${role}", artifact: "..." }).`
220015
- ];
220016
- if (bias !== void 0) lines.push(`Tu sesgo declarado es ${bias}: puntua CON el, no contra el.`);
220017
- return {
220018
- role,
220019
- file,
220020
- prompt: lines.join("\n")
220021
- };
220022
- });
220023
220255
  return {
220024
- output: [`RONDA ${input.round} de ${input.wave}: ${seats.length} asiento(s)`, ...seats.map((seat) => `\n=== ${seat.role} -> ${seat.file}\n${seat.prompt}`)].join("\n"),
220025
- seats
220256
+ state: "muerto",
220257
+ detail: "rojo con la mutacion, verde tras restaurar"
220026
220258
  };
220027
220259
  }
220028
- var ROUNDS;
220029
- var init_roundRunner = __esmMin((() => {
220030
- init_config$6();
220031
- init_fsJson();
220032
- init_nodeFs();
220033
- init_prompts$2();
220034
- ROUNDS = {
220035
- propose: {
220036
- dir: "01-proposals",
220037
- roles: (count) => range("P", count)
220038
- },
220039
- defend: {
220040
- dir: "02-defenses",
220041
- roles: (count) => range("D", count)
220042
- },
220043
- attack: {
220044
- dir: "03-attacks",
220045
- roles: (count) => range("A", count)
220046
- },
220047
- judge: {
220048
- dir: "04-verdicts",
220049
- roles: (count) => range("J", count)
220050
- },
220051
- refine: {
220052
- dir: "05-refined",
220053
- roles: () => ["R1"]
220054
- },
220055
- audit: {
220056
- dir: "05-refined",
220057
- roles: () => ["R2"]
220058
- }
220260
+ function selectTaskCriteria(fs, root, cfg, taskId, ac) {
220261
+ const tasksDir = containedPath(root, cfg.layout.backlog);
220262
+ const file = walk$1(fs, join(tasksDir, "tasks"), (path) => path.endsWith(`${taskId}.json`))[0];
220263
+ if (file === void 0) throw new Error(`no encuentro la task ${taskId} en ${cfg.layout.backlog}/tasks/`);
220264
+ const criteria = asArray$2(asRecord$2(readJson$2(fs, file))["ac"]).map(asRecord$2);
220265
+ if (ac === void 0) return {
220266
+ taskId,
220267
+ criteria
220059
220268
  };
220060
- }));
220061
- // ../../packages/agent-core-v2/src/features/wave/tools/round/round.md?raw
220062
- var round_default;
220063
- var init_round = __esmMin((() => {
220064
- round_default = "Plan one round of a wave: it returns the exact prompt for every seat, ready to launch.\n\nRounds and seats come from `roles.*` in `workflow.config.json`: `propose` gives P1..Pn, `defend` D1..Dn, `attack` A1..An, `judge` J1..Jn (each with a declared bias: coste, falsabilidad, encaje), `refine` R1, `audit` R2.\n\nThis tool does not spawn anything. The orchestrator launches one agent per seat with the returned prompt — `Agent` for a single seat, `AgentSwarm` when the user has enabled swarm mode — and each seat delivers its artifact with WaveSubmit. That keeps fan-out under the user's consent instead of hiding it behind a tool.\n\nThe brief must exist with its seven sections: a round built on a thin brief produces twelve incompatible problems.\n";
220065
- }));
220066
- // ../../packages/agent-core-v2/src/features/wave/tools/round/roundTool.ts
220067
- var WaveRoundTool;
220068
- var init_roundTool = __esmMin((() => {
220069
- init_sessionContext();
220070
- init_input_schema();
220071
- init_round$1();
220072
- init_roundRunner();
220073
- init_round();
220074
- init_decorateParam();
220075
- init_decorate();
220076
- WaveRoundTool = class WaveRoundTool {
220077
- sessionContext;
220078
- name = "WaveRound";
220079
- description = round_default;
220080
- parameters = toInputJsonSchema(WaveRoundToolInputSchema);
220081
- constructor(sessionContext) {
220082
- this.sessionContext = sessionContext;
220083
- }
220084
- resolveExecution(args) {
220085
- return {
220086
- description: `Planning ${args.round} for ${args.wave}`,
220087
- approvalRule: this.name,
220088
- execute: () => Promise.resolve(runWaveRoundForRoot({
220089
- root: args.root ?? this.sessionContext.cwd,
220090
- wave: args.wave,
220091
- round: args.round
220092
- }))
220093
- };
220094
- }
220269
+ const selected = criteria.filter((entry) => asText$1(entry["id"]) === ac);
220270
+ if (selected.length === 0) throw new Error(`no existe el criterio ${ac} en la task ${taskId}`);
220271
+ return {
220272
+ taskId,
220273
+ criteria: selected
220095
220274
  };
220096
- WaveRoundTool = __decorate([__decorateParam(0, ISessionContext)], WaveRoundTool);
220097
- }));
220098
- // ../../packages/agent-core-v2/src/features/wave/tools/submit/submit.ts
220099
- var WaveSubmitToolInputSchema, IWaveSubmitTool;
220100
- var init_submit$1 = __esmMin((() => {
220101
- init_zod$1();
220102
- init_instantiation();
220103
- WaveSubmitToolInputSchema = object$1({
220104
- wave: string().min(2),
220105
- round: _enum([
220106
- "propose",
220107
- "defend",
220108
- "attack",
220109
- "judge",
220110
- "refine",
220111
- "audit"
220112
- ]),
220113
- role: string().min(2),
220114
- artifact: string().min(1),
220115
- replace: boolean$1().optional(),
220116
- root: string().optional()
220117
- }).strict();
220118
- IWaveSubmitTool = createDecorator("waveSubmitTool");
220119
- }));
220120
- // ../../packages/agent-core-v2/src/features/wave/tools/submit/submitRunner.ts
220121
- function slotNames(slot, roles) {
220122
- const configured = roles[slot.role];
220123
- const count = typeof configured === "number" && Number.isFinite(configured) ? Math.max(0, Math.floor(configured)) : 0;
220124
- return Array.from({ length: count }, (_, index) => `${slot.prefix}${index + 1}`);
220125
220275
  }
220126
- function findWaveDir(root, wavesRel, wave) {
220127
- const fs = nodeWaveFs;
220128
- const wavesDir = containedPath(root, wavesRel);
220129
- const name = fs.list(wavesDir).filter((entry) => fs.isDirectory(join(wavesDir, entry))).find((entry) => entry === wave || entry.startsWith(`${wave}-`));
220130
- return name === void 0 ? void 0 : join(wavesDir, name);
220131
- }
220132
- function runWaveSubmitForRoot(input) {
220133
- const fs = nodeWaveFs;
220134
- const rawConfig = readJson$2(fs, join(input.root, "workflow.config.json"));
220135
- if (rawConfig === void 0) return {
220136
- output: `no hay workflow.config.json en ${input.root}`,
220137
- isError: true
220138
- };
220139
- const layout = asRecord$2(asRecord$2(rawConfig)["layout"]);
220140
- const wavesRel = typeof layout["waves"] === "string" ? layout["waves"] : "design/waves";
220141
- const slot = ROUND_SLOTS[input.round];
220142
- const names = slotNames(slot, asRecord$2(asRecord$2(rawConfig)["roles"]));
220143
- const accepted = input.round === "audit" ? names.filter((name) => name !== "R1") : input.round === "refine" ? names.slice(0, 1) : names;
220144
- if (!accepted.includes(input.role)) return {
220145
- output: `el rol "${input.role}" no pertenece a la ronda ${input.round} (esperado ${accepted.join(", ") || "ninguno configurado"})`,
220146
- isError: true
220276
+ function verifyTask(fs, root, cfg, taskId, options) {
220277
+ const { criteria } = selectTaskCriteria(fs, root, cfg, taskId, options?.ac);
220278
+ const runOptions = {
220279
+ root,
220280
+ allowBinaries: cfg.vocabulary.verifyCommands,
220281
+ cwd: options?.cwd,
220282
+ timeoutMs: options?.timeoutMs
220147
220283
  };
220148
- let base;
220149
- try {
220150
- base = findWaveDir(input.root, wavesRel, input.wave);
220151
- } catch (error) {
220152
- return {
220153
- output: error instanceof Error ? error.message : String(error),
220154
- isError: true
220155
- };
220284
+ const acs = [];
220285
+ let declared = 0;
220286
+ for (const ac of criteria) {
220287
+ const verifyCommand = asText$1(ac["verify"]);
220288
+ const verify = runCommand$2(verifyCommand, runOptions);
220289
+ const mutant = evaluateMutant(ac, verifyCommand, runOptions);
220290
+ if (mutant.state === "declarado") declared++;
220291
+ const declaredOk = options?.allowDeclared === true && mutant.state === "declarado";
220292
+ const ok = verify.ok && (mutant.state === "muerto" || declaredOk);
220293
+ acs.push({
220294
+ acId: asText$1(ac["id"]),
220295
+ verify,
220296
+ mutant,
220297
+ ok
220298
+ });
220156
220299
  }
220157
- if (base === void 0) return {
220158
- output: `no existe la oleada ${input.wave} en ${wavesRel}`,
220159
- isError: true
220160
- };
220161
- const dir = join(base, slot.dir);
220162
- if (!fs.isDirectory(dir)) return {
220163
- output: `falta el directorio ${slot.dir} en la oleada ${input.wave}`,
220164
- isError: true
220165
- };
220166
- const file = join(dir, `${input.role}.md`);
220167
- if (fs.exists(file) && input.replace !== true) return {
220168
- output: `el asiento ${input.role} ya entrego su artefacto; un asiento escribe una vez (usa replace solo para relanzar un fallo)`,
220169
- isError: true
220170
- };
220171
- if (input.artifact.trim() === "") return {
220172
- output: "el artefacto esta vacio: un asiento que no escribe, fallo",
220173
- isError: true
220300
+ return {
220301
+ taskId,
220302
+ acs,
220303
+ declared,
220304
+ ok: acs.length > 0 && acs.every((ac) => ac.ok)
220174
220305
  };
220175
- fs.write(file, input.artifact.endsWith("\n") ? input.artifact : `${input.artifact}\n`);
220176
- return { output: `escrito ${wavesRel}/${base.split("/").pop()}/${slot.dir}/${input.role}.md` };
220177
220306
  }
220178
- var ROUND_SLOTS;
220179
- var init_submitRunner = __esmMin((() => {
220307
+ var SHELL_METACHARACTERS, DEFAULT_TIMEOUT_MS$1;
220308
+ var init_runner = __esmMin((() => {
220180
220309
  init_config$6();
220181
220310
  init_fsJson();
220182
- init_nodeFs();
220183
- ROUND_SLOTS = {
220184
- propose: {
220185
- dir: "01-proposals",
220186
- prefix: "P",
220187
- role: "proponents"
220188
- },
220189
- defend: {
220190
- dir: "02-defenses",
220191
- prefix: "D",
220192
- role: "defenders"
220193
- },
220194
- attack: {
220195
- dir: "03-attacks",
220196
- prefix: "A",
220197
- role: "adversaries"
220198
- },
220199
- judge: {
220200
- dir: "04-verdicts",
220201
- prefix: "J",
220202
- role: "judges"
220203
- },
220204
- refine: {
220205
- dir: "05-refined",
220206
- prefix: "R",
220207
- role: "refiners"
220208
- },
220209
- audit: {
220210
- dir: "05-refined",
220211
- prefix: "R",
220212
- role: "refiners"
220213
- }
220214
- };
220215
- }));
220216
- // ../../packages/agent-core-v2/src/features/wave/tools/submit/submit.md?raw
220217
- var submit_default;
220218
- var init_submit = __esmMin((() => {
220219
- 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";
220220
- }));
220221
- // ../../packages/agent-core-v2/src/features/wave/tools/submit/submitTool.ts
220222
- var WaveSubmitTool;
220223
- var init_submitTool = __esmMin((() => {
220224
- init_sessionContext();
220225
- init_input_schema();
220226
- init_submit$1();
220227
- init_submitRunner();
220228
- init_submit();
220229
- init_decorateParam();
220230
- init_decorate();
220231
- WaveSubmitTool = class WaveSubmitTool {
220232
- sessionContext;
220233
- name = "WaveSubmit";
220234
- description = submit_default;
220235
- parameters = toInputJsonSchema(WaveSubmitToolInputSchema);
220236
- constructor(sessionContext) {
220237
- this.sessionContext = sessionContext;
220238
- }
220239
- resolveExecution(args) {
220240
- return {
220241
- description: `Submitting ${args.role}`,
220242
- approvalRule: this.name,
220243
- execute: () => Promise.resolve(runWaveSubmitForRoot({
220244
- root: args.root ?? this.sessionContext.cwd,
220245
- wave: args.wave,
220246
- round: args.round,
220247
- role: args.role,
220248
- artifact: args.artifact,
220249
- replace: args.replace
220250
- }))
220251
- };
220252
- }
220253
- };
220254
- WaveSubmitTool = __decorate([__decorateParam(0, ISessionContext)], WaveSubmitTool);
220311
+ SHELL_METACHARACTERS = /* @__PURE__ */ new Set([
220312
+ "|",
220313
+ "&",
220314
+ ";",
220315
+ "<",
220316
+ ">",
220317
+ "`",
220318
+ "$",
220319
+ "\n",
220320
+ "\r"
220321
+ ]);
220322
+ DEFAULT_TIMEOUT_MS$1 = 6e5;
220255
220323
  }));
220256
220324
  // ../../packages/agent-core-v2/src/features/wave/core/gate/checks.ts
220325
+ function measurableThreshold(text, units) {
220326
+ const low = normalize$1(text);
220327
+ if (OPERATOR_WITH_NUMBER.test(low)) return true;
220328
+ if (EXACT_VALUE.test(low)) return true;
220329
+ if (units.some((unit) => new RegExp(`\\d\\s*${escapeRegExp$1(unit)}\\b`).test(low))) return true;
220330
+ return low.split(/\s*(?:,|;|\by\b)\s*/).filter(Boolean).length >= 3;
220331
+ }
220257
220332
  function record$1(value) {
220258
220333
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
220259
220334
  }
@@ -220281,38 +220356,350 @@ function walk(fs, dir, accept, acc = []) {
220281
220356
  }
220282
220357
  return acc;
220283
220358
  }
220284
- function escapeRegExp$1(value) {
220285
- return value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
220359
+ function requiredArtifacts(cfg) {
220360
+ const required = ["00-brief.md"];
220361
+ for (const round of WAVE_ROUNDS) for (const seat of waveRoundSeats(cfg.roles, round)) required.push(`${WAVE_ROUND_DIRS[round]}/${seat}.md`);
220362
+ required.push(DECISION_FILE, "07-epics.json");
220363
+ return required;
220364
+ }
220365
+ function briefSections(text) {
220366
+ const sections = [];
220367
+ let current;
220368
+ for (const line of text.split("\n")) {
220369
+ const heading = /^##\s+(.+?)\s*$/.exec(line);
220370
+ if (heading !== null) {
220371
+ current = {
220372
+ title: heading[1] ?? "",
220373
+ body: []
220374
+ };
220375
+ sections.push(current);
220376
+ continue;
220377
+ }
220378
+ if (/^#\s+/.test(line)) {
220379
+ current = void 0;
220380
+ continue;
220381
+ }
220382
+ current?.body.push(line);
220383
+ }
220384
+ return sections.map((section) => ({
220385
+ title: section.title,
220386
+ body: section.body.join("\n").trim()
220387
+ }));
220286
220388
  }
220287
- function hasMeasure(value) {
220288
- if (/[<>=≤≥]/.test(value)) return true;
220289
- if (/\b(ms|s|seg|segundos?|minutos?|filas?|bytes?|p95|peticiones?|veces|puntos?|codigo|status|exact\w*)\b/i.test(value)) return true;
220290
- return /[a-z]/i.test(value) && !/^\d+(\s+\d+)+$/.test(value);
220389
+ function sectionKeyword(title) {
220390
+ return normalize$1(title).replace(/^\d+\.?\s*/, "").match(/[a-z0-9]+/)?.[0] ?? "";
220291
220391
  }
220292
- function isDestructive(mutation) {
220293
- return /(borrar|borra|eliminar|elimina|drop|truncate|wipe|rm -rf)[^.]{0,40}(esquema|schema|cluster|volumen|directorio|carpeta|repositorio|contenedor|base de datos|database|entorno)/i.test(mutation) || /(drop|truncate)\s+(table|database|schema)/i.test(mutation);
220392
+ function decisionStrip(value) {
220393
+ return (value ?? "").replaceAll("*", "").trim();
220294
220394
  }
220295
- function verifyTargetExists(waveDir, target) {
220296
- const resolved = resolve(waveDir, target);
220297
- return resolved.startsWith(waveDir) && existsSync(resolved);
220395
+ function decisionSplitRow(line) {
220396
+ return line.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((cell) => cell.trim());
220298
220397
  }
220299
- function waveDirectories(fs, root, cfg) {
220300
- const dir = containedPath(root, cfg.layout.waves);
220301
- const map = /* @__PURE__ */ new Map();
220302
- for (const wave of cfg.waves) {
220303
- const match = fs.list(dir).find((name) => name === wave || name.startsWith(`${wave}-`));
220304
- if (match !== void 0) map.set(wave, join(dir, match));
220398
+ function isDecisionSeparator(row) {
220399
+ return row.length > 0 && row.every((cell) => DECISION_SEPARATOR.test(decisionStrip(cell)));
220400
+ }
220401
+ function decisionTables(text) {
220402
+ const blocks = [];
220403
+ let current = [];
220404
+ for (const line of text.split("\n")) {
220405
+ if (line.trim().startsWith("|")) {
220406
+ current.push(decisionSplitRow(line));
220407
+ continue;
220408
+ }
220409
+ if (current.length > 0) blocks.push(current);
220410
+ current = [];
220305
220411
  }
220306
- return map;
220412
+ if (current.length > 0) blocks.push(current);
220413
+ return blocks.filter((block) => block.length >= 2).map((block) => ({
220414
+ header: block[0] ?? [],
220415
+ body: block.slice(1).filter((row) => !isDecisionSeparator(row) && row.length === (block[0] ?? []).length)
220416
+ }));
220307
220417
  }
220308
- function requiredArtifacts(cfg) {
220309
- const required = ["00-brief.md"];
220310
- for (let i = 1; i <= cfg.roles.proponents; i++) required.push(`01-proposals/P${i}.md`);
220311
- for (let i = 1; i <= cfg.roles.defenders; i++) required.push(`02-defenses/D${i}.md`);
220312
- for (let i = 1; i <= cfg.roles.adversaries; i++) required.push(`03-attacks/A${i}.md`);
220313
- for (let i = 1; i <= cfg.roles.judges; i++) required.push(`04-verdicts/J${i}.md`);
220314
- required.push("05-refined/R1.md", "05-refined/R2.md", DECISION_FILE, "07-epics.json");
220315
- return required;
220418
+ function decisionNumber(cell) {
220419
+ const value = decisionStrip(cell);
220420
+ if (value === "") return void 0;
220421
+ const match = DECISION_LEADING_NUMBER.exec(value);
220422
+ return match === null ? void 0 : Number(match[0].replace(",", "."));
220423
+ }
220424
+ function decisionProposal(cell) {
220425
+ const value = decisionStrip(cell);
220426
+ if (value === "") return void 0;
220427
+ return DECISION_PROPOSAL.test(value.toLowerCase()) ? value.toUpperCase() : void 0;
220428
+ }
220429
+ function decisionAxis(row, axes) {
220430
+ const low = normalize$1(decisionStrip(row));
220431
+ if (low === "") return void 0;
220432
+ const exact = axes.find((axis) => normalize$1(axis) === low);
220433
+ if (exact !== void 0) return exact;
220434
+ return axes.find((axis) => low.includes(normalize$1(axis)));
220435
+ }
220436
+ function isDecisionTotal(cell) {
220437
+ return /\btotal\b/.test(normalize$1(decisionStrip(cell)));
220438
+ }
220439
+ function isDecisionMedian(cell) {
220440
+ return /\bmedian/.test(normalize$1(decisionStrip(cell)));
220441
+ }
220442
+ function decisionColumn(header, predicate) {
220443
+ return header.findIndex((cell) => predicate(cell));
220444
+ }
220445
+ function findDecisionMatrix(blocks, axes) {
220446
+ let best;
220447
+ for (const block of blocks) {
220448
+ const header = block.header.map(decisionStrip);
220449
+ const columnProposals = header.filter((cell) => decisionProposal(cell) !== void 0);
220450
+ const rowProposals = block.body.filter((row) => decisionProposal(row[0]) !== void 0);
220451
+ const axisColumns = header.filter((cell) => decisionAxis(cell, axes) !== void 0 && !isDecisionTotal(cell) && !isDecisionMedian(cell));
220452
+ const axisRows = block.body.filter((row) => decisionAxis(row[0], axes) !== void 0);
220453
+ const byColumn = columnProposals.length >= 2 && axisRows.length > 0;
220454
+ const byRow = rowProposals.length >= 2 && axisColumns.length > 0;
220455
+ if (!byColumn && !byRow) continue;
220456
+ const score = Math.max(axisRows.length, axisColumns.length) * 10 + Math.max(columnProposals.length, rowProposals.length);
220457
+ if (best === void 0 || score > best.score) best = {
220458
+ block,
220459
+ orientation: byColumn ? "columns" : "rows",
220460
+ score
220461
+ };
220462
+ }
220463
+ return best;
220464
+ }
220465
+ function readDecisionColumns(block, axes, proposals, found) {
220466
+ const indexes = /* @__PURE__ */ new Map();
220467
+ for (const [index, cell] of block.header.entries()) {
220468
+ const proposal = decisionProposal(cell);
220469
+ if (proposal !== void 0 && !indexes.has(proposal)) indexes.set(proposal, index);
220470
+ }
220471
+ for (const row of block.body) {
220472
+ const axis = decisionAxis(row[0], axes);
220473
+ if (axis === void 0 || found.has(axis)) continue;
220474
+ const cells = {};
220475
+ found.set(axis, {
220476
+ label: decisionStrip(row[0]),
220477
+ cells
220478
+ });
220479
+ for (const proposal of proposals) {
220480
+ const index = indexes.get(proposal);
220481
+ cells[proposal] = index === void 0 ? void 0 : decisionNumber(row[index]);
220482
+ }
220483
+ }
220484
+ return indexes;
220485
+ }
220486
+ function readDecisionRows(block, axes, found) {
220487
+ const columns = [];
220488
+ for (const [index, cell] of block.header.entries()) {
220489
+ const axis = decisionAxis(cell, axes);
220490
+ if (axis === void 0 || isDecisionTotal(cell) || isDecisionMedian(cell)) continue;
220491
+ columns.push({
220492
+ axis,
220493
+ index,
220494
+ label: decisionStrip(cell)
220495
+ });
220496
+ }
220497
+ const seen = [];
220498
+ for (const row of block.body) {
220499
+ const proposal = decisionProposal(row[0]);
220500
+ if (proposal === void 0) continue;
220501
+ if (!seen.includes(proposal)) seen.push(proposal);
220502
+ for (const column of columns) {
220503
+ const existing = found.get(column.axis);
220504
+ const entry = existing ?? {
220505
+ label: column.label,
220506
+ cells: {}
220507
+ };
220508
+ if (existing === void 0) found.set(column.axis, entry);
220509
+ if (entry.cells[proposal] !== void 0) continue;
220510
+ entry.cells[proposal] = decisionNumber(row[column.index]);
220511
+ }
220512
+ }
220513
+ return seen;
220514
+ }
220515
+ function decisionDeclarations(blocks, matrix, proposals) {
220516
+ const totals = {};
220517
+ const medians = {};
220518
+ const take = (target, proposal, value) => {
220519
+ if (proposal === void 0 || value === void 0 || target[proposal] !== void 0) return;
220520
+ target[proposal] = value;
220521
+ };
220522
+ if (matrix !== void 0) {
220523
+ const header = matrix.block.header.map(decisionStrip);
220524
+ const totalColumn = matrix.orientation === "rows" ? decisionColumn(header, isDecisionTotal) : -1;
220525
+ const medianColumn = matrix.orientation === "rows" ? decisionColumn(header, isDecisionMedian) : -1;
220526
+ for (const row of matrix.block.body) {
220527
+ const proposal = decisionProposal(row[0]);
220528
+ if (proposal !== void 0) {
220529
+ if (totalColumn !== -1) take(totals, proposal, decisionNumber(row[totalColumn]));
220530
+ if (medianColumn !== -1) take(medians, proposal, decisionNumber(row[medianColumn]));
220531
+ continue;
220532
+ }
220533
+ if (isDecisionTotal(row[0]) || isDecisionMedian(row[0])) {
220534
+ const target = isDecisionTotal(row[0]) ? totals : medians;
220535
+ for (const item of proposals) {
220536
+ const index = header.findIndex((cell) => decisionProposal(cell) === item);
220537
+ take(target, item, index === -1 ? void 0 : decisionNumber(row[index]));
220538
+ }
220539
+ }
220540
+ }
220541
+ }
220542
+ for (const block of blocks) {
220543
+ const header = block.header.map(decisionStrip);
220544
+ const totalColumn = decisionColumn(header, isDecisionTotal);
220545
+ const medianColumn = decisionColumn(header, isDecisionMedian);
220546
+ if (totalColumn === -1 && medianColumn === -1) continue;
220547
+ for (const row of block.body) {
220548
+ const proposal = decisionProposal(row[0]);
220549
+ if (proposal === void 0) continue;
220550
+ if (totalColumn !== -1) take(totals, proposal, decisionNumber(row[totalColumn]));
220551
+ if (medianColumn !== -1) take(medians, proposal, decisionNumber(row[medianColumn]));
220552
+ }
220553
+ }
220554
+ return {
220555
+ totals,
220556
+ medians
220557
+ };
220558
+ }
220559
+ function decisionMargins(blocks) {
220560
+ for (const block of blocks) {
220561
+ const header = block.header.map(decisionStrip);
220562
+ const judgeColumn = decisionColumn(header, (cell) => normalize$1(cell).includes("juez"));
220563
+ const marginColumn = decisionColumn(header, (cell) => normalize$1(cell).includes("margen"));
220564
+ if (judgeColumn === -1 || marginColumn === -1) continue;
220565
+ const preferColumn = decisionColumn(header, (cell) => normalize$1(cell).includes("prefer"));
220566
+ const rows = [];
220567
+ for (const row of block.body) {
220568
+ const judge = decisionStrip(row[judgeColumn]);
220569
+ if (!DECISION_JUDGE.test(judge)) continue;
220570
+ const margin = DECISION_SIGNED_MARGIN.exec(decisionStrip(row[marginColumn]));
220571
+ if (margin === null) continue;
220572
+ rows.push({
220573
+ judge,
220574
+ margin: Number((margin[1] ?? "0").replace(",", ".")),
220575
+ prefers: preferColumn === -1 ? void 0 : decisionProposal(row[preferColumn])
220576
+ });
220577
+ }
220578
+ if (rows.length > 0) return rows;
220579
+ }
220580
+ return [];
220581
+ }
220582
+ function decisionDissent(text) {
220583
+ const lines = text.split("\n");
220584
+ const start = lines.findIndex((line) => /^#{1,3}\s+\d*\.?\s*disidencias/i.test(line));
220585
+ if (start === -1) return void 0;
220586
+ const level = /^(#{1,3})/.exec(lines[start] ?? "")?.[1]?.length ?? 1;
220587
+ const collected = [];
220588
+ for (const line of lines.slice(start + 1)) {
220589
+ const heading = /^(#{1,3})\s+\S/.exec(line);
220590
+ if (heading !== null && (heading[1] ?? "").length <= level) break;
220591
+ collected.push(line);
220592
+ }
220593
+ return collected.join("\n").trim();
220594
+ }
220595
+ function parseDecisionMatrix(text, options) {
220596
+ const axes = options.axes.map(String);
220597
+ const blocks = decisionTables(text);
220598
+ const matrix = findDecisionMatrix(blocks, axes);
220599
+ const found = /* @__PURE__ */ new Map();
220600
+ let proposals = options.proposals.map(String);
220601
+ let present = [];
220602
+ if (matrix !== void 0) {
220603
+ if (matrix.orientation === "columns") {
220604
+ if (proposals.length === 0) proposals = matrix.block.header.map(decisionStrip).map(decisionProposal).filter((label) => label !== void 0);
220605
+ const indexes = readDecisionColumns(matrix.block, axes, proposals, found);
220606
+ present = proposals.filter((proposal) => indexes.has(proposal));
220607
+ } else {
220608
+ if (proposals.length === 0) proposals = matrix.block.body.map((row) => decisionProposal(row[0])).filter((label) => label !== void 0);
220609
+ const seen = readDecisionRows(matrix.block, axes, found);
220610
+ present = proposals.filter((proposal) => seen.includes(proposal));
220611
+ }
220612
+ }
220613
+ const axisRows = [];
220614
+ const cells = [];
220615
+ const missing = [];
220616
+ for (const axis of axes) {
220617
+ const row = found.get(axis);
220618
+ if (row === void 0) continue;
220619
+ axisRows.push({
220620
+ axis,
220621
+ label: row.label,
220622
+ cells: row.cells
220623
+ });
220624
+ for (const proposal of present) {
220625
+ const value = row.cells[proposal];
220626
+ if (typeof value === "number") cells.push({
220627
+ axis,
220628
+ proposal,
220629
+ value
220630
+ });
220631
+ else missing.push({
220632
+ axis,
220633
+ proposal
220634
+ });
220635
+ }
220636
+ }
220637
+ const declarations = decisionDeclarations(blocks, matrix, proposals);
220638
+ const axesFound = axisRows.map((row) => row.axis);
220639
+ return {
220640
+ present: matrix !== void 0,
220641
+ orientation: matrix?.orientation,
220642
+ header: matrix === void 0 ? [] : matrix.block.header.map(decisionStrip),
220643
+ proposals,
220644
+ presentProposals: present,
220645
+ axisRows,
220646
+ cells,
220647
+ missing,
220648
+ axesFound,
220649
+ axesMissing: axes.filter((axis) => !axesFound.includes(axis)),
220650
+ totals: declarations.totals,
220651
+ medians: declarations.medians,
220652
+ margins: decisionMargins(blocks),
220653
+ dissent: decisionDissent(text)
220654
+ };
220655
+ }
220656
+ function decisionProposalSum(matrix, proposal) {
220657
+ const values = matrix.axisRows.map((row) => row.cells[proposal]);
220658
+ if (values.length === 0) return void 0;
220659
+ let total = 0;
220660
+ for (const value of values) {
220661
+ if (typeof value !== "number") return void 0;
220662
+ total += value;
220663
+ }
220664
+ return total;
220665
+ }
220666
+ function decisionMedian(values) {
220667
+ if (values.length === 0) return void 0;
220668
+ const sorted = [...values].toSorted((left, right) => left - right);
220669
+ const middle = Math.floor(sorted.length / 2);
220670
+ const current = sorted[middle];
220671
+ if (current === void 0) return void 0;
220672
+ if (sorted.length % 2 === 1) return current;
220673
+ const previous = sorted[middle - 1];
220674
+ return previous === void 0 ? void 0 : (previous + current) / 2;
220675
+ }
220676
+ function decisionRecalculateMedians(verdicts, options) {
220677
+ const tables = [];
220678
+ const missing = [];
220679
+ for (const verdict of verdicts) {
220680
+ const matrix = parseDecisionMatrix(verdict.text, options);
220681
+ if (!(matrix.present && matrix.axesMissing.length === 0 && matrix.missing.length === 0)) {
220682
+ missing.push(verdict.file);
220683
+ continue;
220684
+ }
220685
+ const totals = {};
220686
+ for (const proposal of matrix.proposals) totals[proposal] = decisionProposalSum(matrix, proposal) ?? NaN;
220687
+ tables.push({
220688
+ file: verdict.file,
220689
+ totals
220690
+ });
220691
+ }
220692
+ const medians = {};
220693
+ if (missing.length === 0 && tables.length > 0) for (const proposal of options.proposals) {
220694
+ const values = tables.map((entry) => entry.totals[proposal]).filter((value) => typeof value === "number" && Number.isFinite(value));
220695
+ if (values.length !== tables.length) continue;
220696
+ const value = decisionMedian(values);
220697
+ if (value !== void 0) medians[proposal] = value;
220698
+ }
220699
+ return {
220700
+ medians,
220701
+ missing
220702
+ };
220316
220703
  }
220317
220704
  function runWaveGate(fs, root, cfg) {
220318
220705
  const findings = [];
@@ -220341,8 +220728,24 @@ function runWaveGate(fs, root, cfg) {
220341
220728
  let epics = [];
220342
220729
  let tasks = [];
220343
220730
  let totalAc = 0;
220731
+ const state = waveConfigState(cfg);
220344
220732
  block("config", () => {
220345
220733
  if (cfg.loadedFrom === void 0) add("config.missing", null, "no se encontro workflow.config.json");
220734
+ const raw = state.raw;
220735
+ const version = typeof raw["version"] === "number" ? raw["version"] : state.version;
220736
+ for (const key of [
220737
+ "version",
220738
+ "layout",
220739
+ "waves",
220740
+ "thresholds",
220741
+ "vocabulary"
220742
+ ]) if (raw[key] === void 0) add("config.missing_key", null, `falta la clave "${key}"`);
220743
+ if (version !== 1 && version !== 2) add("config.version_unknown", null, `version "${String(version)}" fuera de uno y dos: el gate no sabe leerla`);
220744
+ if (version === 2) {
220745
+ if (raw["wavesOpen"] === void 0) add("config.missing_key", null, "falta la clave \"wavesOpen\"");
220746
+ if (raw["vocabulary"] === void 0 || record$1(raw["vocabulary"])["units"] === void 0) add("config.missing_key", null, "falta la clave \"vocabulary.units\"");
220747
+ if (raw["falsifier"] === void 0) add("config.missing_key", null, "falta la clave \"falsifier\"");
220748
+ }
220346
220749
  if (cfg.waves.length === 0) add("config.bad_waves", null, "waves debe ser un array no vacio");
220347
220750
  if (vocabulary.verifyCommands.length === 0) add("config.bad_vocabulary", null, "vocabulary.verifyCommands vacio");
220348
220751
  if (vocabulary.verifyPrefixes.length === 0) add("config.bad_vocabulary", null, "vocabulary.verifyPrefixes vacio");
@@ -220378,19 +220781,89 @@ function runWaveGate(fs, root, cfg) {
220378
220781
  }
220379
220782
  }
220380
220783
  });
220784
+ block("brief", () => {
220785
+ const templateFile = join(root, BRIEF_TEMPLATE$1);
220786
+ if (!fs.exists(templateFile)) return;
220787
+ const template = briefSections(fs.read(templateFile) ?? "");
220788
+ if (wavesDir === void 0 || !fs.isDirectory(wavesDir)) return;
220789
+ for (const wave of cfg.waves) {
220790
+ const match = waveDirs.find((name) => name === wave || name.startsWith(`${wave}-`));
220791
+ if (match === void 0) continue;
220792
+ const file = join(wavesDir, match, "00-brief.md");
220793
+ const text = fs.read(file);
220794
+ if (text === void 0) continue;
220795
+ const at = relative$1(root, file);
220796
+ const sections = briefSections(text);
220797
+ if (sections.length !== template.length) add("waves.brief_template_drift", at, `${sections.length} secciones frente a ${template.length} de ${BRIEF_TEMPLATE$1}: el brief ya no sigue la plantilla`);
220798
+ for (const [index, expected] of template.entries()) {
220799
+ const section = sections[index];
220800
+ if (section === void 0) continue;
220801
+ if (sectionKeyword(section.title) !== sectionKeyword(expected.title)) add("waves.brief_template_drift", at, `la seccion ${index + 1} se titula "${section.title}" y ${BRIEF_TEMPLATE$1} exige "${expected.title}"`);
220802
+ }
220803
+ for (const section of sections) if (section.body === "") add("waves.brief_empty_section", at, `la seccion "${section.title}" no tiene contenido`);
220804
+ }
220805
+ });
220381
220806
  block("decision", () => {
220382
220807
  const dir = wavesDir;
220383
220808
  if (dir === void 0 || !fs.isDirectory(dir)) return;
220809
+ const axes = cfg.quorum.axes;
220810
+ const proposals = Array.from({ length: cfg.roles.proponents }, (_, index) => `P${index + 1}`);
220811
+ const judges = cfg.roles.judges;
220384
220812
  for (const wave of cfg.waves) {
220385
220813
  const match = waveDirs.find((name) => name === wave || name.startsWith(`${wave}-`));
220386
220814
  if (match === void 0) continue;
220387
- const file = join(dir, match, DECISION_FILE);
220815
+ const base = join(dir, match);
220816
+ const file = join(base, DECISION_FILE);
220388
220817
  const text = fs.read(file);
220389
220818
  if (text === void 0) continue;
220390
220819
  const low = normalize$1(text);
220391
220820
  const at = relative$1(root, file);
220392
- for (let i = 1; i <= cfg.roles.proponents; i++) if (!low.includes(`p${i}`)) add("waves.decision_missing_role", at, `no nombra la propuesta P${i} de la matriz`);
220393
- for (const axis of cfg.quorum.axes) if (!low.includes(normalize$1(axis))) add("waves.decision_missing_axis", at, `sin eje "${axis}" en la matriz`);
220821
+ const matrix = parseDecisionMatrix(text, {
220822
+ axes,
220823
+ proposals
220824
+ });
220825
+ 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`);
220826
+ if (!matrix.present) add("waves.decision_without_quorum", at, "sin tabla de la matriz: la ronda no trae puntuaciones que auditar");
220827
+ else {
220828
+ for (const axis of axes) if (!matrix.axesFound.includes(axis)) add("waves.decision_missing_axis", at, `sin eje "${axis}" en la matriz`);
220829
+ for (const item of matrix.missing) add("waves.decision_matrix_incomplete", at, `eje "${item.axis}" · propuesta ${item.proposal}: celda vacia`);
220830
+ for (const proposal of proposals) {
220831
+ const declared = matrix.totals[proposal];
220832
+ const sum = decisionProposalSum(matrix, proposal);
220833
+ if (declared === void 0 || sum === void 0 || declared === sum) continue;
220834
+ add("waves.decision_total_mismatch", at, `${proposal}: total declarado ${declared} y recalculado ${sum} desde las celdas de la matriz`);
220835
+ }
220836
+ if (proposals.some((proposal) => matrix.medians[proposal] !== void 0)) {
220837
+ const verdictsDir = join(base, "04-verdicts");
220838
+ const recalc = decisionRecalculateMedians(Array.from({ length: judges }, (_, index) => {
220839
+ const name = `J${index + 1}.md`;
220840
+ return {
220841
+ file: `${relative$1(root, verdictsDir)}/${name}`,
220842
+ text: fs.read(join(verdictsDir, name)) ?? ""
220843
+ };
220844
+ }), {
220845
+ axes,
220846
+ proposals
220847
+ });
220848
+ 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`);
220849
+ if (recalc.missing.length === 0) {
220850
+ const citation = Array.from({ length: judges }, (_, index) => `04-verdicts/J${index + 1}.md`).join(", ");
220851
+ for (const proposal of proposals) {
220852
+ const declared = matrix.medians[proposal];
220853
+ const value = recalc.medians[proposal];
220854
+ if (declared === void 0 || value === void 0 || declared === value) continue;
220855
+ add("waves.decision_median_mismatch", at, `${proposal}: mediana declarada ${declared} y recalculada ${value} desde ${citation}`);
220856
+ }
220857
+ }
220858
+ }
220859
+ if (matrix.margins.length > 0) {
220860
+ const dissent = normalize$1(matrix.dissent ?? "");
220861
+ for (const row of matrix.margins) {
220862
+ if (row.margin >= 0 || dissent.includes(normalize$1(row.judge))) continue;
220863
+ add("waves.decision_undisclosed_dissent", at, `${row.judge}: margen ${row.margin} y no aparece en "## Disidencias"`);
220864
+ }
220865
+ }
220866
+ }
220394
220867
  if (!/^#{1,3}\s+\d*\.?\s*disidencias/im.test(text)) add("waves.decision_without_dissent", at, "falta la seccion \"## Disidencias\"");
220395
220868
  if (text.length < thresholds.minDecisionBytes) add("waves.decision_thin", at, `${text.length} B < ${thresholds.minDecisionBytes} B minimos`);
220396
220869
  const numbers = text.match(/\b\d+(?:[.,]\d+)?\b/g)?.length ?? 0;
@@ -220479,10 +220952,16 @@ function runWaveGate(fs, root, cfg) {
220479
220952
  if (tasks.length < thresholds.minTasks) add("tasks.count", null, `${tasks.length} tasks < ${thresholds.minTasks} minimas`);
220480
220953
  });
220481
220954
  block("ac", () => {
220482
- const vague = vocabulary.vagueWords.map((word) => normalize$1(word)).filter(Boolean);
220483
- const vaguePattern = vague.length === 0 ? void 0 : new RegExp(`(^|[^a-z0-9])(${vague.map(escapeRegExp$1).join("|")})[a-z]*([^a-z0-9]|$)`);
220955
+ const vague = vocabulary.vagueWords.map((word) => normalize$1(word)).filter(Boolean).map((word) => ({
220956
+ word,
220957
+ root: word.replace(/[aeiou]$/, "")
220958
+ })).filter((entry) => entry.root !== "");
220959
+ const units = asArray$1(record$1(state.raw["vocabulary"])["units"]).map(str$2).map(normalize$1).filter(Boolean);
220960
+ const falsifierLexicon = record$1(state.raw["falsifier"]);
220961
+ const stateVerbs = asArray$1(falsifierLexicon["stateVerbs"]).map(str$2).map(normalize$1).filter(Boolean);
220962
+ const stateObjects = asArray$1(falsifierLexicon["stateObjects"]).map(str$2).map(normalize$1).filter(Boolean);
220484
220963
  const withFalsifier = /* @__PURE__ */ new Set();
220485
- const waveDirs = waveDirectories(fs, root, cfg);
220964
+ const openWaves = new Set(state.wavesOpen);
220486
220965
  for (const task of tasks) {
220487
220966
  const taskId = str$2(task["id"]);
220488
220967
  for (const raw of asArray$1(task["ac"])) {
@@ -220502,31 +220981,67 @@ function runWaveGate(fs, root, cfg) {
220502
220981
  }
220503
220982
  const metric = str$2(ac["metric"]);
220504
220983
  if (metric !== "" && metric.length < thresholds.minMetricChars) add("ac.short_metric", at, `"metric" < ${thresholds.minMetricChars} caracteres`);
220505
- const prose = normalize$1(`${str$2(ac["then"])} ${str$2(ac["threshold"])} ${metric}`);
220506
- const hit = vaguePattern?.exec(prose)?.[2];
220507
- if (hit !== void 0) add("ac.vague_language", at, `"${hit}" no es medible: el AC no muerde`);
220508
- const thresholdText = str$2(ac["threshold"]).trim();
220509
- if (thresholdText !== "" && !hasMeasure(thresholdText)) add("ac.threshold_not_measurable", at, `"${thresholdText}" no declara unidad, operador ni magnitud comparada`);
220984
+ const threshold = str$2(ac["threshold"]);
220985
+ 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`);
220986
+ const prose = normalize$1(`${str$2(ac["then"])} ${threshold} ${metric}`);
220987
+ const vagueHit = vague.find((entry) => new RegExp(`\\b${escapeRegExp$1(entry.root)}[a-z]{0,10}\\b`).test(prose));
220988
+ if (vagueHit !== void 0) {
220989
+ const matched = new RegExp(`\\b${escapeRegExp$1(vagueHit.root)}[a-z]{0,10}\\b`).exec(prose)?.[0] ?? vagueHit.root;
220990
+ add("ac.vague_language", at, `"${matched}" contiene la raiz "${vagueHit.root}" de "${vagueHit.word}": no es medible`);
220991
+ }
220510
220992
  const verify = str$2(ac["verify"]).trim();
220511
220993
  if (verify !== "") {
220512
220994
  const command = verify.split(/\s+/)[0] ?? "";
220513
220995
  if (!vocabulary.verifyCommands.includes(command)) add("ac.verify_not_command", at, `"${command}" no es un comando de la lista permitida`);
220514
220996
  else {
220515
- const matched = verify.match(/\b((?:[\w.-]+\/)+[\w.-]+)/)?.[1];
220516
- if (matched === void 0) add("ac.verify_outside_test_plan", at, "el comando no apunta a ningun fichero o directorio verificable");
220517
- else if (!vocabulary.verifyPrefixes.some((prefix) => matched.startsWith(prefix))) add("ac.verify_outside_test_plan", at, `"${matched}" fuera del test plan declarado`);
220518
- else if (!thresholds.allowVerifyTargetMissing && !verifyTargetExists(waveDirs.get(str$2(task["wave"])) ?? root, matched)) add("ac.verify_target_missing", at, `"${matched}" no existe en el arbol: el verify saldria verde sin ejecutar nada`);
220997
+ let argv;
220998
+ try {
220999
+ argv = splitCommand(verify);
221000
+ } catch (error) {
221001
+ add("ac.verify_command_unsafe", at, error instanceof Error ? error.message : String(error));
221002
+ }
221003
+ if (argv !== void 0) {
221004
+ let escaped;
221005
+ for (const token of argv) {
221006
+ if (token.startsWith("-") || !token.includes("/")) continue;
221007
+ try {
221008
+ containedPath(root, token);
221009
+ } catch {
221010
+ escaped = token;
221011
+ break;
221012
+ }
221013
+ }
221014
+ if (escaped !== void 0) add("ac.verify_command_unsafe", at, `el token "${escaped}" escapa de la raiz del paquete`);
221015
+ else {
221016
+ const token = argv.slice(1).find((item) => !item.startsWith("-") && item.includes("/"));
221017
+ if (token === void 0) add("ac.verify_outside_test_plan", at, "el comando no apunta a ningun fichero o directorio verificable");
221018
+ else {
221019
+ const target = token.replace(/^\.\//, "");
221020
+ if (!vocabulary.verifyPrefixes.some((prefix) => target.startsWith(prefix))) add("ac.verify_outside_test_plan", at, `"${target}" fuera del test plan declarado`);
221021
+ 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`);
221022
+ const destination = join(root, target);
221023
+ const isTest = /(^|\/)test\//.test(target) || /\.test\./.test(target);
221024
+ const exempt = /(^|\/)scripts\//.test(target);
221025
+ if (isTest && !exempt && fs.exists(destination) && fs.isDirectory(destination) === false) {
221026
+ if ((fs.read(destination) ?? "").match(ASSERTION) === null) add("ac.verify_stub", at, `el destino "${target}" no tiene ninguna asercion: el verify no mide nada`);
221027
+ }
221028
+ }
221029
+ }
221030
+ }
220519
221031
  }
220520
221032
  }
220521
221033
  const falsifier = record$1(ac["falsifier"]);
220522
221034
  if (Object.keys(falsifier).length > 0) {
220523
221035
  const mutation = str$2(falsifier["mutation"]);
220524
221036
  const expect = str$2(falsifier["expect"]);
220525
- const script = str$2(falsifier["script"]);
220526
221037
  if (mutation.length < thresholds.minFieldChars) add("ac.falsifier_thin", at, "falsifier.mutation insuficiente");
220527
221038
  else if (expect.length < thresholds.minFieldChars) add("ac.falsifier_thin", at, "falsifier.expect insuficiente");
220528
- else if (script === "" && isDestructive(mutation)) add("ac.falsifier_not_reversible", at, `"${mutation}" necesita falsifier.script con apply y restore`);
220529
221039
  else withFalsifier.add(taskId);
221040
+ const normalizedMutation = normalize$1(mutation);
221041
+ const verb = stateVerbs.find((entry) => new RegExp(`\\b${escapeRegExp$1(entry)}[a-z]{0,4}\\b`).test(normalizedMutation));
221042
+ const object = stateObjects.find((entry) => new RegExp(`\\b${escapeRegExp$1(entry)}s?\\b`).test(normalizedMutation));
221043
+ const reversible = str$2(falsifier["script"]).trim() !== "" || str$2(falsifier["restore"]).trim() !== "";
221044
+ 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`);
220530
221045
  }
220531
221046
  }
220532
221047
  }
@@ -220572,6 +221087,19 @@ function runWaveGate(fs, root, cfg) {
220572
221087
  }
220573
221088
  });
220574
221089
  block("hygiene", () => {
221090
+ const wavesDir = join(root, cfg.layout.waves);
221091
+ for (const wave of cfg.waves) {
221092
+ const dir = fs.list(wavesDir).find((entry) => entry === wave || entry.startsWith(`${wave}-`));
221093
+ if (dir === void 0) continue;
221094
+ const contracted = contractedSeats(fs, join(wavesDir, dir, WAVE_CONTRACTS_FILE));
221095
+ if (contracted === void 0) continue;
221096
+ for (const round of WAVE_ROUNDS) for (const role of waveRoundSeats(cfg.roles, round)) {
221097
+ const path = `${cfg.layout.waves}/${dir}/${WAVE_ROUND_DIRS[round]}/${role}.md`;
221098
+ if (!fs.exists(join(root, path))) continue;
221099
+ if (contracted.some((seat) => seat.round === round && seat.role === role)) continue;
221100
+ add("contracts.uncontracted", path, `el asiento ${role} de ${round} entrego sin contrato de WaveContract`);
221101
+ }
221102
+ }
220575
221103
  const secrets = cfg.secrets.filter((secret) => secret.length >= 6);
220576
221104
  if (secrets.length === 0) return;
220577
221105
  const files = [...walk(fs, join(root, cfg.layout.waves), (path) => /\.(md|json|txt)$/.test(path)), ...walk(fs, join(root, cfg.layout.backlog), (path) => /\.(md|json|txt)$/.test(path))];
@@ -220588,14 +221116,18 @@ function runWaveGate(fs, root, cfg) {
220588
221116
  waves: cfg.waves.length,
220589
221117
  epics: epics.length,
220590
221118
  tasks: tasks.length,
220591
- ac: totalAc
221119
+ ac: totalAc,
221120
+ notRun: NOT_RUN_BLOCKS
220592
221121
  }
220593
221122
  };
220594
221123
  }
220595
- var DECISION_FILE, AC_FIELDS, normalize$1, relative$1;
221124
+ var DECISION_FILE, BRIEF_TEMPLATE$1, 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;
220596
221125
  var init_checks = __esmMin((() => {
220597
221126
  init_config$6();
221127
+ init_seats();
221128
+ init_runner();
220598
221129
  DECISION_FILE = "06-DECISION.md";
221130
+ BRIEF_TEMPLATE$1 = "workflow/templates/brief.md";
220599
221131
  AC_FIELDS = [
220600
221132
  "id",
220601
221133
  "given",
@@ -220606,8 +221138,24 @@ var init_checks = __esmMin((() => {
220606
221138
  "verify",
220607
221139
  "falsifier"
220608
221140
  ];
221141
+ OPERATOR_WITH_NUMBER = /[=<>≥≤]\s*\d|\b(?:mayor|menor|igual|al menos|como maximo|como minimo)\b[^0-9]{0,20}\d/;
221142
+ EXACT_VALUE = /\b\d+(?:[.,]\d+)?\s+(?:exacto|exacta|exactos|exactas|fijo|fija|justo|justa)\b/;
221143
+ ASSERTION = /\bassert\b|\bexpect\s*\(|\bit\s*\(|\btest\s*\(|\bfailures\b|process\.exit\s*\(\s*(?!0\b)/g;
221144
+ escapeRegExp$1 = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
221145
+ NOT_RUN_BLOCKS = [{
221146
+ block: "regression",
221147
+ closedBy: "oracle"
221148
+ }, {
221149
+ block: "schemas",
221150
+ closedBy: "oracle"
221151
+ }];
220609
221152
  normalize$1 = (value) => value.normalize("NFD").replaceAll(/[\u0300-\u036F]/g, "").toLowerCase();
220610
221153
  relative$1 = (root, path) => path.startsWith(root) ? path.slice(root.length).replaceAll("\\", "/").replace(/^\/+/, "") : path;
221154
+ DECISION_SEPARATOR = /^:?-{2,}:?$/;
221155
+ DECISION_PROPOSAL = /^p\d+$/;
221156
+ DECISION_LEADING_NUMBER = /^[+-]?\d+(?:[.,]\d+)?/;
221157
+ DECISION_JUDGE = /^J\d+$/;
221158
+ DECISION_SIGNED_MARGIN = /^([+-]?\d+(?:[.,]\d+)?)$/;
220611
221159
  }));
220612
221160
  // ../../packages/agent-core-v2/src/features/wave/tools/gate/gateRunner.ts
220613
221161
  function runWaveGateForRoot(input) {
@@ -220629,6 +221177,7 @@ function runWaveGateForRoot(input) {
220629
221177
  };
220630
221178
  const lines = [`GATE — ${report.ok ? "verde" : "con hallazgos"}`, ""];
220631
221179
  for (const block of report.blocks) lines.push(`${block.ok ? "OK " : "FAIL"} ${block.name}`);
221180
+ for (const entry of report.summary.notRun) lines.push(`NO EJECUTADO ${entry.block} — cerrado por ${entry.closedBy}`);
220632
221181
  if (report.findings.length > 0) {
220633
221182
  lines.push("", `PENDIENTE: ${report.findings.length} hallazgo(s)`, "");
220634
221183
  for (const finding of report.findings) lines.push(` - ${finding.code}${finding.path === null ? "" : ` ${finding.path}`} — ${finding.message}`);
@@ -220680,175 +221229,328 @@ var init_gateTool = __esmMin((() => {
220680
221229
  };
220681
221230
  WaveGateTool = __decorate([__decorateParam(0, ISessionContext)], WaveGateTool);
220682
221231
  }));
220683
- // ../../packages/agent-core-v2/src/features/wave/tools/verify/verify.ts
220684
- var WaveVerifyToolInputSchema, IWaveVerifyTool;
220685
- var init_verify$1 = __esmMin((() => {
221232
+ // ../../packages/agent-core-v2/src/features/wave/tools/open/open.ts
221233
+ var WaveOpenToolInputSchema, IWaveOpenTool;
221234
+ var init_open$1 = __esmMin((() => {
220686
221235
  init_zod$1();
220687
221236
  init_instantiation();
220688
- WaveVerifyToolInputSchema = object$1({
220689
- task: string().min(3),
221237
+ WaveOpenToolInputSchema = object$1({
221238
+ name: string().min(2),
221239
+ id: string().optional(),
220690
221240
  root: string().optional()
220691
221241
  }).strict();
220692
- IWaveVerifyTool = createDecorator("waveVerifyTool");
221242
+ IWaveOpenTool = createDecorator("waveOpenTool");
220693
221243
  }));
220694
- // ../../packages/agent-core-v2/src/features/wave/core/verify/runner.ts
220695
- function splitCommand(command) {
220696
- const tokens = [];
220697
- let current = "";
220698
- let quote;
220699
- for (const char of command) {
220700
- if (quote !== void 0) {
220701
- if (char === quote) quote = void 0;
220702
- else current += char;
220703
- continue;
220704
- }
220705
- if (char === "\"" || char === "'") {
220706
- quote = char;
220707
- continue;
220708
- }
220709
- if (SHELL_METACHARACTERS.has(char)) throw new Error(`metacaracter de shell prohibido en: ${command}`);
220710
- if (char === " " || char === " ") {
220711
- if (current !== "") {
220712
- tokens.push(current);
220713
- current = "";
220714
- }
220715
- continue;
220716
- }
220717
- current += char;
220718
- }
220719
- if (quote !== void 0) throw new Error(`comillas sin cerrar en: ${command}`);
220720
- if (current !== "") tokens.push(current);
220721
- if (tokens.length === 0) throw new Error("comando vacio");
220722
- return tokens;
221244
+ // ../../packages/agent-core-v2/src/features/wave/tools/open/openRunner.ts
221245
+ function briefTemplate(root) {
221246
+ const fs = nodeWaveFs;
221247
+ const local = join(root, BRIEF_TEMPLATE);
221248
+ if (fs.exists(local)) return { file: local };
221249
+ if (fs.isDirectory(join(root, "workflow"))) return { missing: BRIEF_TEMPLATE };
221250
+ return fs.exists(BUNDLED_BRIEF_TEMPLATE) ? { file: BUNDLED_BRIEF_TEMPLATE } : { missing: BRIEF_TEMPLATE };
220723
221251
  }
220724
- function containPaths(argv, root) {
220725
- for (const token of argv) {
220726
- if (token.startsWith("-")) continue;
220727
- if (!token.includes("/") && !/\.(mjs|cjs|js|ts|sh)$/.test(token)) continue;
220728
- containedPath(root, token);
220729
- }
221252
+ function nextEpic(backlogDir) {
221253
+ 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);
221254
+ const next = numbers.length > 0 ? Math.max(...numbers) + 1 : 1;
221255
+ return `E${String(next).padStart(2, "0")}`;
220730
221256
  }
220731
- function runCommand$2(command, options) {
220732
- let argv;
221257
+ function slugify(name) {
221258
+ return name.normalize("NFD").replaceAll(/[\u0300-\u036F]/g, "").toLowerCase().replaceAll(/[^a-z0-9-]+/g, "-").replaceAll(/^-+|-+$/g, "");
221259
+ }
221260
+ function runWaveOpenForRoot(input) {
221261
+ const fs = nodeWaveFs;
221262
+ const configFile = join(input.root, "workflow.config.json");
221263
+ const rawConfig = readJson$2(fs, configFile);
221264
+ if (rawConfig === void 0) return {
221265
+ output: `no hay workflow.config.json en ${input.root}`,
221266
+ isError: true
221267
+ };
221268
+ const layout = asRecord$2(asRecord$2(rawConfig)["layout"]);
221269
+ const wavesRel = typeof layout["waves"] === "string" ? layout["waves"] : "design/waves";
221270
+ const backlogRel = typeof layout["backlog"] === "string" ? layout["backlog"] : "backlog";
221271
+ const minimum = makeWaveConfig(rawConfig).thresholds.minBriefSections;
221272
+ let wavesDir;
221273
+ let backlogDir;
220733
221274
  try {
220734
- argv = splitCommand(command);
220735
- const binary = (argv[0] ?? "").replace(/\.exe$/i, "");
220736
- const allowed = options.allowBinaries.map((item) => item.replace(/\.exe$/i, ""));
220737
- if (!allowed.includes(binary)) throw new Error(`binario no permitido: ${binary} (permitidos: ${allowed.join(", ")})`);
220738
- containPaths(argv, options.root);
221275
+ wavesDir = containedPath(input.root, wavesRel);
221276
+ backlogDir = containedPath(input.root, backlogRel);
220739
221277
  } catch (error) {
220740
221278
  return {
220741
- ok: false,
220742
- output: `rechazado: ${error instanceof Error ? error.message : String(error)}`,
220743
- rejected: true
221279
+ output: error instanceof Error ? error.message : String(error),
221280
+ isError: true
220744
221281
  };
220745
221282
  }
220746
- const result = spawnSync(argv[0] ?? "", argv.slice(1), {
220747
- cwd: options.cwd ?? options.root,
220748
- encoding: "utf8",
220749
- timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS$1,
220750
- stdio: "pipe",
220751
- shell: false
220752
- });
220753
- const output = `${result.stdout ?? ""}${result.stderr ?? ""}${result.error === void 0 ? "" : result.error.message}`.replaceAll(/\s+/g, " ").trim().slice(0, 300);
220754
- if (result.error !== void 0) return {
220755
- ok: false,
220756
- output: `no se pudo ejecutar: ${output}`,
220757
- rejected: false
221283
+ const template = briefTemplate(input.root);
221284
+ if (template.file === void 0) return {
221285
+ output: `falta ${template.missing ?? BRIEF_TEMPLATE}: no se genera un brief sin la plantilla unica`,
221286
+ isError: true
220758
221287
  };
220759
- return {
220760
- ok: result.status === 0,
220761
- output,
220762
- rejected: false
221288
+ const source = fs.read(template.file);
221289
+ if (source === void 0) return {
221290
+ output: `no se pudo leer ${template.file}`,
221291
+ isError: true
220763
221292
  };
220764
- }
220765
- function evaluateMutant(ac, verifyCommand, options) {
220766
- const script = asText$1(asRecord$2(ac["falsifier"])["script"]);
220767
- if (script === "") return {
220768
- state: "declarado",
220769
- detail: "sin falsifier.script: el AC queda declarado y cuenta como FALLO"
221293
+ 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));
221294
+ const next = input.id ?? `W${existing.length > 0 ? Math.max(...existing) + 1 : 0}`;
221295
+ if (!/^W\d{1,2}$/.test(next)) return {
221296
+ output: `id de oleada invalido "${next}"`,
221297
+ isError: true
220770
221298
  };
220771
- const apply = runCommand$2(`${script} apply`, options);
220772
- if (apply.rejected) return {
220773
- state: "rechazado",
220774
- detail: `apply rechazado: ${apply.output}`
221299
+ const slug = slugify(input.name);
221300
+ if (slug === "") return {
221301
+ output: "el nombre de la oleada queda vacio al normalizarlo",
221302
+ isError: true
220775
221303
  };
220776
- if (!apply.ok) return {
220777
- state: "error",
220778
- detail: `apply fallo: ${apply.output}`
221304
+ if (fs.list(wavesDir).some((name) => name === next || name.startsWith(`${next}-`))) return {
221305
+ output: `la oleada ${next} ya existe`,
221306
+ isError: true
220779
221307
  };
220780
- const mutated = runCommand$2(verifyCommand, options);
220781
- const restore = runCommand$2(`${script} restore`, options);
220782
- const after = runCommand$2(verifyCommand, options);
220783
- if (restore.rejected || !restore.ok) return {
220784
- state: "error",
220785
- detail: `restore fallo, el arbol puede estar sucio: ${restore.output}`
221308
+ const dir = join(wavesDir, `${next}-${slug}`);
221309
+ const brief = source.replaceAll("{{WAVE}}", next).replaceAll("{{NAME}}", slug).replaceAll("{{NEXT_EPIC}}", nextEpic(backlogDir));
221310
+ for (const sub of SUBDIRS) fs.mkdir(join(dir, sub));
221311
+ fs.write(join(dir, "00-brief.md"), brief);
221312
+ const declared = asArray$2(asRecord$2(rawConfig)["waves"]).map(String);
221313
+ if (!declared.includes(next)) writeJson(fs, configFile, {
221314
+ ...asRecord$2(rawConfig),
221315
+ waves: [...declared, next].toSorted()
221316
+ });
221317
+ return { output: [
221318
+ `oleada creada: ${next}-${slug}`,
221319
+ ` brief: ${wavesRel}/${next}-${slug}/00-brief.md (rellena las ${minimum} secciones antes de lanzar asientos)`,
221320
+ ` config: ${next} declarada en workflow.config.json (el gate la exige desde ahora)`
221321
+ ].join("\n") };
221322
+ }
221323
+ var SUBDIRS, BRIEF_TEMPLATE, BUNDLED_BRIEF_TEMPLATE;
221324
+ var init_openRunner = __esmMin((() => {
221325
+ init_config$6();
221326
+ init_fsJson();
221327
+ init_nodeFs();
221328
+ SUBDIRS = [
221329
+ "01-proposals",
221330
+ "02-defenses",
221331
+ "03-attacks",
221332
+ "04-verdicts",
221333
+ "05-refined"
221334
+ ];
221335
+ BRIEF_TEMPLATE = "workflow/templates/brief.md";
221336
+ BUNDLED_BRIEF_TEMPLATE = resolve(import.meta.dirname, "../../../../../../../workflow/templates/brief.md");
221337
+ }));
221338
+ // ../../packages/agent-core-v2/src/features/wave/tools/open/open.md?raw
221339
+ var open_default;
221340
+ var init_open = __esmMin((() => {
221341
+ open_default = "Open a wave: create its artifact tree and a brief skeleton, and declare the wave in `workflow.config.json`.\n\nThe brief starts with the seven mandatory sections and nothing else — a brief that already contains the answer makes the twelve seats theatre. Fill it before launching any seat; the gate rejects a brief with fewer than seven sections.\n\nOpening a wave also declares it in the config, so the package gate will require its artifacts from then on.\n";
221342
+ }));
221343
+ // ../../packages/agent-core-v2/src/features/wave/tools/open/openTool.ts
221344
+ var WaveOpenTool;
221345
+ var init_openTool = __esmMin((() => {
221346
+ init_sessionContext();
221347
+ init_input_schema();
221348
+ init_open$1();
221349
+ init_openRunner();
221350
+ init_open();
221351
+ init_decorateParam();
221352
+ init_decorate();
221353
+ WaveOpenTool = class WaveOpenTool {
221354
+ sessionContext;
221355
+ name = "WaveOpen";
221356
+ description = open_default;
221357
+ parameters = toInputJsonSchema(WaveOpenToolInputSchema);
221358
+ constructor(sessionContext) {
221359
+ this.sessionContext = sessionContext;
221360
+ }
221361
+ resolveExecution(args) {
221362
+ return {
221363
+ description: `Opening wave ${args.name}`,
221364
+ approvalRule: this.name,
221365
+ execute: () => Promise.resolve(runWaveOpenForRoot({
221366
+ root: args.root ?? this.sessionContext.cwd,
221367
+ name: args.name,
221368
+ id: args.id
221369
+ }))
221370
+ };
221371
+ }
220786
221372
  };
220787
- if (mutated.ok) return {
220788
- state: "sobrevive",
220789
- detail: "el verify pasa con la mutacion aplicada: el AC no muerde"
221373
+ WaveOpenTool = __decorate([__decorateParam(0, ISessionContext)], WaveOpenTool);
221374
+ }));
221375
+ // ../../packages/agent-core-v2/src/features/wave/tools/submit/submit.ts
221376
+ var WaveSubmitToolInputSchema, IWaveSubmitTool;
221377
+ var init_submit$1 = __esmMin((() => {
221378
+ init_zod$1();
221379
+ init_instantiation();
221380
+ WaveSubmitToolInputSchema = object$1({
221381
+ wave: string().min(2),
221382
+ round: _enum([
221383
+ "propose",
221384
+ "defend",
221385
+ "attack",
221386
+ "judge",
221387
+ "refine",
221388
+ "audit"
221389
+ ]),
221390
+ role: string().min(2),
221391
+ artifact: string().min(1),
221392
+ ticket: string().optional(),
221393
+ reason: string().optional(),
221394
+ replace: boolean$1().optional(),
221395
+ root: string().optional()
221396
+ }).strict();
221397
+ IWaveSubmitTool = createDecorator("waveSubmitTool");
221398
+ }));
221399
+ // ../../packages/agent-core-v2/src/features/wave/tools/submit/submitRunner.ts
221400
+ function findWaveDir(root, wavesRel, wave) {
221401
+ const fs = nodeWaveFs;
221402
+ const wavesDir = containedPath(root, wavesRel);
221403
+ const name = fs.list(wavesDir).filter((entry) => fs.isDirectory(join(wavesDir, entry))).find((entry) => entry === wave || entry.startsWith(`${wave}-`));
221404
+ return name === void 0 ? void 0 : join(wavesDir, name);
221405
+ }
221406
+ function runWaveSubmitForRoot(input) {
221407
+ const fs = nodeWaveFs;
221408
+ const rawConfig = readJson$2(fs, join(input.root, "workflow.config.json"));
221409
+ if (rawConfig === void 0) return {
221410
+ output: `no hay workflow.config.json en ${input.root}`,
221411
+ isError: true
220790
221412
  };
220791
- if (!after.ok) return {
220792
- state: "error",
220793
- detail: "el verify no vuelve a verde tras restaurar"
221413
+ const config = makeWaveConfig(rawConfig);
221414
+ const wavesRel = config.layout.waves;
221415
+ const seats = waveRoundSeats(config.roles, input.round);
221416
+ if (!seats.includes(input.role)) return {
221417
+ output: `seats.unknown_seat: el rol "${input.role}" no pertenece a la ronda ${input.round} (esperado ${seats.join(", ")})`,
221418
+ isError: true
220794
221419
  };
220795
- return {
220796
- state: "muerto",
220797
- detail: "rojo con la mutacion, verde tras restaurar"
221420
+ let base;
221421
+ try {
221422
+ base = findWaveDir(input.root, wavesRel, input.wave);
221423
+ } catch (error) {
221424
+ return {
221425
+ output: error instanceof Error ? error.message : String(error),
221426
+ isError: true
221427
+ };
221428
+ }
221429
+ if (base === void 0) return {
221430
+ output: `no existe la oleada ${input.wave} en ${wavesRel}`,
221431
+ isError: true
220798
221432
  };
220799
- }
220800
- function verifyTask(fs, root, cfg, taskId, options) {
220801
- const tasksDir = containedPath(root, cfg.layout.backlog);
220802
- const file = walk$1(fs, join(tasksDir, "tasks"), (path) => path.endsWith(`${taskId}.json`))[0];
220803
- if (file === void 0) throw new Error(`no encuentro la task ${taskId} en ${cfg.layout.backlog}/tasks/`);
220804
- const task = asRecord$2(readJson$2(fs, file));
220805
- const runOptions = {
220806
- root,
220807
- allowBinaries: cfg.vocabulary.verifyCommands,
220808
- cwd: options?.cwd,
220809
- timeoutMs: options?.timeoutMs
221433
+ const dirName = WAVE_ROUND_DIRS[input.round];
221434
+ const dir = join(base, dirName);
221435
+ if (!fs.isDirectory(dir)) return {
221436
+ output: `falta el directorio ${dirName} en la oleada ${input.wave}`,
221437
+ isError: true
220810
221438
  };
220811
- const acs = [];
220812
- let declared = 0;
220813
- for (const raw of asArray$2(task["ac"])) {
220814
- const ac = asRecord$2(raw);
220815
- const verifyCommand = asText$1(ac["verify"]);
220816
- const verify = runCommand$2(verifyCommand, runOptions);
220817
- const mutant = evaluateMutant(ac, verifyCommand, runOptions);
220818
- if (mutant.state === "declarado") declared++;
220819
- const ok = verify.ok && mutant.state === "muerto";
220820
- acs.push({
220821
- acId: asText$1(ac["id"]),
220822
- verify,
220823
- mutant,
220824
- ok
220825
- });
221439
+ const seatsDir = join(base, WAVE_SEATS_DIR);
221440
+ if (fs.isDirectory(seatsDir) && fs.list(seatsDir).length > 0) {
221441
+ const presented = (input.ticket ?? "").trim();
221442
+ if (presented === "") return {
221443
+ output: `seats.foreign_replace: el asiento ${input.role} no presento el ticket que emitio la ronda`,
221444
+ isError: true
221445
+ };
221446
+ const stored = (fs.read(join(seatsDir, input.role)) ?? "").trim();
221447
+ if (stored === "" || stored !== seatTicketHash(presented)) return {
221448
+ output: `seats.foreign_replace: el ticket presentado no es el del asiento ${input.role}`,
221449
+ isError: true
221450
+ };
221451
+ if (input.replace === true && (input.reason ?? "").trim() === "") return {
221452
+ output: `seats.replace_without_reason: reescribir el artefacto del asiento ${input.role} exige un motivo no vacio`,
221453
+ isError: true
221454
+ };
220826
221455
  }
220827
- return {
220828
- taskId,
220829
- acs,
220830
- declared,
220831
- ok: acs.length > 0 && acs.every((ac) => ac.ok)
221456
+ const file = join(dir, `${input.role}.md`);
221457
+ if (fs.exists(file) && input.replace !== true) return {
221458
+ output: `el asiento ${input.role} ya entrego su artefacto; un asiento escribe una vez (usa replace solo para relanzar un fallo)`,
221459
+ isError: true
220832
221460
  };
221461
+ if (input.artifact.trim() === "") return {
221462
+ output: "el artefacto esta vacio: un asiento que no escribe, fallo",
221463
+ isError: true
221464
+ };
221465
+ fs.write(file, input.artifact.endsWith("\n") ? input.artifact : `${input.artifact}\n`);
221466
+ return { output: `escrito ${wavesRel}/${base.split("/").pop()}/${dirName}/${input.role}.md` };
220833
221467
  }
220834
- var SHELL_METACHARACTERS, DEFAULT_TIMEOUT_MS$1;
220835
- var init_runner = __esmMin((() => {
221468
+ var init_submitRunner = __esmMin((() => {
220836
221469
  init_config$6();
220837
221470
  init_fsJson();
220838
- SHELL_METACHARACTERS = /* @__PURE__ */ new Set([
220839
- "|",
220840
- "&",
220841
- ";",
220842
- "<",
220843
- ">",
220844
- "`",
220845
- "$",
220846
- "\n",
220847
- "\r"
220848
- ]);
220849
- DEFAULT_TIMEOUT_MS$1 = 6e5;
221471
+ init_nodeFs();
221472
+ init_seats();
221473
+ }));
221474
+ // ../../packages/agent-core-v2/src/features/wave/tools/submit/submit.md?raw
221475
+ var submit_default;
221476
+ var init_submit = __esmMin((() => {
221477
+ 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";
221478
+ }));
221479
+ // ../../packages/agent-core-v2/src/features/wave/tools/submit/submitTool.ts
221480
+ var WaveSubmitTool;
221481
+ var init_submitTool = __esmMin((() => {
221482
+ init_sessionContext();
221483
+ init_input_schema();
221484
+ init_submit$1();
221485
+ init_submitRunner();
221486
+ init_submit();
221487
+ init_decorateParam();
221488
+ init_decorate();
221489
+ WaveSubmitTool = class WaveSubmitTool {
221490
+ sessionContext;
221491
+ name = "WaveSubmit";
221492
+ description = submit_default;
221493
+ parameters = toInputJsonSchema(WaveSubmitToolInputSchema);
221494
+ constructor(sessionContext) {
221495
+ this.sessionContext = sessionContext;
221496
+ }
221497
+ resolveExecution(args) {
221498
+ return {
221499
+ description: `Submitting ${args.role}`,
221500
+ approvalRule: this.name,
221501
+ execute: () => Promise.resolve(runWaveSubmitForRoot({
221502
+ root: args.root ?? this.sessionContext.cwd,
221503
+ wave: args.wave,
221504
+ round: args.round,
221505
+ role: args.role,
221506
+ artifact: args.artifact,
221507
+ ticket: args.ticket,
221508
+ reason: args.reason,
221509
+ replace: args.replace
221510
+ }))
221511
+ };
221512
+ }
221513
+ };
221514
+ WaveSubmitTool = __decorate([__decorateParam(0, ISessionContext)], WaveSubmitTool);
221515
+ }));
221516
+ // ../../packages/agent-core-v2/src/features/wave/tools/verify/verify.ts
221517
+ var WaveVerifyToolInputSchema, IWaveVerifyTool;
221518
+ var init_verify$1 = __esmMin((() => {
221519
+ init_zod$1();
221520
+ init_instantiation();
221521
+ WaveVerifyToolInputSchema = object$1({
221522
+ task: string().min(3),
221523
+ root: string().optional(),
221524
+ ac: string().min(3).optional(),
221525
+ dryRun: boolean$1().optional(),
221526
+ allowDeclared: boolean$1().optional()
221527
+ }).strict();
221528
+ IWaveVerifyTool = createDecorator("waveVerifyTool");
220850
221529
  }));
220851
221530
  // ../../packages/agent-core-v2/src/features/wave/tools/verify/verifyRunner.ts
221531
+ function failure$1(error) {
221532
+ return {
221533
+ output: error instanceof Error ? error.message : String(error),
221534
+ isError: true
221535
+ };
221536
+ }
221537
+ function runDry(root, config, input) {
221538
+ let selected;
221539
+ try {
221540
+ selected = selectTaskCriteria(nodeWaveFs, root, config, input.task, input.ac);
221541
+ } catch (error) {
221542
+ return failure$1(error);
221543
+ }
221544
+ const lines = [`TASK ${selected.taskId} · dryRun: no se ejecuta ningun comando`, ""];
221545
+ for (const ac of selected.criteria) {
221546
+ const falsifier = asRecord$2(ac["falsifier"]);
221547
+ lines.push(`dry ${asText$1(ac["id"])}`);
221548
+ lines.push(` verify: ${asText$1(ac["verify"])}`);
221549
+ lines.push(` mutacion: ${asText$1(falsifier["mutation"])}`);
221550
+ }
221551
+ lines.push("", `criterios ${selected.criteria.length} · comandos 0`);
221552
+ return { output: lines.join("\n") };
221553
+ }
220852
221554
  function runWaveVerifyForRoot(input) {
220853
221555
  const root = resolve(input.root);
220854
221556
  const config = readWaveConfig(nodeWaveFs, root);
@@ -220856,7 +221558,16 @@ function runWaveVerifyForRoot(input) {
220856
221558
  output: `no hay workflow.config.json en ${root}`,
220857
221559
  isError: true
220858
221560
  };
220859
- const result = verifyTask(nodeWaveFs, root, config, input.task);
221561
+ if (input.dryRun === true) return runDry(root, config, input);
221562
+ let result;
221563
+ try {
221564
+ result = verifyTask(nodeWaveFs, root, config, input.task, {
221565
+ ac: input.ac,
221566
+ allowDeclared: input.allowDeclared
221567
+ });
221568
+ } catch (error) {
221569
+ return failure$1(error);
221570
+ }
220860
221571
  const lines = [`TASK ${result.taskId}`, ""];
220861
221572
  for (const ac of result.acs) {
220862
221573
  lines.push(`${ac.ok ? "ok " : "FAIL"} ${ac.acId} verify ${ac.verify.ok ? "verde" : "rojo"} mutante ${ac.mutant.state}`);
@@ -220872,13 +221583,14 @@ function runWaveVerifyForRoot(input) {
220872
221583
  }
220873
221584
  var init_verifyRunner = __esmMin((() => {
220874
221585
  init_config$6();
221586
+ init_fsJson();
220875
221587
  init_nodeFs();
220876
221588
  init_runner();
220877
221589
  }));
220878
221590
  // ../../packages/agent-core-v2/src/features/wave/tools/verify/verify.md?raw
220879
221591
  var verify_default;
220880
221592
  var init_verify = __esmMin((() => {
220881
- 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";
221593
+ 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";
220882
221594
  }));
220883
221595
  // ../../packages/agent-core-v2/src/features/wave/tools/verify/verifyTool.ts
220884
221596
  var WaveVerifyTool;
@@ -220904,7 +221616,10 @@ var init_verifyTool = __esmMin((() => {
220904
221616
  approvalRule: this.name,
220905
221617
  execute: () => Promise.resolve(runWaveVerifyForRoot({
220906
221618
  root: args.root ?? this.sessionContext.cwd,
220907
- task: args.task
221619
+ task: args.task,
221620
+ ac: args.ac,
221621
+ dryRun: args.dryRun,
221622
+ allowDeclared: args.allowDeclared
220908
221623
  }))
220909
221624
  };
220910
221625
  }
@@ -220912,28 +221627,35 @@ var init_verifyTool = __esmMin((() => {
220912
221627
  WaveVerifyTool = __decorate([__decorateParam(0, ISessionContext)], WaveVerifyTool);
220913
221628
  }));
220914
221629
  // ../../packages/agent-core-v2/src/features/wave/waveFeature.ts
221630
+ function profileHolds(accessor, profile) {
221631
+ return accessor.get(IAgentProfileService).data().profileName === profile;
221632
+ }
220915
221633
  function isWaveFeatureAssembled(flags) {
220916
221634
  return assembledOverrideForTests ?? assembledFlagServices.has(flags);
220917
221635
  }
220918
221636
  var WAVE_TOOL_CONTRIBUTIONS, WaveFeature, assembledFlagServices, assembledOverrideForTests;
220919
221637
  var init_waveFeature = __esmMin((() => {
221638
+ init_instantiation();
221639
+ init_profile$1();
220920
221640
  init_flag$7();
220921
221641
  init_feature();
220922
221642
  init_featureRegistry();
220923
- init_wave$3();
221643
+ init_waveService();
221644
+ init_waveMode();
220924
221645
  init_seatProfile();
221646
+ init_contract$4();
221647
+ init_contractTool();
220925
221648
  init_decide$1();
220926
221649
  init_decideTool();
220927
221650
  init_gate$1();
221651
+ init_gateTool();
220928
221652
  init_open$1();
220929
221653
  init_openTool();
220930
- init_round$1();
220931
- init_roundTool();
220932
221654
  init_submit$1();
220933
221655
  init_submitTool();
220934
- init_gateTool();
220935
221656
  init_verify$1();
220936
221657
  init_verifyTool();
221658
+ init_wave$3();
220937
221659
  init_decorateParam();
220938
221660
  init_decorate();
220939
221661
  WAVE_TOOL_CONTRIBUTIONS = [
@@ -220957,15 +221679,15 @@ var init_waveFeature = __esmMin((() => {
220957
221679
  ctor: WaveOpenTool,
220958
221680
  name: "WaveOpen"
220959
221681
  },
221682
+ {
221683
+ id: IWaveContractTool,
221684
+ ctor: WaveContractTool,
221685
+ name: "WaveContract"
221686
+ },
220960
221687
  {
220961
221688
  id: IWaveSubmitTool,
220962
221689
  ctor: WaveSubmitTool,
220963
221690
  name: "WaveSubmit"
220964
- },
220965
- {
220966
- id: IWaveRoundTool,
220967
- ctor: WaveRoundTool,
220968
- name: "WaveRound"
220969
221691
  }
220970
221692
  ];
220971
221693
  WaveFeature = class WaveFeature extends Feature {
@@ -220977,10 +221699,15 @@ var init_waveFeature = __esmMin((() => {
220977
221699
  this.onDispose(() => {
220978
221700
  assembledFlagServices.delete(flags);
220979
221701
  });
220980
- for (const tool of WAVE_TOOL_CONTRIBUTIONS) this.contributeTool(tool.id, tool.ctor, {
220981
- name: tool.name,
220982
- domain: WAVE_TOOL_DOMAIN
220983
- });
221702
+ this.contributeAgentService(IAgentWaveService, AgentWaveService, { activation: 0 });
221703
+ for (const tool of WAVE_TOOL_CONTRIBUTIONS) {
221704
+ const profile = tool.name === "WaveSubmit" ? WAVE_SEAT_PROFILE : WAVE_DIRECTOR_PROFILE;
221705
+ this.contributeTool(tool.id, tool.ctor, {
221706
+ name: tool.name,
221707
+ domain: WAVE_TOOL_DOMAIN,
221708
+ when: (accessor) => profileHolds(accessor, profile)
221709
+ });
221710
+ }
220984
221711
  this.contributeProfiles([WAVE_SEAT_PROFILE_DEF]);
220985
221712
  }
220986
221713
  };
@@ -220995,7 +221722,7 @@ var init_flag$2 = __esmMin((() => {
220995
221722
  init_wave$3();
220996
221723
  init_waveFeature();
220997
221724
  waveFlag = {
220998
- id: WAVE_FLAG_ID$1,
221725
+ id: WAVE_FLAG_ID,
220999
221726
  title: "Wave workflow",
221000
221727
  description: "Enable the wave workflow: adversarial design rounds with isolated seats, the package gate, and task verification tools.",
221001
221728
  env: WAVE_FLAG_ENV,
@@ -221005,6 +221732,27 @@ var init_flag$2 = __esmMin((() => {
221005
221732
  };
221006
221733
  registerFlagDefinition(waveFlag);
221007
221734
  }));
221735
+ var init_round = __esmMin((() => {
221736
+ init_zod$1();
221737
+ init_instantiation();
221738
+ object$1({
221739
+ wave: string().min(2),
221740
+ round: _enum([
221741
+ "propose",
221742
+ "defend",
221743
+ "attack",
221744
+ "judge",
221745
+ "refine",
221746
+ "audit"
221747
+ ]),
221748
+ root: string().optional()
221749
+ }).strict();
221750
+ createDecorator("waveRoundTool");
221751
+ }));
221752
+ // ../../packages/agent-core-v2/src/features/wave/tools/round/roundRunner.ts
221753
+ var init_roundRunner = __esmMin((() => {
221754
+ init_prompts$2();
221755
+ }));
221008
221756
  // ../../packages/agent-core-v2/src/agent/usage/cacheProbe.ts
221009
221757
  var IAgentCacheProbeService;
221010
221758
  var init_cacheProbe = __esmMin((() => {
@@ -223569,6 +224317,7 @@ var AGENT_TOOLS, CODER_TOOLS, EXPLORE_TOOLS, CODER_ROLE;
223569
224317
  var init_profiles = __esmMin((() => {
223570
224318
  init_gitContext();
223571
224319
  init_contribution();
224320
+ init_wave$3();
223572
224321
  init_profile_shared();
223573
224322
  init_explore_overlay();
223574
224323
  AGENT_TOOLS = [
@@ -223603,6 +224352,8 @@ var init_profiles = __esmMin((() => {
223603
224352
  "TowerStatus",
223604
224353
  "TowerTeardown",
223605
224354
  "WaveOpen",
224355
+ "WaveRound",
224356
+ "WaveContract",
223606
224357
  "WaveSubmit",
223607
224358
  "WaveGate",
223608
224359
  "WaveDecide",
@@ -223649,7 +224400,8 @@ var init_profiles = __esmMin((() => {
223649
224400
  subagents: [
223650
224401
  "coder",
223651
224402
  "explore",
223652
- "plan"
224403
+ "plan",
224404
+ WAVE_SEAT_PROFILE
223653
224405
  ],
223654
224406
  renderSystemPrompt: (context) => renderSystemPromptResult("", context, { skillActive: skillActiveFor(AGENT_TOOLS) })
223655
224407
  });
@@ -281821,6 +282573,8 @@ var init_src$10 = __esmMin((() => {
281821
282573
  init_flag$2();
281822
282574
  init_wave$3();
281823
282575
  init_waveFeature();
282576
+ init_waveMode();
282577
+ init_waveOps();
281824
282578
  init_gate$1();
281825
282579
  init_gateRunner();
281826
282580
  init_decide$1();
@@ -281832,9 +282586,12 @@ var init_src$10 = __esmMin((() => {
281832
282586
  init_submit$1();
281833
282587
  init_submitRunner();
281834
282588
  init_seatProfile();
281835
- init_round$1();
282589
+ init_round();
281836
282590
  init_roundRunner();
281837
282591
  init_prompts$2();
282592
+ init_seats();
282593
+ init_contract$4();
282594
+ init_contractRunner();
281838
282595
  init_flag$2();
281839
282596
  init_waveFeature();
281840
282597
  init_usage();
@@ -288170,6 +288927,7 @@ var init_sdk_rpc_client_v2 = __esmMin((() => {
288170
288927
  init_connection_manager();
288171
288928
  init_towerRateLimit();
288172
288929
  init_statusReader();
288930
+ init_waveMode();
288173
288931
  init_configLoader();
288174
288932
  init_fs$1();
288175
288933
  init_appendLogStore$1();
@@ -289455,6 +290213,7 @@ var init_sdk_rpc_client_v2 = __esmMin((() => {
289455
290213
  permission: agent.accessor.get(IAgentPermissionModeService).mode,
289456
290214
  planMode: plan !== null,
289457
290215
  swarmMode: agent.accessor.get(IAgentSwarmService).isActive,
290216
+ waveMode: agent.accessor.get(IAgentWaveService).isActive,
289458
290217
  towerMode: agent.accessor.get(IAgentTowerService).isActive,
289459
290218
  contextTokens,
289460
290219
  maxContextTokens,
@@ -289742,6 +290501,11 @@ var init_sdk_rpc_client_v2 = __esmMin((() => {
289742
290501
  });
289743
290502
  return this.prompt(input);
289744
290503
  }
290504
+ async setWaveMode(input) {
290505
+ const wave = (await this.agentScope(input.sessionId)).accessor.get(IAgentWaveService);
290506
+ if (input.enabled) await wave.enter();
290507
+ else await wave.exit();
290508
+ }
289745
290509
  /** Through the agent scope (`IAgentTowerService.enter` / `.exit`) — no klient facade exists. */
289746
290510
  async setTowerMode(input) {
289747
290511
  const agent = await this.agentScope(input.sessionId);
@@ -394734,10 +395498,6 @@ function swarmArgumentCompletions(argumentPrefix) {
394734
395498
  function towerArgumentCompletions(argumentPrefix) {
394735
395499
  return completeLeadingArg(TOWER_ARG_COMPLETIONS, argumentPrefix);
394736
395500
  }
394737
- /** Argument autocompletion for the `/wave` command (subcommands). */
394738
- function waveArgumentCompletions(argumentPrefix) {
394739
- return completeLeadingArg(WAVE_ARG_COMPLETIONS, argumentPrefix);
394740
- }
394741
395501
  /** Argument autocompletion for the `/add-dir` command. */
394742
395502
  function addDirArgumentCompletions(argumentPrefix) {
394743
395503
  if (isPathLikeAddDirArgument(argumentPrefix)) return completeAddDirPath(argumentPrefix);
@@ -394817,7 +395577,7 @@ function resolveSlashCommandAvailability(command, args) {
394817
395577
  function sortSlashCommands(commands) {
394818
395578
  return [...commands].toSorted((a, b) => (b.priority ?? 0) - (a.priority ?? 0) || a.name.localeCompare(b.name));
394819
395579
  }
394820
- var GOAL_ARG_COMPLETIONS, GOAL_NEXT_ARG_COMPLETIONS, SWARM_ARG_COMPLETIONS, TOWER_ARG_COMPLETIONS, WAVE_ARG_COMPLETIONS, ADD_DIR_ARG_COMPLETIONS, BUILTIN_SLASH_COMMANDS;
395580
+ var GOAL_ARG_COMPLETIONS, GOAL_NEXT_ARG_COMPLETIONS, SWARM_ARG_COMPLETIONS, TOWER_ARG_COMPLETIONS, ADD_DIR_ARG_COMPLETIONS, BUILTIN_SLASH_COMMANDS;
394821
395581
  var init_registry$2 = __esmMin((() => {
394822
395582
  init_dist$5();
394823
395583
  init_complete_args();
@@ -394876,20 +395636,6 @@ var init_registry$2 = __esmMin((() => {
394876
395636
  description: "Turn tower mode off"
394877
395637
  }
394878
395638
  ];
394879
- WAVE_ARG_COMPLETIONS = [
394880
- {
394881
- value: "on",
394882
- description: "Enable the wave experiment"
394883
- },
394884
- {
394885
- value: "off",
394886
- description: "Disable the wave experiment"
394887
- },
394888
- {
394889
- value: "status",
394890
- description: "Report whether the wave experiment is on"
394891
- }
394892
- ];
394893
395639
  ADD_DIR_ARG_COMPLETIONS = [{
394894
395640
  value: "list",
394895
395641
  description: "Show configured additional workspace directories"
@@ -394952,12 +395698,9 @@ var init_registry$2 = __esmMin((() => {
394952
395698
  {
394953
395699
  name: "wave",
394954
395700
  aliases: [],
394955
- description: "Run a design wave: brief, adversarial swarm, gate and execution",
395701
+ description: "Turn the wave mode on or off, or open a design wave with an objective",
394956
395702
  priority: 90,
394957
- argumentHint: "[on|off|status] | <objetivo de la oleada>",
394958
- completeArgs: waveArgumentCompletions,
394959
- availability: "idle-only",
394960
- experimentalFlag: "wave"
395703
+ argumentHint: "[on|off] | <objetivo de la oleada>"
394961
395704
  },
394962
395705
  {
394963
395706
  name: "model",
@@ -471840,6 +472583,7 @@ var init_footer = __esmMin((() => {
471840
472583
  if (state.permissionMode === "yolo") modes.push(chalk.hex(colors.warning).bold(PERMISSION_MODE_DISPLAY_NAMES.yolo));
471841
472584
  if (state.planMode) modes.push(chalk.hex(colors.primary).bold("plan"));
471842
472585
  if (state.swarmMode) modes.push(chalk.hex(colors.accent).bold("swarm"));
472586
+ if (state.waveMode) modes.push(chalk.hex(colors.accent).bold("wave"));
471843
472587
  if (state.towerMode) modes.push(chalk.hex(colors.accent).bold("tower"));
471844
472588
  if (modes.length > 0) slots["mode"] = [modes.join(" ")];
471845
472589
  const goalBadge = formatGoalBadge(state.goal, colors, this.goalWallClockMs(state.goal));
@@ -477577,80 +478321,58 @@ var init_swarm = __esmMin((() => {
477577
478321
  SWARM_USAGE_NOTICE = "High usage: Swarm is built for large parallel jobs and can use many times the tokens of a normal task. Start small, and run /swarm off when you're done.";
477578
478322
  }));
477579
478323
  // src/tui/commands/wave.ts
477580
- function buildWavePrompt(args) {
478324
+ function buildWavePrompt(objective) {
477581
478325
  return [
477582
- `Ejecuta una oleada del método workflow para: ${args.trim()}`,
478326
+ `Abre una oleada del método workflow para: ${objective}`,
477583
478327
  "",
477584
- "Reglas de la oleada:",
477585
- "- 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.",
477586
- "- Lanza un agente por asiento con `Agent` (o `AgentSwarm` si el usuario activó swarm) usando el prompt que devuelve `WaveRound`. No inventes el prompt ni cambies el rol.",
477587
- "- Un asiento nunca escribe con Write/Edit: entrega con `WaveSubmit`, que ata rol y ruta.",
477588
- "- Si el brief no tiene las siete secciones, para y pide que se rellenen; no lo escribas tú.",
477589
- "- Sin `adopt` de `WaveDecide`, lanza `refine` y después `audit`; con dos rondas sin quórum, adopta R1 con disidencia escrita.",
477590
- "- La oleada no está cerrada hasta que `WaveGate` sale en verde. Si sale en rojo, dilo con los códigos de hallazgo."
478328
+ "Reglas:",
478329
+ "- Redacta primero el plan de la oleada (WaveOpen con nombre, alcance, evidencia y rondas) y crea el Goal con completionCriterion \"WaveGate verde sobre la oleada W<n> y WaveVerify 0 en todas sus tasks\".",
478330
+ "- No ejecutes la oleada en este turno: el plan se revisa antes de aprobarse.",
478331
+ "- Tras la aprobación, contrata con WaveContract y lanza un agente `wave-seat` por asiento. Tú no escribes artefactos: WaveSubmit es del asiento.",
478332
+ "- Cierras con WaveDecide, WaveVerify y WaveGate; la oleada no está cerrada hasta que WaveGate sale en verde."
477591
478333
  ].join("\n");
477592
478334
  }
477593
478335
  async function handleWaveCommand(host, args) {
477594
- const input = args.trim();
477595
- const sub = input.toLowerCase();
477596
- if (sub === "on" || sub === "off") {
477597
- await setWaveExperiment(host, sub === "on");
477598
- return;
477599
- }
477600
- if (sub === "" || sub === "status") {
477601
- await reportWaveStatus(host, sub === "");
478336
+ const session = host.session;
478337
+ if (session === void 0) {
478338
+ host.showError(NO_ACTIVE_SESSION_MESSAGE);
477602
478339
  return;
477603
478340
  }
477604
- if (sub === "help") {
477605
- host.showNotice("Wave", WAVE_USAGE);
478341
+ const input = args.trim();
478342
+ const command = input.toLowerCase();
478343
+ if (command === "on" || command === "off" || command === "") {
478344
+ await applyWaveMode(host, command === "" ? !host.state.appState.waveMode : command === "on");
477606
478345
  return;
477607
478346
  }
478347
+ if (!host.state.appState.waveMode && !await applyWaveMode(host, true)) return;
478348
+ if (!host.state.appState.planMode) await applyPlanMode(host, session, true);
477608
478349
  host.sendNormalUserInput(buildWavePrompt(input));
477609
478350
  }
477610
- async function reportWaveStatus(host, asUsage) {
477611
- let enabled;
477612
- try {
477613
- enabled = (await host.harness.getExperimentalFeatures()).find((feature) => feature.id === WAVE_FLAG_ID)?.enabled === true;
477614
- } catch (error) {
477615
- host.showError(`Failed to read the wave experiment state: ${formatErrorMessage$2(error)}`);
477616
- return;
477617
- }
477618
- if (asUsage) {
477619
- host.showNotice(`Wave experiment: ${enabled ? "ON" : "OFF"}`, `${WAVE_USAGE}\n\n${enabled ? "Las tools Wave están disponibles en esta sesión." : "Actívalo con `/wave on`; no hace falta editar config.toml ni reiniciar."}`);
477620
- return;
477621
- }
477622
- host.showStatus(enabled ? "Wave experiment is on." : "Wave experiment is off. Run `/wave on` to enable it without a restart.");
477623
- }
477624
- async function setWaveExperiment(host, enabled) {
477625
- try {
477626
- await host.harness.setConfig({ experimental: { [WAVE_FLAG_ID]: enabled } });
477627
- setExperimentalFeatures(await host.harness.getExperimentalFeatures());
477628
- host.refreshSlashCommandAutocomplete();
477629
- } catch (error) {
477630
- host.showError(`Failed to ${enabled ? "enable" : "disable"} the wave experiment: ${formatErrorMessage$2(error)}`);
477631
- return;
477632
- }
477633
- if (!enabled) {
477634
- host.showStatus("Wave experiment off. `/wave` is hidden until you turn it back on.");
477635
- return;
477636
- }
477637
- if (host.session === void 0) {
477638
- host.showStatus("Wave experiment on. `/wave <objetivo>` is ready.", "success");
477639
- return;
478351
+ async function applyWaveMode(host, enabled) {
478352
+ if (enabled === host.state.appState.waveMode) {
478353
+ host.showStatus(`Wave mode is already ${enabled ? "on" : "off"}.`);
478354
+ return true;
477640
478355
  }
477641
478356
  try {
477642
- const reloadedSession = await host.harness.reloadSession({ id: host.session.id });
477643
- await host.reloadCurrentSessionView(reloadedSession, "Wave experiment on. Session reloaded — `/wave <objetivo>` is ready.");
478357
+ await host.requireSession().setWaveMode(enabled);
477644
478358
  } catch (error) {
477645
- host.showError(`Wave experiment is on, but the session could not be reloaded: ${formatErrorMessage$2(error)}`);
478359
+ host.showError(`Failed to ${enabled ? "enable" : "disable"} wave mode: ${formatErrorMessage$2(error)}`);
478360
+ return false;
477646
478361
  }
478362
+ host.setAppState({ waveMode: enabled });
478363
+ host.showNotice(`Wave mode: ${enabled ? "ON" : "OFF"}`);
478364
+ return true;
477647
478365
  }
477648
- var WAVE_USAGE, WAVE_FLAG_ID;
477649
478366
  var init_wave = __esmMin((() => {
478367
+ init_nexgenk_tui();
477650
478368
  init_event_payload();
477651
- init_experimental_flags();
477652
- WAVE_USAGE = "Uso: /wave <objetivo de la oleada> — abre una oleada de diseño, lanza el swarm adversarial y cierra con el gate. Los subcomandos `/wave on`, `/wave off` y `/wave status` activan o consultan el experimento.";
477653
- WAVE_FLAG_ID = "wave";
478369
+ init_config();
478370
+ [
478371
+ "Uso:",
478372
+ " /wave enciende o apaga el modo wave",
478373
+ " /wave off lo apaga",
478374
+ " /wave <objetivo> lo enciende y abre el plan de una oleada"
478375
+ ].join("\n");
477654
478376
  }));
477655
478377
  // src/tui/commands/tower.ts
477656
478378
  async function handleTowerCommand(host, args) {
@@ -484747,7 +485469,6 @@ var init_commands = __esmMin((() => {
484747
485469
  init_config();
484748
485470
  init_swarm();
484749
485471
  init_tower();
484750
- init_wave();
484751
485472
  init_info();
484752
485473
  init_plugins();
484753
485474
  init_reload();
@@ -494367,6 +495088,7 @@ var SessionEventHandler = class {
494367
495088
  }
494368
495089
  if (event.planMode !== void 0) patch.planMode = event.planMode;
494369
495090
  if (event.swarmMode !== void 0) patch.swarmMode = event.swarmMode;
495091
+ if (event.waveMode !== void 0) patch.waveMode = event.waveMode;
494370
495092
  if (event.towerMode !== void 0) patch.towerMode = event.towerMode;
494371
495093
  if (event.permission !== void 0) patch.permissionMode = event.permission;
494372
495094
  if (event.model !== void 0) patch.model = event.model;
@@ -499535,6 +500257,7 @@ function createInitialAppState(input) {
499535
500257
  planMode: input.cliOptions.plan,
499536
500258
  inputMode: "prompt",
499537
500259
  swarmMode: false,
500260
+ waveMode: false,
499538
500261
  towerMode: false,
499539
500262
  thinkingEffort: "off",
499540
500263
  contextUsage: 0,
@@ -501304,6 +502027,7 @@ var NexgenTUI = class {
501304
502027
  permissionMode: status.permission,
501305
502028
  planMode: status.planMode,
501306
502029
  swarmMode: status.swarmMode ?? false,
502030
+ waveMode: status.waveMode ?? false,
501307
502031
  towerMode: status.towerMode ?? false,
501308
502032
  contextTokens: status.contextTokens,
501309
502033
  maxContextTokens: status.maxContextTokens,