frontend-harness 0.7.9 → 0.8.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 (98) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +20 -10
  3. package/dist/cli/index.js +388 -66
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/runtime/builtin-skills.js +1 -1
  6. package/dist/runtime/clean.js +25 -3
  7. package/dist/runtime/clean.js.map +1 -1
  8. package/dist/runtime/command-taxonomy.js +6 -1
  9. package/dist/runtime/command-taxonomy.js.map +1 -1
  10. package/dist/runtime/context.d.ts +33 -2
  11. package/dist/runtime/context.js +112 -13
  12. package/dist/runtime/context.js.map +1 -1
  13. package/dist/runtime/evidence.d.ts +27 -0
  14. package/dist/runtime/evidence.js +302 -19
  15. package/dist/runtime/evidence.js.map +1 -1
  16. package/dist/runtime/graph.js +11 -4
  17. package/dist/runtime/graph.js.map +1 -1
  18. package/dist/runtime/ingest.d.ts +38 -0
  19. package/dist/runtime/ingest.js +157 -0
  20. package/dist/runtime/ingest.js.map +1 -0
  21. package/dist/runtime/knowledge/constants.d.ts +9 -0
  22. package/dist/runtime/knowledge/constants.js +25 -0
  23. package/dist/runtime/knowledge/constants.js.map +1 -0
  24. package/dist/runtime/knowledge/core.d.ts +25 -0
  25. package/dist/runtime/knowledge/core.js +1569 -0
  26. package/dist/runtime/knowledge/core.js.map +1 -0
  27. package/dist/runtime/knowledge/types.d.ts +241 -0
  28. package/dist/runtime/knowledge/types.js +2 -0
  29. package/dist/runtime/knowledge/types.js.map +1 -0
  30. package/dist/runtime/knowledge.d.ts +2 -188
  31. package/dist/runtime/knowledge.js +1 -1126
  32. package/dist/runtime/knowledge.js.map +1 -1
  33. package/dist/runtime/plan/component-resolver.js +17 -6
  34. package/dist/runtime/plan/component-resolver.js.map +1 -1
  35. package/dist/runtime/plan/guidance.d.ts +1 -1
  36. package/dist/runtime/plan/guidance.js +88 -25
  37. package/dist/runtime/plan/guidance.js.map +1 -1
  38. package/dist/runtime/plan/proposal.js +9 -0
  39. package/dist/runtime/plan/proposal.js.map +1 -1
  40. package/dist/runtime/plan/workflow.d.ts +1 -0
  41. package/dist/runtime/plan/workflow.js +32 -1
  42. package/dist/runtime/plan/workflow.js.map +1 -1
  43. package/dist/runtime/plan.d.ts +13 -0
  44. package/dist/runtime/plan.js +137 -82
  45. package/dist/runtime/plan.js.map +1 -1
  46. package/dist/runtime/policy-provenance.d.ts +17 -1
  47. package/dist/runtime/policy-provenance.js +84 -16
  48. package/dist/runtime/policy-provenance.js.map +1 -1
  49. package/dist/runtime/project-discovery.js +32 -17
  50. package/dist/runtime/project-discovery.js.map +1 -1
  51. package/dist/runtime/project-paths.js +7 -1
  52. package/dist/runtime/project-paths.js.map +1 -1
  53. package/dist/runtime/protocol-init.js +117 -26
  54. package/dist/runtime/protocol-init.js.map +1 -1
  55. package/dist/runtime/repair-decision.js +76 -16
  56. package/dist/runtime/repair-decision.js.map +1 -1
  57. package/dist/runtime/repair-packet.js +141 -20
  58. package/dist/runtime/repair-packet.js.map +1 -1
  59. package/dist/runtime/scaffold/vue-template.js +1 -1
  60. package/dist/runtime/scaffold/vue-template.js.map +1 -1
  61. package/dist/runtime/scaffold.js +44 -8
  62. package/dist/runtime/scaffold.js.map +1 -1
  63. package/dist/runtime/skills.d.ts +9 -0
  64. package/dist/runtime/skills.js +133 -18
  65. package/dist/runtime/skills.js.map +1 -1
  66. package/dist/runtime/state-explain.js +39 -7
  67. package/dist/runtime/state-explain.js.map +1 -1
  68. package/dist/runtime/state.js +85 -10
  69. package/dist/runtime/state.js.map +1 -1
  70. package/dist/runtime/task-context.d.ts +122 -0
  71. package/dist/runtime/task-context.js +1322 -0
  72. package/dist/runtime/task-context.js.map +1 -0
  73. package/dist/runtime/task-signals.d.ts +1 -0
  74. package/dist/runtime/task-signals.js +1 -1
  75. package/dist/runtime/task-signals.js.map +1 -1
  76. package/dist/runtime/ui-restoration.d.ts +3 -3
  77. package/dist/runtime/ui-restoration.js +3 -3
  78. package/dist/runtime/ui-restoration.js.map +1 -1
  79. package/dist/runtime/ui-source.d.ts +6 -0
  80. package/dist/runtime/ui-source.js +66 -0
  81. package/dist/runtime/ui-source.js.map +1 -0
  82. package/dist/runtime/units.js +11 -4
  83. package/dist/runtime/units.js.map +1 -1
  84. package/dist/runtime/verification-commands.js +95 -21
  85. package/dist/runtime/verification-commands.js.map +1 -1
  86. package/dist/runtime/verify.js +129 -43
  87. package/dist/runtime/verify.js.map +1 -1
  88. package/dist/runtime/visual-compare.js +104 -12
  89. package/dist/runtime/visual-compare.js.map +1 -1
  90. package/dist/schemas/types.d.ts +75 -2
  91. package/dist/schemas/validation.js +257 -6
  92. package/dist/schemas/validation.js.map +1 -1
  93. package/dist/storage/json.d.ts +9 -1
  94. package/dist/storage/json.js +106 -8
  95. package/dist/storage/json.js.map +1 -1
  96. package/docs/DIRECTION.md +13 -11
  97. package/docs/RELEASE.md +5 -1
  98. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { buildContext } from "../runtime/context.js";
3
3
  import { checkComponentGraph } from "../runtime/graph.js";
4
- import { addKnowledge, checkKnowledge, checkKnowledgeCoverage, createModuleKnowledge, indexKnowledge, listKnowledge, promoteKnowledge, searchKnowledge, showKnowledge, updateKnowledge } from "../runtime/knowledge.js";
4
+ import { addKnowledge, checkKnowledge, checkKnowledgeCoverage, createModuleKnowledge, draftKnowledgeFromIngest, indexKnowledge, listKnowledge, promoteKnowledge, searchKnowledge, showKnowledge, updateKnowledge } from "../runtime/knowledge.js";
5
5
  import { checkAgentPlanningProposal, createPlan } from "../runtime/plan.js";
6
6
  import { publicHelpLines } from "../runtime/command-taxonomy.js";
7
7
  import { cleanRuntimeArtifacts } from "../runtime/clean.js";
@@ -10,12 +10,15 @@ import { createRepairPacket } from "../runtime/repair-packet.js";
10
10
  import { isScaffoldPresetName, scaffoldProject } from "../runtime/scaffold.js";
