@parabolic-technologies/banzai 2.6.5 → 2.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/banzai.mjs CHANGED
@@ -5897,6 +5897,13 @@ function consultationString(value, label, maximum) {
5897
5897
  }
5898
5898
  return value;
5899
5899
  }
5900
+ function consultationProse(value, label, maximum) {
5901
+ return consultationString(
5902
+ typeof value === "string" ? value.replace(/[ \t\n\r]*[\t\n\r][ \t\n\r]*/gu, " ").replace(/^ +| +$/gu, "") : value,
5903
+ label,
5904
+ maximum
5905
+ );
5906
+ }
5900
5907
  function consultationIdentifier(value, label) {
5901
5908
  const identifier22 = consultationString(value, label, 128);
5902
5909
  if (identifier22 === "." || identifier22 === ".." || !CONSULTATION_ID_PATTERN.test(identifier22)) {
@@ -5904,12 +5911,12 @@ function consultationIdentifier(value, label) {
5904
5911
  }
5905
5912
  return identifier22;
5906
5913
  }
5907
- function consultationStrings(value, label, maximumItems, maximumLength) {
5914
+ function consultationStrings(value, label, maximumItems, maximumLength, decodeItem) {
5908
5915
  if (!Array.isArray(value) || value.length > maximumItems) {
5909
5916
  return consultationError(`${label} must be a bounded string array.`);
5910
5917
  }
5911
5918
  const strings = value.map(
5912
- (item, index) => consultationString(item, `${label}[${index}]`, maximumLength)
5919
+ (item, index) => decodeItem(item, `${label}[${index}]`, maximumLength)
5913
5920
  );
5914
5921
  if (new Set(strings).size !== strings.length) {
5915
5922
  return consultationError(`${label} must not contain duplicates.`);
@@ -5939,15 +5946,34 @@ function parseConsultationOption(value, label) {
5939
5946
  ]);
5940
5947
  return {
5941
5948
  optionId: consultationIdentifier(record7.optionId, `${label}.optionId`),
5942
- title: consultationString(record7.title, `${label}.title`, 160),
5943
- benefits: consultationStrings(record7.benefits, `${label}.benefits`, 8, 500),
5944
- costs: consultationStrings(record7.costs, `${label}.costs`, 8, 500),
5945
- risks: consultationStrings(record7.risks, `${label}.risks`, 8, 500),
5949
+ title: consultationProse(record7.title, `${label}.title`, 160),
5950
+ benefits: consultationStrings(
5951
+ record7.benefits,
5952
+ `${label}.benefits`,
5953
+ 8,
5954
+ 500,
5955
+ consultationProse
5956
+ ),
5957
+ costs: consultationStrings(
5958
+ record7.costs,
5959
+ `${label}.costs`,
5960
+ 8,
5961
+ 500,
5962
+ consultationProse
5963
+ ),
5964
+ risks: consultationStrings(
5965
+ record7.risks,
5966
+ `${label}.risks`,
5967
+ 8,
5968
+ 500,
5969
+ consultationProse
5970
+ ),
5946
5971
  consequences: consultationStrings(
5947
5972
  record7.consequences,
5948
5973
  `${label}.consequences`,
5949
5974
  8,
5950
- 500
5975
+ 500,
5976
+ consultationProse
5951
5977
  )
5952
5978
  };
5953
5979
  }
@@ -5991,7 +6017,7 @@ function parseConsultationCard(value, index) {
5991
6017
  return {
5992
6018
  path: consultationPath(evidenceRecord.path, `${evidenceLabel}.path`),
5993
6019
  line,
5994
- detail: consultationString(
6020
+ detail: consultationProse(
5995
6021
  evidenceRecord.detail,
5996
6022
  `${evidenceLabel}.detail`,
5997
6023
  500
@@ -6035,7 +6061,7 @@ function parseConsultationCard(value, index) {
6035
6061
  }
6036
6062
  recommendation = {
6037
6063
  optionId,
6038
- rationale: consultationString(
6064
+ rationale: consultationProse(
6039
6065
  recommendationRecord.rationale,
6040
6066
  `${label}.recommendation.rationale`,
6041
6067
  1e3
@@ -6051,7 +6077,8 @@ function parseConsultationCard(value, index) {
6051
6077
  record7.affectedRequirements,
6052
6078
  `${label}.affectedRequirements`,
6053
6079
  16,
6054
- 120
6080
+ 120,
6081
+ consultationString
6055
6082
  );
6056
6083
  if (affectedRequirements.length === 0) {
6057
6084
  return consultationError(
@@ -6063,9 +6090,9 @@ function parseConsultationCard(value, index) {
6063
6090
  record7.decisionId,
6064
6091
  `${label}.decisionId`
6065
6092
  ),
6066
- title: consultationString(record7.title, `${label}.title`, 160),
6067
- question: consultationString(record7.question, `${label}.question`, 1e3),
6068
- why: consultationString(record7.why, `${label}.why`, 1200),
6093
+ title: consultationProse(record7.title, `${label}.title`, 160),
6094
+ question: consultationProse(record7.question, `${label}.question`, 1e3),
6095
+ why: consultationProse(record7.why, `${label}.why`, 1200),
6069
6096
  affectedRequirements,
6070
6097
  evidence: evidence2,
6071
6098
  decisionOwner: "human",
@@ -6296,7 +6323,7 @@ function parsePhaseResultFields(record7) {
6296
6323
  const decisionConsultation = parseDecisionConsultation(
6297
6324
  record7.decisionConsultation
6298
6325
  );
6299
- const summary2 = gate === "decision_consultation" ? consultationString(record7.summary, "summary", 1e3) : requireString(record7.summary, "summary");
6326
+ const summary2 = gate === "decision_consultation" ? consultationProse(record7.summary, "summary", 1e3) : requireString(record7.summary, "summary");
6300
6327
  if (gate === "decision_consultation" ? phase !== "plan" || outcome !== "needs_human_decision" || decisionConsultation === null || questions.length !== 0 : decisionConsultation !== null) {
6301
6328
  throw new BanzaiError2(
6302
6329
  "INVALID_RESULT",
@@ -12887,6 +12914,13 @@ function consultationString2(value, label, maximum) {
12887
12914
  }
12888
12915
  return value;
12889
12916
  }
12917
+ function consultationProse2(value, label, maximum) {
12918
+ return consultationString2(
12919
+ typeof value === "string" ? value.replace(/[ \t\n\r]*[\t\n\r][ \t\n\r]*/gu, " ").replace(/^ +| +$/gu, "") : value,
12920
+ label,
12921
+ maximum
12922
+ );
12923
+ }
12890
12924
  function consultationIdentifier2(value, label) {
12891
12925
  const identifier4 = consultationString2(value, label, 128);
12892
12926
  if (identifier4 === "." || identifier4 === ".." || !CONSULTATION_ID_PATTERN2.test(identifier4)) {
@@ -12894,12 +12928,12 @@ function consultationIdentifier2(value, label) {
12894
12928
  }
12895
12929
  return identifier4;
12896
12930
  }
12897
- function consultationStrings2(value, label, maximumItems, maximumLength) {
12931
+ function consultationStrings2(value, label, maximumItems, maximumLength, decodeItem) {
12898
12932
  if (!Array.isArray(value) || value.length > maximumItems) {
12899
12933
  return consultationError2(`${label} must be a bounded string array.`);
12900
12934
  }
12901
12935
  const strings = value.map(
12902
- (item, index) => consultationString2(item, `${label}[${index}]`, maximumLength)
12936
+ (item, index) => decodeItem(item, `${label}[${index}]`, maximumLength)
12903
12937
  );
12904
12938
  if (new Set(strings).size !== strings.length) {
12905
12939
  return consultationError2(`${label} must not contain duplicates.`);
@@ -12929,15 +12963,34 @@ function parseConsultationOption2(value, label) {
12929
12963
  ]);
12930
12964
  return {
12931
12965
  optionId: consultationIdentifier2(record7.optionId, `${label}.optionId`),
12932
- title: consultationString2(record7.title, `${label}.title`, 160),
12933
- benefits: consultationStrings2(record7.benefits, `${label}.benefits`, 8, 500),
12934
- costs: consultationStrings2(record7.costs, `${label}.costs`, 8, 500),
12935
- risks: consultationStrings2(record7.risks, `${label}.risks`, 8, 500),
12966
+ title: consultationProse2(record7.title, `${label}.title`, 160),
12967
+ benefits: consultationStrings2(
12968
+ record7.benefits,
12969
+ `${label}.benefits`,
12970
+ 8,
12971
+ 500,
12972
+ consultationProse2
12973
+ ),
12974
+ costs: consultationStrings2(
12975
+ record7.costs,
12976
+ `${label}.costs`,
12977
+ 8,
12978
+ 500,
12979
+ consultationProse2
12980
+ ),
12981
+ risks: consultationStrings2(
12982
+ record7.risks,
12983
+ `${label}.risks`,
12984
+ 8,
12985
+ 500,
12986
+ consultationProse2
12987
+ ),
12936
12988
  consequences: consultationStrings2(
12937
12989
  record7.consequences,
12938
12990
  `${label}.consequences`,
12939
12991
  8,
12940
- 500
12992
+ 500,
12993
+ consultationProse2
12941
12994
  )
12942
12995
  };
12943
12996
  }
@@ -12981,7 +13034,7 @@ function parseConsultationCard2(value, index) {
12981
13034
  return {
12982
13035
  path: consultationPath2(evidenceRecord.path, `${evidenceLabel}.path`),
12983
13036
  line,
12984
- detail: consultationString2(
13037
+ detail: consultationProse2(
12985
13038
  evidenceRecord.detail,
12986
13039
  `${evidenceLabel}.detail`,
12987
13040
  500
@@ -13025,7 +13078,7 @@ function parseConsultationCard2(value, index) {
13025
13078
  }
13026
13079
  recommendation = {
13027
13080
  optionId,
13028
- rationale: consultationString2(
13081
+ rationale: consultationProse2(
13029
13082
  recommendationRecord.rationale,
13030
13083
  `${label}.recommendation.rationale`,
13031
13084
  1e3
@@ -13041,7 +13094,8 @@ function parseConsultationCard2(value, index) {
13041
13094
  record7.affectedRequirements,
13042
13095
  `${label}.affectedRequirements`,
13043
13096
  16,
13044
- 120
13097
+ 120,
13098
+ consultationString2
13045
13099
  );
13046
13100
  if (affectedRequirements.length === 0) {
13047
13101
  return consultationError2(
@@ -13053,9 +13107,9 @@ function parseConsultationCard2(value, index) {
13053
13107
  record7.decisionId,
13054
13108
  `${label}.decisionId`
13055
13109
  ),
13056
- title: consultationString2(record7.title, `${label}.title`, 160),
13057
- question: consultationString2(record7.question, `${label}.question`, 1e3),
13058
- why: consultationString2(record7.why, `${label}.why`, 1200),
13110
+ title: consultationProse2(record7.title, `${label}.title`, 160),
13111
+ question: consultationProse2(record7.question, `${label}.question`, 1e3),
13112
+ why: consultationProse2(record7.why, `${label}.why`, 1200),
13059
13113
  affectedRequirements,
13060
13114
  evidence: evidence2,
13061
13115
  decisionOwner: "human",
@@ -13372,7 +13426,7 @@ function parsePhaseResultFields2(record7) {
13372
13426
  const decisionConsultation = parseDecisionConsultation2(
13373
13427
  record7.decisionConsultation
13374
13428
  );
13375
- const summary2 = gate === "decision_consultation" ? consultationString2(record7.summary, "summary", 1e3) : requireString2(record7.summary, "summary");
13429
+ const summary2 = gate === "decision_consultation" ? consultationProse2(record7.summary, "summary", 1e3) : requireString2(record7.summary, "summary");
13376
13430
  if (gate === "decision_consultation" ? phase !== "plan" || outcome !== "needs_human_decision" || decisionConsultation === null || questions.length !== 0 : decisionConsultation !== null) {
13377
13431
  throw new BanzaiError(
13378
13432
  "INVALID_RESULT",
@@ -24395,7 +24449,7 @@ import process7 from "node:process";
24395
24449
  // package.json
24396
24450
  var package_default = {
24397
24451
  name: "@parabolic-technologies/banzai",
24398
- version: "2.6.5",
24452
+ version: "2.6.6",
24399
24453
  private: false,
24400
24454
  description: "Spec-driven AI development CLI for Codex and Claude Code, with human approvals and independent review for complex changes.",
24401
24455
  keywords: [
@@ -24530,6 +24584,7 @@ var phase_result_schema_default = {
24530
24584
  },
24531
24585
  summary: {
24532
24586
  type: "string",
24587
+ description: "With gate decision_consultation, one plain line of at most 1000 characters without control characters; the decision cards carry the detail.",
24533
24588
  minLength: 1
24534
24589
  },
24535
24590
  artifacts: {
@@ -24687,6 +24742,7 @@ var phase_result_schema_default = {
24687
24742
  },
24688
24743
  {
24689
24744
  type: "object",
24745
+ description: "Every string in this request is one plain line without control characters within its maxLength; use separate array entries instead of line breaks.",
24690
24746
  additionalProperties: false,
24691
24747
  properties: {
24692
24748
  schema: {
@@ -31570,18 +31626,6 @@ async function establishPlanRemainderDigest(context, state, attempt, planPath, m
31570
31626
  }
31571
31627
  await recordResultDigestEvidence(context, state, attempt, [comparison]);
31572
31628
  }
31573
- function completionInvalidCheckpoint(context, sourceAttemptId, error, sourceAttemptKind = "implementation") {
31574
- return {
31575
- schemaVersion: 1,
31576
- status: "invalid",
31577
- sourceAttemptId,
31578
- sourceAttemptKind,
31579
- errorCode: "PLAN_TASK_COMPLETION_INVALID",
31580
- violation: error.violation,
31581
- taskId: error.taskId,
31582
- recordedAt: timestamp(context)
31583
- };
31584
- }
31585
31629
 
31586
31630
  // src/workflow/verification/required-checks.ts
31587
31631
  import { readFile as readFile13 } from "node:fs/promises";
@@ -32323,6 +32367,22 @@ function artifactWritePaths(state, phase) {
32323
32367
 
32324
32368
  // src/workflow/attempts/lifecycle.ts
32325
32369
  import path29 from "node:path";
32370
+
32371
+ // src/workflow/domain/completion-checkpoint.ts
32372
+ function completionInvalidCheckpoint(facts) {
32373
+ return {
32374
+ schemaVersion: 1,
32375
+ status: "invalid",
32376
+ sourceAttemptId: facts.sourceAttemptId,
32377
+ sourceAttemptKind: facts.sourceAttemptKind,
32378
+ errorCode: "PLAN_TASK_COMPLETION_INVALID",
32379
+ violation: facts.violation,
32380
+ taskId: facts.taskId,
32381
+ recordedAt: facts.recordedAt
32382
+ };
32383
+ }
32384
+
32385
+ // src/workflow/attempts/lifecycle.ts
32326
32386
  function newAttempt(context, state, kind, mutable) {
32327
32387
  return {
32328
32388
  id: `${kind}-${state.reviewIteration + 1}-${context.ids().slice(0, 8)}`,
@@ -32590,12 +32650,13 @@ async function failAttempt(context, state, record7, error) {
32590
32650
  }
32591
32651
  }
32592
32652
  if (completionError3 !== null) {
32593
- state.planTaskCompletion = completionInvalidCheckpoint(
32594
- context,
32595
- record7.attempt.id,
32596
- completionError3,
32597
- record7.attempt.kind === "fix" ? "fix" : "implementation"
32598
- );
32653
+ state.planTaskCompletion = completionInvalidCheckpoint({
32654
+ sourceAttemptId: record7.attempt.id,
32655
+ sourceAttemptKind: record7.attempt.kind === "fix" ? "fix" : "implementation",
32656
+ violation: completionError3.violation,
32657
+ taskId: completionError3.taskId,
32658
+ recordedAt: timestamp(context)
32659
+ });
32599
32660
  }
32600
32661
  blockState(
32601
32662
  state,
@@ -34235,12 +34296,13 @@ async function blockForCompletionFailure(context, state, sourceAttemptId, error)
34235
34296
  "source_attempt_invalid",
34236
34297
  errorMessage(error)
34237
34298
  );
34238
- state.planTaskCompletion = completionInvalidCheckpoint(
34239
- context,
34299
+ state.planTaskCompletion = completionInvalidCheckpoint({
34240
34300
  sourceAttemptId,
34241
- completionError3,
34242
- state.planTaskCompletion?.sourceAttemptId === sourceAttemptId ? state.planTaskCompletion.sourceAttemptKind ?? "implementation" : "implementation"
34243
- );
34301
+ sourceAttemptKind: state.planTaskCompletion?.sourceAttemptId === sourceAttemptId ? state.planTaskCompletion.sourceAttemptKind ?? "implementation" : "implementation",
34302
+ violation: completionError3.violation,
34303
+ taskId: completionError3.taskId,
34304
+ recordedAt: timestamp(context)
34305
+ });
34244
34306
  state.activeProcess = null;
34245
34307
  blockState(
34246
34308
  state,
@@ -35483,6 +35545,10 @@ still genuinely unresolved and blocks sound requirements, an ADR, or the plan,
35483
35545
  stop before authoring a Proposed ADR or plan that selects an option. Return
35484
35546
  outcome=needs_human_decision, gate=decision_consultation, questions=[], and one
35485
35547
  closed decisionConsultation request containing 1-3 sequential decision cards.
35548
+ Its summary is one plain line of at most 1000 characters naming the pending
35549
+ decisions; the cards carry the detail. Every card string is also one plain line
35550
+ within its schema maxLength: put separate points in separate benefits, costs,
35551
+ risks, consequences, or evidence entries instead of line breaks or lists.
35486
35552
  Each card must have a fresh stable decisionId, a precise question and why,
35487
35553
  affected requirement IDs, repository-relative evidence, an accountable owner,
35488
35554
  the supported responseMode, explicit options with consequences when the mode is