forgedock 1.0.10 → 1.0.11

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.
@@ -111,12 +111,22 @@ export function parseEnrichedDraft(output, draft) {
111
111
  // each section must be a plain non-null object. The typeof+null guard
112
112
  // rejects null and primitives; Array.isArray() additionally rejects
113
113
  // arrays since typeof [] === 'object' would otherwise pass them.
114
+ const isPlainObject = (v) =>
115
+ typeof v === "object" && v !== null && !Array.isArray(v);
114
116
  if (
115
- typeof enriched.project !== "object" || enriched.project === null || Array.isArray(enriched.project) ||
116
- typeof enriched.paths !== "object" || enriched.paths === null || Array.isArray(enriched.paths) ||
117
- typeof enriched.branches !== "object" || enriched.branches === null || Array.isArray(enriched.branches) ||
118
- typeof enriched.meta !== "object" || enriched.meta === null || Array.isArray(enriched.meta)
117
+ !isPlainObject(enriched.project) ||
118
+ !isPlainObject(enriched.paths) ||
119
+ !isPlainObject(enriched.branches) ||
120
+ !isPlainObject(enriched.meta)
119
121
  ) {
122
+ if (process.env.FORGEDOCK_DEBUG) {
123
+ const failing = ["project", "paths", "branches", "meta"]
124
+ .filter((k) => !isPlainObject(enriched[k]))
125
+ .join(", ");
126
+ console.error(
127
+ ` ${dim("[debug]")} api enrichment: parseEnrichedDraft rejected LLM output — missing/invalid sections: ${failing}. Falling back to baseline draft.`,
128
+ );
129
+ }
120
130
  return draft;
121
131
  }
122
132
  return enriched;
package/bin/tui.mjs CHANGED
@@ -743,11 +743,14 @@ export function truncateVisible(str, maxWidth) {
743
743
  if (remaining > 0) {
744
744
  result += str.slice(lastIndex, lastIndex + remaining);
745
745
  }
746
- // If truncation occurred and the result contains any ANSI sequences,
747
- // append a full reset to prevent color from bleeding into adjacent columns.
748
- // Truncation is detected by checking whether the original string has more
749
- // visible characters than maxWidth (i.e. stripAnsi(str).length > maxWidth).
750
- if (stripAnsi(str).length > maxWidth && result.includes("\x1b[")) {
746
+ // If truncation occurred (or visible length exactly equals maxWidth) and the
747
+ // result contains any ANSI sequences, append a full reset to prevent color from
748
+ // bleeding into adjacent columns. The guard uses >= rather than > to cover the
749
+ // exact-boundary case: when visible === maxWidth the loop guard (visible < maxWidth)
750
+ // suppresses the original trailing RESET token, so the post-loop guard must fire
751
+ // to close any open sequences. Inputs shorter than maxWidth are unaffected because
752
+ // stripAnsi(str).length < maxWidth makes the condition false.
753
+ if (stripAnsi(str).length >= maxWidth && result.includes("\x1b[")) {
751
754
  result += "\x1b[0m";
752
755
  }
753
756
  return result;