11
11
  import { explainState } from "../runtime/state-explain.js";
12
12
  import { checkProtocol, initializeProtocol } from "../runtime/protocol-init.js";
13
- import { checkSkills, discoverSkills } from "../runtime/skills.js";
13
+ import { checkSkills, listSkills } from "../runtime/skills.js";
14
14
  import { changedFilesFromGit, checkStateContract, getNextAction, loadState, recordChangedFiles } from "../runtime/state.js";
15
15
  import { checkExecutionUnits } from "../runtime/units.js";
16
+ import { listIngestRecords, recordIngestSource, showIngestRecord } from "../runtime/ingest.js";
17
+ import { buildCompactTaskContext } from "../runtime/task-context.js";
16
18
  import { assertDesignSourceReadyForProjectChanges, createEvidenceTemplate, recordEvidence } from "../runtime/evidence.js";
17
19
  import { runVerification } from "../runtime/verify.js";
18
20
  import { compareVisualArtifacts } from "../runtime/visual-compare.js";
21
+ const MAX_HUMAN_VERIFICATION_RESULTS = 10;
19
22
  const COMMAND_HELP = {
20
23
  init: [
21
24
  "Usage:",
@@ -30,7 +33,18 @@ const COMMAND_HELP = {
30
33
  ],
31
34
  context: [
32
35
  "Usage:",
33
- " frontend-harness context --json"
36
+ " frontend-harness context --json",
37
+ " frontend-harness context task --json \"<task>\" [--prd <prd-file>] [--api-source <openapi-file-or-url>] [--ui-source <ui-artifact-or-design-url>] [--limit <count>]",
38
+ "",
39
+ "`context task` builds a compact task packet from workflow policy, knowledge cards, and ingest provenance."
40
+ ],
41
+ ingest: [
42
+ "Usage:",
43
+ " frontend-harness ingest record --json --kind prd|openapi|ui-package --id <source-id> --source <file-or-url> --summary \"<summary>\" [--cards <ids>]",
44
+ " frontend-harness ingest list --json [--kind prd|openapi|ui-package]",
45
+ " frontend-harness ingest show --json --ref ingest://<kind>/<source-id>",
46
+ "",
47
+ "Records lightweight provenance for temporary PRD, OpenAPI, or UI package inputs."
34
48
  ],
35
49
  clean: [
36
50
  "Usage:",
@@ -43,10 +57,11 @@ const COMMAND_HELP = {
43
57
  ],
44
58
  plan: [
45
59
  "Usage:",
46
- " frontend-harness plan --json \"<task>\" [--prd <prd-file>] [--ui-source <ui-artifact-or-design-url>] [--agent-proposal <agent-proposal.json>]",
60
+ " frontend-harness plan --json \"<task>\" [--prd <prd-file>] [--api-source <openapi-file-or-url>] [--ui-source <ui-artifact-or-design-url>] [--agent-proposal <agent-proposal.json>]",
47
61
  "",
48
62
  "Flags:",
49
63
  " --prd <file> Project-relative PRD or requirement source.",
64
+ " --api-source <path-or-url> OpenAPI/Swagger source file or URL.",
50
65
  " --ui-source <path-or-url> UI source artifact or supported design URL.",
51
66
  " --agent-proposal <json-file> Bounded planning proposal envelope.",
52
67
  " --json Print machine-readable output."
@@ -112,6 +127,7 @@ const COMMAND_HELP = {
112
127
  knowledge: [
113
128
  "Usage:",
114
129
  " frontend-harness knowledge add --json --kind <kind> --subject \"<subject>\" <content-flag>",
130
+ " frontend-harness knowledge draft --json --ref ingest://<kind>/<source-id>",
115
131
  " frontend-harness knowledge module --json --id <id> --title \"<title>\" --summary \"<summary>\" --body \"<body>\"",
116
132
  " frontend-harness knowledge update --json --id <knowledge-id> [metadata flags]",
117
133
  " frontend-harness knowledge index --json",
@@ -147,6 +163,13 @@ const COMMAND_HELP = {
147
163
  " --status active|deprecated",
148
164
  " --stability stable|evolving"
149
165
  ],
166
+ "knowledge draft": [
167
+ "Usage:",
168
+ " frontend-harness knowledge draft --json --ref ingest://<kind>/<source-id>",
169
+ "",
170
+ "Builds a knowledge add scaffold from recorded ingest provenance.",
171
+ "Review the summary and replace placeholder content, coverage, verification, scope, and tags before adding durable knowledge."
172
+ ],
150
173
  "knowledge module": [
151
174
  "Usage:",
152
175
  " frontend-harness knowledge module --json --id <kebab-id> --title \"<title>\" --summary \"<summary>\" --body \"<body>\" [traceability flags]",
@@ -254,7 +277,10 @@ async function main() {
254
277
  }
255
278
  return;
256
279
  case "context":
257
- output(buildContext(projectRoot), parsed.json);
280
+ handleContext(projectRoot, parsed);
281
+ return;
282
+ case "ingest":
283
+ handleIngest(projectRoot, parsed);
258
284
  return;
259
285
  case "clean":
260
286
  output(cleanRuntimeArtifacts(projectRoot, {
@@ -266,6 +292,7 @@ async function main() {
266
292
  output(createPlan(projectRoot, {
267
293
  taskText: parsed.taskText,
268
294
  ...optionalString("prd", parsed.flags["prd"]),
295
+ ...optionalString("apiSource", parsed.flags["api-source"]),
269
296
  ...optionalString("uiSource", parsed.flags["ui-source"]),
270
297
  ...optionalString("agentProposal", parsed.flags["agent-proposal"])
271
298
  }), parsed.json);
@@ -348,11 +375,27 @@ async function main() {
348
375
  console.log(JSON.stringify({ error: message }, null, 2));
349
376
  }
350
377
  else {
351
- console.error(message);
378
+ console.error(humanField(message));
352
379
  }
353
380
  process.exitCode = 1;
354
381
  }
355
382
  }
383
+ function handleContext(projectRoot, parsed) {
384
+ if (parsed.subcommand === "task") {
385
+ output(buildCompactTaskContext(projectRoot, {
386
+ taskText: parsed.positionals.slice(2).join(" "),
387
+ ...optionalString("prd", parsed.flags["prd"]),
388
+ ...optionalString("apiSource", parsed.flags["api-source"]),
389
+ ...optionalString("uiSource", parsed.flags["ui-source"]),
390
+ ...optionalNumber("limit", parsed.flags["limit"])
391
+ }), parsed.json);
392
+ return;
393
+ }
394
+ if (parsed.subcommand) {
395
+ throw new Error("context requires subcommand: task");
396
+ }
397
+ output(buildContext(projectRoot), parsed.json);
398
+ }
356
399
  function handleEvidence(projectRoot, parsed) {
357
400
  if (parsed.subcommand === "template") {
358
401
  output(createEvidenceTemplate(projectRoot), parsed.json);
@@ -364,6 +407,27 @@ function handleEvidence(projectRoot, parsed) {
364
407
  }
365
408
  throw new Error("evidence requires subcommand: template or record");
366
409
  }
410
+ function handleIngest(projectRoot, parsed) {
411
+ if (parsed.subcommand === "record") {
412
+ output(recordIngestSource(projectRoot, {
413
+ ...optionalString("kind", parsed.flags["kind"]),
414
+ ...optionalString("id", parsed.flags["id"]),
415
+ ...optionalString("source", parsed.flags["source"]),
416
+ ...optionalString("summary", parsed.flags["summary"]),
417
+ ...optionalString("cards", parsed.flags["cards"])
418
+ }), parsed.json);
419
+ return;
420
+ }
421
+ if (parsed.subcommand === "list") {
422
+ output(listIngestRecords(projectRoot, stringFlag(parsed.flags["kind"])), parsed.json);
423
+ return;
424
+ }
425
+ if (parsed.subcommand === "show") {
426
+ output(showIngestRecord(projectRoot, stringFlag(parsed.flags["ref"])), parsed.json);
427
+ return;
428
+ }
429
+ throw new Error("ingest requires subcommand: record, list, or show");
430
+ }
367
431
  function handleVisual(projectRoot, parsed) {
368
432
  if (parsed.subcommand === "compare") {
369
433
  const result = compareVisualArtifacts(projectRoot, {
@@ -371,7 +435,7 @@ function handleVisual(projectRoot, parsed) {
371
435
  ...optionalString("actual", parsed.flags["actual"]),
372
436
  ...optionalString("diff", parsed.flags["diff"]),
373
437
  ...optionalString("report", parsed.flags["report"]),
374
- ...optionalNumber("threshold", parsed.flags["threshold"])
438
+ ...optionalFiniteNumber("threshold", parsed.flags["threshold"])
375
439
  });
376
440
  output(result, parsed.json);
377
441
  process.exitCode = result.status === "failed" ? 1 : 0;
@@ -424,7 +488,7 @@ function handleRepair(projectRoot, parsed) {
424
488
  }
425
489
  function handleSkills(projectRoot, parsed) {
426
490
  if (parsed.subcommand === "list") {
427
- output({ skills: discoverSkills(projectRoot) }, parsed.json);
491
+ output(listSkills(projectRoot), parsed.json);
428
492
  return;
429
493
  }
430
494
  if (parsed.subcommand === "check") {
@@ -458,6 +522,12 @@ function handleKnowledge(projectRoot, parsed) {
458
522
  }), parsed.json);
459
523
  return;
460
524
  }
525
+ if (parsed.subcommand === "draft") {
526
+ output(draftKnowledgeFromIngest(projectRoot, {
527
+ ...optionalString("ref", parsed.flags["ref"])
528
+ }), parsed.json);
529
+ return;
530
+ }
461
531
  if (parsed.subcommand === "promote") {
462
532
  output(promoteKnowledge(projectRoot, {
463
533
  ...optionalString("title", parsed.flags["title"]),
@@ -546,7 +616,7 @@ function handleKnowledge(projectRoot, parsed) {
546
616
  process.exitCode = result.status === "failed" ? 1 : 0;
547
617
  return;
548
618
  }
549
- throw new Error("knowledge requires subcommand: add, promote, module, update, index, coverage, list, search, show, or check");
619
+ throw new Error("knowledge requires subcommand: add, draft, promote, module, update, index, coverage, list, search, show, or check");
550
620
  }
551
621
  function requireSubcommand(parsed, subcommand, message) {
552
622
  if (parsed.subcommand !== subcommand) {
@@ -563,6 +633,12 @@ function parseArgs(args) {
563
633
  }
564
634
  if (arg.startsWith("--")) {
565
635
  const key = arg.slice(2);
636
+ if (key.includes("=")) {
637
+ throw new Error(`Unsupported flag assignment syntax: --${key}. Use --${key.split("=")[0]} <value>.`);
638
+ }
639
+ if (Object.prototype.hasOwnProperty.call(flags, key)) {
640
+ throw new Error(`Duplicate flag: --${key}`);
641
+ }
566
642
  if (["json", "from-git", "dry-run", "check", "help", "force", "include-deprecated"].includes(key)) {
567
643
  flags[key] = true;
568
644
  }
@@ -611,12 +687,13 @@ function allowedFlags(parsed) {
611
687
  const global = ["json", "help"];
612
688
  const commandFlags = {
613
689
  init: ["dry-run", "check"],
614
- context: [],
690
+ context: parsed.subcommand === "task" ? ["limit", "prd", "api-source", "ui-source"] : [],
615
691
  clean: ["dry-run", "keep-logs"],
616
- plan: ["prd", "ui-source", "agent-proposal"],
692
+ plan: ["prd", "api-source", "ui-source", "agent-proposal"],
617
693
  verify: ["typecheck", "test", "build"],
618
694
  visual: parsed.subcommand === "compare" ? ["design", "actual", "diff", "report", "threshold"] : [],
619
695
  evidence: parsed.subcommand === "record" ? ["file"] : [],
696
+ ingest: ingestFlags(parsed.subcommand),
620
697
  state: parsed.subcommand === "record-change" ? ["from-git"] : [],
621
698
  knowledge: knowledgeFlags(parsed.subcommand),
622
699
  protocol: [],
@@ -642,6 +719,8 @@ function knowledgeFlags(subcommand) {
642
719
  switch (subcommand) {
643
720
  case "add":
644
721
  return ["id", "kind", "subject", "summary", ...atomicContent, ...traceability, ...lifecycle];
722
+ case "draft":
723
+ return ["ref"];
645
724
  case "promote":
646
725
  return ["title", "body", "type", ...lifecycle];
647
726
  case "module":
@@ -663,6 +742,20 @@ function knowledgeFlags(subcommand) {
663
742
  return [];
664
743
  }
665
744
  }
745
+ function ingestFlags(subcommand) {
746
+ switch (subcommand) {
747
+ case "record":
748
+ return ["kind", "id", "source", "summary", "cards"];
749
+ case "list":
750
+ return ["kind"];
751
+ case "show":
752
+ return ["ref"];
753
+ case undefined:
754
+ return [];
755
+ default:
756
+ return [];
757
+ }
758
+ }
666
759
  function output(value, json) {
667
760
  if (json) {
668
761
  console.log(JSON.stringify(value, null, 2));
@@ -670,63 +763,199 @@ function output(value, json) {
670
763
  }
671
764
  console.log(renderHuman(value));
672
765
  }
766
+ const MAX_HUMAN_FIELD_CHARS = 240;
767
+ const MAX_HUMAN_PROMPT_CHARS = 4_000;
768
+ function humanField(value) {
769
+ const normalized = normalizeHumanField(value);
770
+ return normalized.length > MAX_HUMAN_FIELD_CHARS
771
+ ? `${normalized.slice(0, MAX_HUMAN_FIELD_CHARS - 3)}...`
772
+ : normalized;
773
+ }
774
+ function humanFieldTruncated(value) {
775
+ return normalizeHumanField(value).length > MAX_HUMAN_FIELD_CHARS;
776
+ }
777
+ function normalizeHumanField(value) {
778
+ return String(value ?? "unknown").replace(/\s+/g, " ").trim();
779
+ }
780
+ function humanBlock(value, maxChars) {
781
+ const text = String(value ?? "").trimEnd();
782
+ return text.length > maxChars ? `${text.slice(0, maxChars - 3)}...` : text;
783
+ }
784
+ function humanBlockTruncated(value, maxChars) {
785
+ return String(value ?? "").trimEnd().length > maxChars;
786
+ }
673
787
  function renderHuman(value) {
674
788
  if (!isRecord(value)) {
675
789
  return String(value);
676
790
  }
677
791
  if ("projectRoot" in value && "detectedStack" in value) {
678
792
  const context = value;
793
+ const knowledgeLimit = context.projectStatus?.knowledgeLimits;
794
+ const skillLimit = context.projectStatus?.skillLimits;
795
+ const planningDecision = context.projectStatus?.planningDecision;
796
+ const proposalLimits = planningDecision?.limits;
797
+ const evidence = planningDecision?.planningEvidence;
679
798
  return [
680
- `projectRoot: ${String(context.projectRoot ?? "unknown")}`,
681
- `packageManager: ${String(context.detectedStack?.packageManager ?? "unknown")}`,
682
- `framework: ${String(context.detectedStack?.framework ?? "unknown")}`,
683
- `language: ${String(context.detectedStack?.language ?? "unknown")}`
799
+ `projectRoot: ${humanField(context.projectRoot ?? "unknown")}`,
800
+ `packageManager: ${humanField(context.detectedStack?.packageManager ?? "unknown")}`,
801
+ `framework: ${humanField(context.detectedStack?.framework ?? "unknown")}`,
802
+ `language: ${humanField(context.detectedStack?.language ?? "unknown")}`,
803
+ `knowledge: ${Array.isArray(context.projectStatus?.knowledge) ? context.projectStatus.knowledge.length : 0}/${String(knowledgeLimit?.total ?? "unknown")}`,
804
+ `omittedKnowledge: ${String(knowledgeLimit?.omitted ?? 0)}`,
805
+ `skills: ${Array.isArray(context.projectStatus?.skills) ? context.projectStatus.skills.length : 0}/${String(skillLimit?.total ?? "unknown")}`,
806
+ `omittedSkills: ${String(skillLimit?.omitted ?? 0)}`,
807
+ ...(planningDecision ? [
808
+ `planningDecision: ${humanField(planningDecision.artifactPath ?? "unknown")}`,
809
+ `planningConstraintHints: ${String(proposalLimits?.constraintHints?.selected ?? (Array.isArray(planningDecision.constraintHints) ? planningDecision.constraintHints.length : 0))}/${String(proposalLimits?.constraintHints?.max ?? "unknown")}`,
810
+ `planningComponentHints: ${String(proposalLimits?.componentHints?.selected ?? (Array.isArray(planningDecision.componentHints) ? planningDecision.componentHints.length : 0))}/${String(proposalLimits?.componentHints?.max ?? "unknown")}`,
811
+ `planningWorkflowCandidates: ${String(proposalLimits?.workflowCandidates?.selected ?? (Array.isArray(evidence?.workflowCandidates) ? evidence.workflowCandidates.length : 0))}/${String(proposalLimits?.workflowCandidates?.max ?? "unknown")}`,
812
+ `planningTargetCandidates: ${String(proposalLimits?.targetCandidates?.selected ?? (Array.isArray(evidence?.targetCandidates) ? evidence.targetCandidates.length : 0))}/${String(proposalLimits?.targetCandidates?.max ?? "unknown")}`,
813
+ `planningVerificationCandidates: ${String(proposalLimits?.verificationCandidates?.selected ?? (Array.isArray(evidence?.verificationCandidates) ? evidence.verificationCandidates.length : 0))}/${String(proposalLimits?.verificationCandidates?.max ?? "unknown")}`,
814
+ `planningAmbiguities: ${String(proposalLimits?.ambiguities?.selected ?? (Array.isArray(evidence?.ambiguities) ? evidence.ambiguities.length : 0))}/${String(proposalLimits?.ambiguities?.max ?? "unknown")}`
815
+ ] : [])
684
816
  ].join("\n");
685
817
  }
686
818
  if ("task" in value && "units" in value && Array.isArray(value["units"])) {
687
819
  const plan = value;
820
+ const guidanceLimits = plan.limits?.guidance;
821
+ return [
822
+ `intent: ${humanField(plan.task?.intent)}`,
823
+ `scope: ${humanField(plan.task?.scope)}`,
824
+ `components: ${Array.isArray(plan.components) ? plan.components.length : 0}`,
825
+ `units: ${plan.units.length}`,
826
+ `guidanceComponents: ${String(guidanceLimits?.components?.selected ?? "unknown")}/${String(guidanceLimits?.components?.total ?? "unknown")}`,
827
+ `omittedGuidanceComponents: ${String(guidanceLimits?.components?.omitted ?? 0)}`,
828
+ `guidanceUnits: ${String(guidanceLimits?.units?.selected ?? "unknown")}/${String(guidanceLimits?.units?.total ?? "unknown")}`,
829
+ `omittedGuidanceUnits: ${String(guidanceLimits?.units?.omitted ?? 0)}`,
830
+ `guidancePath: ${humanField(plan.guidancePath ?? "unknown")}`,
831
+ `componentGraphPath: ${humanField(plan.componentGraphPath ?? "unknown")}`,
832
+ `statePath: ${humanField(plan.statePath ?? "unknown")}`
833
+ ].join("\n");
834
+ }
835
+ if ("task" in value && "workflow" in value && "prompt" in value) {
836
+ const taskContext = value;
837
+ const sourceHintCount = [
838
+ taskContext.sourceHints?.endpoints,
839
+ taskContext.sourceHints?.prdCoverage,
840
+ taskContext.sourceHints?.uiArtifacts,
841
+ taskContext.sourceHints?.apiImplementations
842
+ ].reduce((total, group) => total + (Array.isArray(group) ? group.length : 0), 0);
843
+ const prompt = String(taskContext.prompt ?? "");
688
844
  return [
689
- `intent: ${String(plan.task?.intent ?? "unknown")}`,
690
- `scope: ${String(plan.task?.scope ?? "unknown")}`,
691
- `units: ${plan.units.length}`
845
+ `task: ${humanField(taskContext.task)}`,
846
+ `workflow: ${humanField(taskContext.workflow?.kind)}`,
847
+ `knowledge: ${Array.isArray(taskContext.selectedKnowledge) ? taskContext.selectedKnowledge.length : 0}`,
848
+ `ingestSources: ${Array.isArray(taskContext.selectedIngestSources) ? taskContext.selectedIngestSources.length : 0}`,
849
+ `projectFiles: ${Array.isArray(taskContext.selectedProjectFiles) ? taskContext.selectedProjectFiles.length : 0}`,
850
+ `sourceHints: ${sourceHintCount}`,
851
+ `omittedKnowledge: ${String(taskContext.limits?.omittedSelectedKnowledge ?? 0)}`,
852
+ `omittedKnowledgeSourcePaths: ${String(taskContext.limits?.omittedSelectedKnowledgeSourcePaths ?? 0)}`,
853
+ `omittedKnowledgeCoverage: ${String(taskContext.limits?.omittedSelectedKnowledgeCoverage ?? 0)}`,
854
+ `omittedKnowledgeVerification: ${String(taskContext.limits?.omittedSelectedKnowledgeVerification ?? 0)}`,
855
+ `omittedIngestSources: ${String(taskContext.limits?.omittedSelectedIngestSources ?? 0)}`,
856
+ `omittedIngestProducedKnowledgeCardIds: ${String(taskContext.limits?.omittedSelectedIngestProducedKnowledgeCardIds ?? 0)}`,
857
+ `omittedProjectFiles: ${String(taskContext.limits?.omittedSelectedProjectFiles ?? 0)}`,
858
+ `omittedSourceHints: ${String(taskContext.limits?.omittedSourceHints ?? 0)}`,
859
+ `omittedPrdCoverageHintCoverage: ${String(taskContext.limits?.omittedPrdCoverageHintCoverage ?? 0)}`,
860
+ `omittedPrdCoverageHintAnchors: ${String(taskContext.limits?.omittedPrdCoverageHintAnchors ?? 0)}`,
861
+ `omittedPrdCoverageHintSourcePaths: ${String(taskContext.limits?.omittedPrdCoverageHintSourcePaths ?? 0)}`,
862
+ `projectFilesScanned: ${String(taskContext.limits?.totalScannedProjectFiles ?? 0)}/${String(taskContext.limits?.scannedProjectFiles ?? "unknown")}`,
863
+ `projectFileScanLimitReached: ${String(taskContext.limits?.projectFileScanLimitReached ?? false)}`,
864
+ `skippedPrdSourceHintSources: ${String(taskContext.limits?.skippedPrdSourceHintSources ?? 0)}`,
865
+ `skippedApiSourceHintSources: ${String(taskContext.limits?.skippedApiSourceHintSources ?? 0)}`,
866
+ `artifactPath: ${humanField(taskContext.artifactPath ?? "unknown")}`,
867
+ `promptChars: ${String(prompt.length)}`,
868
+ `promptTruncated: ${String(humanBlockTruncated(prompt, MAX_HUMAN_PROMPT_CHARS))}`,
869
+ "",
870
+ humanBlock(prompt, MAX_HUMAN_PROMPT_CHARS)
692
871
  ].join("\n");
693
872
  }
694
873
  if ("results" in value && Array.isArray(value["results"])) {
695
874
  const verification = value;
875
+ const selectedResults = verification.results.slice(0, MAX_HUMAN_VERIFICATION_RESULTS);
876
+ const omittedResults = Math.max(0, verification.results.length - selectedResults.length);
696
877
  return [
697
- `status: ${String(verification.status ?? "unknown")}`,
878
+ `status: ${humanField(verification.status ?? "unknown")}`,
698
879
  `results: ${verification.results.length}`,
699
- ...verification.results.map((item) => `- ${String(item.name ?? "verification")}: ${String(item.status ?? "unknown")} (${String(item.exitCode ?? "n/a")})`)
880
+ `omittedResults: ${String(omittedResults)}`,
881
+ ...selectedResults.map((item) => `- ${humanField(item.name ?? "verification")}: ${humanField(item.status ?? "unknown")} (${String(item.exitCode ?? "n/a")})`)
882
+ ].join("\n");
883
+ }
884
+ if ("manifestPath" in value && "entries" in value && "instructions" in value) {
885
+ const template = value;
886
+ const entryLimits = template.limits?.entries;
887
+ return [
888
+ `status: ${humanField(template.status ?? "unknown")}`,
889
+ `manifestPath: ${humanField(template.manifestPath ?? "unknown")}`,
890
+ `entries: ${String(entryLimits?.selected ?? (Array.isArray(template.entries) ? template.entries.length : 0))}/${String(entryLimits?.total ?? (Array.isArray(template.entries) ? template.entries.length : 0))}`,
891
+ `omittedEntries: ${String(entryLimits?.omitted ?? 0)}`
892
+ ].join("\n");
893
+ }
894
+ if ("recordedEntries" in value && "entryCount" in value && "provenance" in value) {
895
+ const evidence = value;
896
+ const selectedSourceLimit = evidence.provenance?.limits?.selectedEvidenceSources ?? "unknown";
897
+ return [
898
+ `status: ${humanField(evidence.status ?? "unknown")}`,
899
+ `inputPath: ${humanField(evidence.inputPath ?? "unknown")}`,
900
+ `manifestPath: ${humanField(evidence.manifestPath ?? "unknown")}`,
901
+ `recordedEntries: ${Array.isArray(evidence.recordedEntries) ? evidence.recordedEntries.length : 0}`,
902
+ `entryCount: ${String(evidence.entryCount ?? 0)}`,
903
+ `planArtifactPath: ${humanField(evidence.provenance?.planArtifactPath ?? "none")}`,
904
+ `taskContextArtifactPath: ${humanField(evidence.provenance?.taskContextArtifactPath ?? "none")}`,
905
+ `selectedApiContractSources: ${Array.isArray(evidence.provenance?.selectedApiContractSources) ? evidence.provenance.selectedApiContractSources.length : 0}/${String(selectedSourceLimit)}`,
906
+ `omittedSelectedApiContractSources: ${String(evidence.provenance?.limits?.omittedSelectedApiContractSources ?? 0)}`,
907
+ `selectedUiSources: ${Array.isArray(evidence.provenance?.selectedUiSources) ? evidence.provenance.selectedUiSources.length : 0}/${String(selectedSourceLimit)}`,
908
+ `omittedSelectedUiSources: ${String(evidence.provenance?.limits?.omittedSelectedUiSources ?? 0)}`,
909
+ `selectedIngestSources: ${Array.isArray(evidence.provenance?.selectedIngestSources) ? evidence.provenance.selectedIngestSources.length : 0}/${String(selectedSourceLimit)}`,
910
+ `omittedSelectedIngestSources: ${String(evidence.provenance?.limits?.omittedSelectedIngestSources ?? 0)}`
700
911
  ].join("\n");
701
912
  }
702
913
  if ("comparisonTool" in value && "score" in value) {
703
914
  const comparison = value;
704
915
  return [
705
- `status: ${String(comparison.status ?? "unknown")}`,
916
+ `status: ${humanField(comparison.status ?? "unknown")}`,
706
917
  `score: ${String(comparison.score ?? "unknown")}`,
707
918
  `threshold: ${String(comparison.threshold ?? "unknown")}`,
708
919
  `changedPixels: ${String(comparison.changedPixels ?? "unknown")}`,
709
920
  `changedRatio: ${String(comparison.changedRatio ?? "unknown")}`,
710
- `diffPath: ${String(comparison.diffPath ?? "unknown")}`,
921
+ `diffPath: ${humanField(comparison.diffPath ?? "unknown")}`,
711
922
  ...(Array.isArray(comparison.limitations) && comparison.limitations.length
712
- ? [`limitations: ${comparison.limitations.map((item) => String(item)).join(" ")}`]
923
+ ? [`limitations: ${comparison.limitations.map((item) => humanField(item)).join(" ")}`]
713
924
  : [])
714
925
  ].join("\n");
715
926
  }
716
927
  if ("action" in value && "stateStatus" in value) {
717
928
  const next = value;
929
+ const changedFileLimit = next.limits?.changedFiles;
930
+ return [
931
+ `action: ${humanField(next.action ?? "unknown")}`,
932
+ `reason: ${humanField(next.reason ?? "unknown")}`,
933
+ `command: ${humanField(next.command ?? "none")}`,
934
+ `changedFiles: ${String(changedFileLimit?.selected ?? (Array.isArray(next.changedFiles) ? next.changedFiles.length : 0))}/${String(changedFileLimit?.total ?? (Array.isArray(next.changedFiles) ? next.changedFiles.length : 0))}`,
935
+ `omittedChangedFiles: ${String(changedFileLimit?.omitted ?? 0)}`
936
+ ].join("\n");
937
+ }
938
+ if ("nextAction" in value && "requiredArtifacts" in value && "recommendedCommands" in value) {
939
+ const explain = value;
940
+ const markdownLimits = explain.limits?.markdown;
718
941
  return [
719
- `action: ${String(next.action ?? "unknown")}`,
720
- `reason: ${String(next.reason ?? "unknown")}`,
721
- `command: ${String(next.command ?? "none")}`
942
+ `action: ${humanField(explain.nextAction?.action ?? "unknown")}`,
943
+ `summary: ${humanField(explain.summary ?? "unknown")}`,
944
+ `rationale: ${String(markdownLimits?.rationale?.selected ?? "unknown")}/${String(markdownLimits?.rationale?.total ?? "unknown")}`,
945
+ `omittedRationale: ${String(markdownLimits?.rationale?.omitted ?? 0)}`,
946
+ `requiredArtifacts: ${String(markdownLimits?.requiredArtifacts?.selected ?? (Array.isArray(explain.requiredArtifacts) ? explain.requiredArtifacts.length : 0))}/${String(markdownLimits?.requiredArtifacts?.total ?? (Array.isArray(explain.requiredArtifacts) ? explain.requiredArtifacts.length : 0))}`,
947
+ `omittedRequiredArtifacts: ${String(markdownLimits?.requiredArtifacts?.omitted ?? 0)}`,
948
+ `recommendedCommands: ${String(markdownLimits?.recommendedCommands?.selected ?? (Array.isArray(explain.recommendedCommands) ? explain.recommendedCommands.length : 0))}/${String(markdownLimits?.recommendedCommands?.total ?? (Array.isArray(explain.recommendedCommands) ? explain.recommendedCommands.length : 0))}`,
949
+ `omittedRecommendedCommands: ${String(markdownLimits?.recommendedCommands?.omitted ?? 0)}`,
950
+ `stopCondition: ${humanField(explain.stopCondition ?? "unknown")}`
722
951
  ].join("\n");
723
952
  }
724
953
  if ("changedFiles" in value && "verification" in value) {
725
954
  const state = value;
726
955
  return [
727
- `status: ${String(state.status ?? "unknown")}`,
956
+ `status: ${humanField(state.status ?? "unknown")}`,
728
957
  `changedFiles: ${Array.isArray(state.changedFiles) ? state.changedFiles.length : 0}`,
729
- `verification: ${String(state.verification?.status ?? "unknown")}`,
958
+ `verification: ${humanField(state.verification?.status ?? "unknown")}`,
730
959
  `retryCount: ${String(state.retryCount ?? 0)}`
731
960
  ].join("\n");
732
961
  }
@@ -740,41 +969,80 @@ function renderHuman(value) {
740
969
  }
741
970
  if ("skills" in value && Array.isArray(value["skills"])) {
742
971
  const skills = value["skills"];
743
- return [`skills: ${skills.length}`, ...skills.map((skill) => `- ${String(skill.name ?? "unknown")}: ${String(skill.title ?? "unknown")} (${String(skill.path ?? "unknown")})`)].join("\n");
972
+ const limits = value["limits"];
973
+ const selected = limits?.selected ?? skills.length;
974
+ const total = limits?.total ?? skills.length;
975
+ return [
976
+ `skills: ${String(selected)}/${String(total)}`,
977
+ `omittedSkills: ${String(limits?.omitted ?? 0)}`,
978
+ ...skills.map((skill) => `- ${humanField(skill.name)}: ${humanField(skill.title)} (${humanField(skill.path)})`)
979
+ ].join("\n");
744
980
  }
745
- if ("cards" in value && Array.isArray(value["cards"])) {
746
- const cards = value["cards"];
981
+ if ("records" in value && Array.isArray(value["records"])) {
982
+ const records = value["records"];
983
+ const limits = value["limits"];
984
+ const selected = limits?.selected ?? records.length;
985
+ const total = limits?.total ?? records.length;
747
986
  return [
748
- `cards: ${cards.length}`,
749
- ...cards.map((card) => {
750
- const score = card.score === undefined ? "" : ` score=${String(card.score)}`;
751
- return `- ${String(card.id ?? "unknown")}: ${String(card.title ?? "unknown")} (${String(card.path ?? "unknown")})${score}`;
752
- })
987
+ `records: ${String(selected)}/${String(total)}`,
988
+ `omittedRecords: ${String(limits?.omitted ?? 0)}`,
989
+ ...records.map((record) => `- ${humanField(record.ingestRef)}: ${humanField(record.summary)} (${humanField(record.artifactPath)})`)
753
990
  ].join("\n");
754
991
  }
755
- if ("card" in value && "body" in value) {
756
- const shown = value;
992
+ if ("ingestRef" in value && "source" in value && "producedKnowledgeCardIds" in value) {
993
+ const record = value;
757
994
  return [
758
- `id: ${String(shown.card?.id ?? "unknown")}`,
759
- `title: ${String(shown.card?.title ?? "unknown")}`,
760
- `path: ${String(shown.card?.path ?? "unknown")}`,
761
- "",
762
- String(shown.body ?? "")
995
+ `ingestRef: ${humanField(record.ingestRef)}`,
996
+ `kind: ${humanField(record.kind)}`,
997
+ `source: ${humanField(record.source?.value)}`,
998
+ `sha256: ${humanField(record.source?.sha256 ?? "none")}`,
999
+ `cards: ${Array.isArray(record.producedKnowledgeCardIds) ? record.producedKnowledgeCardIds.length : 0}`,
1000
+ `artifactPath: ${humanField(record.artifactPath)}`
763
1001
  ].join("\n");
764
1002
  }
765
1003
  if ("artifactPath" in value && "prdSourceCount" in value) {
766
1004
  const index = value;
1005
+ const cardLimits = index.limits?.cards;
767
1006
  return [
768
- `artifactPath: ${String(index.artifactPath ?? "unknown")}`,
1007
+ `artifactPath: ${humanField(index.artifactPath ?? "unknown")}`,
769
1008
  `cardCount: ${String(index.cardCount ?? 0)}`,
1009
+ `cards: ${String(cardLimits?.selected ?? index.cardCount ?? 0)}/${String(cardLimits?.total ?? index.cardCount ?? 0)}`,
1010
+ `omittedCards: ${String(cardLimits?.omitted ?? 0)}`,
770
1011
  `prdSourceCount: ${String(index.prdSourceCount ?? 0)}`,
771
1012
  `uncoveredPrdSourceCount: ${String(index.uncoveredPrdSourceCount ?? 0)}`
772
1013
  ].join("\n");
773
1014
  }
1015
+ if ("cards" in value && Array.isArray(value["cards"])) {
1016
+ const cards = value["cards"];
1017
+ const limits = value["limits"];
1018
+ const selected = limits?.selected ?? cards.length;
1019
+ const total = limits?.total ?? cards.length;
1020
+ return [
1021
+ `cards: ${String(selected)}${limits ? `/${String(total)}` : ""}`,
1022
+ ...(limits ? [`omittedCards: ${String(limits.omitted ?? 0)}`] : []),
1023
+ ...cards.map((card) => {
1024
+ const score = card.score === undefined ? "" : ` score=${String(card.score)}`;
1025
+ return `- ${humanField(card.id)}: ${humanField(card.title)} (${humanField(card.path)})${score}`;
1026
+ })
1027
+ ].join("\n");
1028
+ }
1029
+ if ("card" in value && "body" in value) {
1030
+ const shown = value;
1031
+ const body = String(shown.body ?? "");
1032
+ return [
1033
+ `id: ${humanField(shown.card?.id)}`,
1034
+ `title: ${humanField(shown.card?.title)}`,
1035
+ `path: ${humanField(shown.card?.path)}`,
1036
+ `bodyChars: ${String(body.length)}`,
1037
+ `bodyTruncated: ${String(humanFieldTruncated(body))}`,
1038
+ "",
1039
+ humanField(body)
1040
+ ].join("\n");
1041
+ }
774
1042
  if ("coveredPrdSourceCount" in value && "uncoveredPrdSources" in value) {
775
1043
  const coverage = value;
776
1044
  return [
777
- `status: ${String(coverage.status ?? "unknown")}`,
1045
+ `status: ${humanField(coverage.status ?? "unknown")}`,
778
1046
  `prdSourceCount: ${String(coverage.prdSourceCount ?? 0)}`,
779
1047
  `coveredPrdSourceCount: ${String(coverage.coveredPrdSourceCount ?? 0)}`,
780
1048
  `uncoveredPrdSources: ${Array.isArray(coverage.uncoveredPrdSources) ? coverage.uncoveredPrdSources.length : 0}`,
@@ -783,7 +1051,19 @@ function renderHuman(value) {
783
1051
  }
784
1052
  if ("path" in value && "title" in value) {
785
1053
  const knowledge = value;
786
- return [`path: ${String(knowledge.path ?? "unknown")}`, `title: ${String(knowledge.title ?? "unknown")}`, `createdAt: ${String(knowledge.createdAt ?? "unknown")}`].join("\n");
1054
+ return [`path: ${humanField(knowledge.path)}`, `title: ${humanField(knowledge.title)}`, `createdAt: ${humanField(knowledge.createdAt)}`].join("\n");
1055
+ }
1056
+ if ("ingestRef" in value && "recommendedAction" in value && "updateCandidates" in value) {
1057
+ const draft = value;
1058
+ const candidateLimits = draft.limits?.updateCandidates;
1059
+ return [
1060
+ `ingestRef: ${humanField(draft.ingestRef ?? "unknown")}`,
1061
+ `recommendedAction: ${humanField(draft.recommendedAction ?? "unknown")}`,
1062
+ `recommendedKind: ${humanField(draft.recommendedKind ?? "unknown")}`,
1063
+ `recommendedType: ${humanField(draft.recommendedType ?? "unknown")}`,
1064
+ `updateCandidates: ${String(candidateLimits?.selected ?? (Array.isArray(draft.updateCandidates) ? draft.updateCandidates.length : 0))}/${String(candidateLimits?.total ?? (Array.isArray(draft.updateCandidates) ? draft.updateCandidates.length : 0))}`,
1065
+ `omittedUpdateCandidates: ${String(candidateLimits?.omitted ?? 0)}`
1066
+ ].join("\n");
787
1067
  }
788
1068
  if ("artifactPath" in value && "unitCount" in value) {
789
1069
  return renderCheck(value, "unitCount");
@@ -791,30 +1071,53 @@ function renderHuman(value) {
791
1071
  if ("artifactPath" in value && "nodeCount" in value) {
792
1072
  return renderCheck(value, "nodeCount");
793
1073
  }
1074
+ if ("artifactPath" in value && "proposal" in value) {
1075
+ const checked = value;
1076
+ const evidence = checked.proposal?.planningEvidence;
1077
+ return [
1078
+ `status: ${humanField(checked.status ?? "unknown")}`,
1079
+ `artifactPath: ${humanField(checked.artifactPath)}`,
1080
+ `constraintHints: ${String(checked.limits?.constraintHints?.selected ?? (Array.isArray(checked.proposal?.constraintHints) ? checked.proposal.constraintHints.length : 0))}/${String(checked.limits?.constraintHints?.max ?? "unknown")}`,
1081
+ `componentHints: ${String(checked.limits?.componentHints?.selected ?? (Array.isArray(checked.proposal?.componentHints) ? checked.proposal.componentHints.length : 0))}/${String(checked.limits?.componentHints?.max ?? "unknown")}`,
1082
+ `workflowCandidates: ${String(checked.limits?.workflowCandidates?.selected ?? (Array.isArray(evidence?.workflowCandidates) ? evidence.workflowCandidates.length : 0))}/${String(checked.limits?.workflowCandidates?.max ?? "unknown")}`,
1083
+ `targetCandidates: ${String(checked.limits?.targetCandidates?.selected ?? (Array.isArray(evidence?.targetCandidates) ? evidence.targetCandidates.length : 0))}/${String(checked.limits?.targetCandidates?.max ?? "unknown")}`,
1084
+ `verificationCandidates: ${String(checked.limits?.verificationCandidates?.selected ?? (Array.isArray(evidence?.verificationCandidates) ? evidence.verificationCandidates.length : 0))}/${String(checked.limits?.verificationCandidates?.max ?? "unknown")}`,
1085
+ `ambiguities: ${String(checked.limits?.ambiguities?.selected ?? (Array.isArray(evidence?.ambiguities) ? evidence.ambiguities.length : 0))}/${String(checked.limits?.ambiguities?.max ?? "unknown")}`,
1086
+ ...(Array.isArray(checked.errors) && checked.errors.length ? checked.errors.map((error) => `error: ${humanField(error)}`) : [])
1087
+ ].join("\n");
1088
+ }
794
1089
  if ("skillsRoot" in value && "skillCount" in value) {
795
1090
  return renderCheck(value, "skillCount");
796
1091
  }
797
1092
  if ("knowledgeRoot" in value && "cardCount" in value) {
798
1093
  return renderCheck(value, "cardCount");
799
1094
  }
800
- if ("artifactPath" in value && ("proposal" in value || "decision" in value)) {
1095
+ if ("artifactPath" in value && "decision" in value) {
801
1096
  return renderCheck(value, null);
802
1097
  }
803
1098
  if ("contractVersion" in value && "failedCommands" in value) {
804
1099
  const packet = value;
805
1100
  return [
806
- `status: ${String(packet.status ?? "unknown")}`,
807
- `verificationStatus: ${String(packet.verificationStatus ?? "unknown")}`,
808
- `failedCommands: ${Array.isArray(packet.failedCommands) ? packet.failedCommands.length : 0}`
1101
+ `status: ${humanField(packet.status ?? "unknown")}`,
1102
+ `verificationStatus: ${humanField(packet.verificationStatus ?? "unknown")}`,
1103
+ `changedFiles: ${Array.isArray(packet.changedFiles) ? packet.changedFiles.length : 0}/${String(packet.limits?.totalChangedFiles ?? "unknown")}`,
1104
+ `omittedChangedFiles: ${String(packet.limits?.omittedChangedFiles ?? 0)}`,
1105
+ `failedCommands: ${Array.isArray(packet.failedCommands) ? packet.failedCommands.length : 0}/${String(packet.limits?.totalFailedCommands ?? "unknown")}`,
1106
+ `omittedFailedCommands: ${String(packet.limits?.omittedFailedCommands ?? 0)}`,
1107
+ `retryGuidanceFailedCommands: ${Array.isArray(packet.retryGuidance?.failedCommands) ? packet.retryGuidance.failedCommands.length : 0}/${String(packet.limits?.totalRetryGuidanceFailedCommands ?? "unknown")}`,
1108
+ `omittedRetryGuidanceFailedCommands: ${String(packet.limits?.omittedRetryGuidanceFailedCommands ?? 0)}`,
1109
+ `retryGuidanceLogs: ${Array.isArray(packet.retryGuidance?.logs) ? packet.retryGuidance.logs.length : 0}/${String(packet.limits?.totalRetryGuidanceLogs ?? "unknown")}`,
1110
+ `omittedRetryGuidanceLogs: ${String(packet.limits?.omittedRetryGuidanceLogs ?? 0)}`,
1111
+ `retryGuidanceInstructionTruncated: ${String(packet.limits?.retryGuidanceInstructionTruncated ?? false)}`
809
1112
  ].join("\n");
810
1113
  }
811
1114
  if ("contractVersion" in value && "files" in value) {
812
1115
  const init = value;
813
1116
  return [
814
1117
  `dryRun: ${String(init.dryRun ?? false)}`,
815
- `needsUpdate: ${String(init.needsUpdate ?? "unknown")}`,
816
- ...(Array.isArray(init.files) ? init.files.map((file) => `${String(file.path ?? "unknown")}: ${String(file.action ?? "unknown")}`) : []),
817
- ...(Array.isArray(init.skills) ? init.skills.map((skill) => `${String(skill.path ?? "unknown")}: ${String(skill.action ?? "unknown")}`) : [])
1118
+ `needsUpdate: ${humanField(init.needsUpdate ?? "unknown")}`,
1119
+ ...(Array.isArray(init.files) ? init.files.map((file) => `${humanField(file.path ?? "unknown")}: ${humanField(file.action ?? "unknown")}`) : []),
1120
+ ...(Array.isArray(init.skills) ? init.skills.map((skill) => `${humanField(skill.path ?? "unknown")}: ${humanField(skill.action ?? "unknown")}`) : [])
818
1121
  ].join("\n");
819
1122
  }
820
1123
  if ("removed" in value && "kept" in value) {
@@ -828,30 +1131,36 @@ function renderHuman(value) {
828
1131
  if ("preset" in value && "files" in value && Array.isArray(value["files"])) {
829
1132
  const scaffold = value;
830
1133
  return [
831
- `status: ${String(scaffold.status ?? "unknown")}`,
832
- `preset: ${String(scaffold.preset ?? "unknown")}`,
833
- `target: ${String(scaffold.target ?? "unknown")}`,
834
- `projectName: ${String(scaffold.projectName ?? "unknown")}`,
1134
+ `status: ${humanField(scaffold.status ?? "unknown")}`,
1135
+ `preset: ${humanField(scaffold.preset ?? "unknown")}`,
1136
+ `target: ${humanField(scaffold.target ?? "unknown")}`,
1137
+ `projectName: ${humanField(scaffold.projectName ?? "unknown")}`,
835
1138
  `files: ${scaffold.files.length}`
836
1139
  ].join("\n");
837
1140
  }
838
1141
  if ("status" in value) {
839
- return `status: ${String(value["status"])}`;
1142
+ return `status: ${humanField(value["status"])}`;
840
1143
  }
841
1144
  return JSON.stringify(value, null, 2);
842
1145
  }
843
1146
  function renderCheck(value, countKey) {
1147
+ const errors = Array.isArray(value["errors"]) ? value["errors"] : [];
1148
+ const warnings = Array.isArray(value["warnings"]) ? value["warnings"] : [];
1149
+ const selectedErrors = errors.slice(0, 5);
1150
+ const selectedWarnings = warnings.slice(0, 5);
844
1151
  const lines = [
845
- `status: ${String(value["status"] ?? "unknown")}`,
846
- ...(value["artifactPath"] ? [`artifactPath: ${String(value["artifactPath"])}`] : []),
847
- ...(value["skillsRoot"] ? [`skillsRoot: ${String(value["skillsRoot"])}`] : []),
848
- ...(countKey ? [`${countKey}: ${String(value[countKey] ?? 0)}`] : [])
1152
+ `status: ${humanField(value["status"] ?? "unknown")}`,
1153
+ ...(value["artifactPath"] ? [`artifactPath: ${humanField(value["artifactPath"])}`] : []),
1154
+ ...(value["skillsRoot"] ? [`skillsRoot: ${humanField(value["skillsRoot"])}`] : []),
1155
+ ...(countKey ? [`${countKey}: ${String(value[countKey] ?? 0)}`] : []),
1156
+ `omittedErrors: ${String(Math.max(0, errors.length - selectedErrors.length))}`,
1157
+ `omittedWarnings: ${String(Math.max(0, warnings.length - selectedWarnings.length))}`
849
1158
  ];
850
- for (const error of (Array.isArray(value["errors"]) ? value["errors"] : []).slice(0, 5)) {
851
- lines.push(`error: ${String(error)}`);
1159
+ for (const error of selectedErrors) {
1160
+ lines.push(`error: ${humanField(error)}`);
852
1161
  }
853
- for (const warning of (Array.isArray(value["warnings"]) ? value["warnings"] : []).slice(0, 5)) {
854
- lines.push(`warning: ${String(warning)}`);
1162
+ for (const warning of selectedWarnings) {
1163
+ lines.push(`warning: ${humanField(warning)}`);
855
1164
  }
856
1165
  return lines.join("\n");
857
1166
  }
@@ -892,6 +1201,19 @@ function optionalNumber(key, value) {
892
1201
  }
893
1202
  return { [key]: parsed };
894
1203
  }
1204
+ function optionalFiniteNumber(key, value) {
1205
+ if (value === undefined) {
1206
+ return {};
1207
+ }
1208
+ if (typeof value !== "string") {
1209
+ throw new Error("numeric flag requires a value");
1210
+ }
1211
+ const parsed = Number(value);
1212
+ if (!Number.isFinite(parsed)) {
1213
+ throw new Error(`Invalid numeric value: ${value}`);
1214
+ }
1215
+ return { [key]: parsed };
1216
+ }
895
1217
  function isRecord(value) {
896
1218
  return typeof value === "object" && value !== null;
897
1219
  }