@sushanglewis/lincoln 1.6.3 → 1.7.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 (45) hide show
  1. package/framework/.claude/agents/pm.md +2 -2
  2. package/framework/.claude/agents/security-reviewer.md +57 -0
  3. package/framework/.claude/harnesses/codex.yaml +31 -2
  4. package/framework/.claude/harnesses/command-map.yaml +4 -0
  5. package/framework/.claude/harnesses/opencode.yaml +33 -3
  6. package/framework/.claude/hooks/hooks.yaml +37 -0
  7. package/framework/.claude/hooks/on-session-start.sh +20 -5
  8. package/framework/.claude/hooks/on-stop.sh +22 -0
  9. package/framework/.claude/hooks/pre-tool-use.sh +22 -0
  10. package/framework/.claude/mcp/mcp.yaml +34 -0
  11. package/framework/.claude/policies/friction.yaml +18 -0
  12. package/framework/.claude/policies/security.yaml +46 -0
  13. package/framework/.claude/schemas/design-review-feedback.json +32 -0
  14. package/framework/.claude/schemas/stage-definition.schema.json +22 -0
  15. package/framework/.claude/skills/clarify-requirements/SKILL.md +1 -0
  16. package/framework/.claude/skills/clarify-requirements/prompts/main.md +44 -10
  17. package/framework/.claude/stages/clarify.yaml +3 -1
  18. package/framework/.claude/stages/phase-1-p0-design.yaml +44 -0
  19. package/framework/.claude/stages/phase-1-p0-implement.yaml +47 -0
  20. package/framework/.claude/stages/phase-2-p1-design.yaml +53 -0
  21. package/framework/.claude/stages/phase-2-p1-implement.yaml +45 -0
  22. package/framework/.claude/workflows/framework-self-improvement.yaml +100 -0
  23. package/framework/.claude/workflows/interview-to-knowledge.yaml +1 -0
  24. package/framework/.claude-plugin/marketplace.json +2 -2
  25. package/framework/.claude-plugin/plugin.json +1 -1
  26. package/framework/.version-bump.json +1 -1
  27. package/framework/README.en.md +24 -5
  28. package/framework/README.md +24 -5
  29. package/framework/RELEASE.md +22 -0
  30. package/framework/SKILL.md +15 -6
  31. package/framework/manifest.json +93 -37
  32. package/framework/scripts/check-harness-drift.sh +11 -1
  33. package/framework/scripts/lincoln-setup.py +17 -0
  34. package/framework/scripts/lincoln_condenser.py +110 -0
  35. package/framework/scripts/lincoln_friction.py +266 -0
  36. package/framework/scripts/lincoln_harness_adapter.py +185 -13
  37. package/framework/scripts/lincoln_mr_mine.py +146 -0
  38. package/framework/scripts/lincoln_recall.py +142 -0
  39. package/framework/scripts/lincoln_trace.py +119 -3
  40. package/framework/scripts/security_analyzer.py +234 -0
  41. package/framework/scripts/stage_loader.py +124 -1
  42. package/framework/tools/lincoln/package-lock.json +2 -2
  43. package/framework/tools/lincoln/package.json +1 -1
  44. package/framework/tools/lincoln-installer/package.json +6 -1
  45. package/package.json +6 -1
@@ -36,7 +36,7 @@ if str(PROJECT_ROOT) not in sys.path:
36
36
 
37
37
  import yaml
38
38
 
39
- from scripts import lincoln_trace
39
+ from scripts import lincoln_condenser, lincoln_trace
40
40
  from scripts import lincoln_render
41
41
  from scripts.lincoln_documents import write_documents_index
42
42
  from scripts.lincoln_index import write_package_index
@@ -84,6 +84,29 @@ def now_iso() -> str:
84
84
  return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
85
85
 
86
86
 
87
+ def _record_stage_event(
88
+ state_file: Path | None,
89
+ category: str,
90
+ event_type: str,
91
+ payload: dict[str, Any] | None = None,
92
+ ) -> None:
93
+ """Write a lifecycle or gate event to the session trace.
94
+
95
+ Failures are logged but never block the stage action.
96
+ """
97
+ try:
98
+ merged_payload = {"event_type": event_type}
99
+ if payload:
100
+ merged_payload.update(payload)
101
+ lincoln_trace.append_event_entry(
102
+ state_path=state_file,
103
+ category=category,
104
+ payload=merged_payload,
105
+ )
106
+ except Exception as exc:
107
+ print(f"Warning: could not record {category}/{event_type} trace event: {exc}")
108
+
109
+
87
110
  def load_yaml(path: Path) -> Any:
88
111
  if not path.exists():
89
112
  raise FileNotFoundError(path)
@@ -483,6 +506,53 @@ def _check_previous_stage_completed(stage_id: str, prev_stage_id: str, state: di
483
506
  return False
484
507
 
485
508
 
509
+
510
+
511
+ def _check_agent_delegation(stage_id: str) -> bool:
512
+ """Validate parallel specialist agent configuration in stage YAML."""
513
+ stage = load_stage_yaml(stage_id)
514
+ agent = stage.get("agent", {})
515
+ specialists = agent.get("parallel_specialists", [])
516
+ if not specialists:
517
+ return True
518
+
519
+ all_valid = True
520
+ for specialist in specialists:
521
+ agent_file = f"{specialist.lstrip('lc-')}.md"
522
+ agent_path = PROJECT_ROOT / ".claude" / "agents" / agent_file
523
+ if not agent_path.exists():
524
+ print(
525
+ f"FAIL: specialist agent '{specialist}' not found at .claude/agents/{agent_file}",
526
+ file=sys.stderr,
527
+ )
528
+ all_valid = False
529
+ else:
530
+ print(f"PASS: specialist agent '{specialist}' found")
531
+
532
+ output_schema = agent.get("output_schema")
533
+ if output_schema:
534
+ schema_path = PROJECT_ROOT / output_schema
535
+ if not schema_path.exists():
536
+ print(f"FAIL: output_schema not found: {output_schema}", file=sys.stderr)
537
+ all_valid = False
538
+ else:
539
+ try:
540
+ json.loads(schema_path.read_text(encoding="utf-8"))
541
+ print(f"PASS: output_schema is valid JSON: {output_schema}")
542
+ except json.JSONDecodeError as exc:
543
+ print(f"FAIL: output_schema is invalid JSON: {exc}", file=sys.stderr)
544
+ all_valid = False
545
+
546
+ merge_strategy = agent.get("merge_strategy", "priority")
547
+ if merge_strategy not in {"priority", "vote", "consensus"}:
548
+ print(f"FAIL: unsupported merge_strategy '{merge_strategy}'", file=sys.stderr)
549
+ all_valid = False
550
+ else:
551
+ print(f"PASS: merge_strategy '{merge_strategy}' supported")
552
+
553
+ return all_valid
554
+
555
+
486
556
  def _run_gate_check(
487
557
  phase: str,
488
558
  check: dict[str, Any],
@@ -564,6 +634,10 @@ def action_validate(
564
634
  if not passed:
565
635
  all_passed = False
566
636
 
637
+ if phase == "entry":
638
+ if not _check_agent_delegation(stage_id):
639
+ all_passed = False
640
+
567
641
  if not all_passed:
568
642
  if _is_legacy_state(state):
569
643
  stage_state["status"] = "validation_failed"
@@ -638,6 +712,13 @@ def action_record_artifacts(
638
712
  print(f"Recorded {len(recorded)} artifacts for stage '{stage_id}'")
639
713
  for art in recorded:
640
714
  print(f" - {art}")
715
+
716
+ _record_stage_event(
717
+ state_file,
718
+ "stage_lifecycle",
719
+ "artifacts_recorded",
720
+ {"stage_id": stage_id, "artifact_count": len(recorded), "artifacts": recorded},
721
+ )
641
722
  return recorded
642
723
 
643
724
 
@@ -677,6 +758,13 @@ def action_approve_gate(
677
758
 
678
759
  save_state(state, state_file)
679
760
  print(f"PASS: gate approved for stage '{stage_id}' by '{approved_by}'")
761
+
762
+ _record_stage_event(
763
+ state_file,
764
+ "gate",
765
+ "gate_approved",
766
+ {"stage_id": stage_id, "approved_by": approved_by},
767
+ )
680
768
  return 0
681
769
 
682
770
 
@@ -799,6 +887,27 @@ def action_transition_next(stage_id: str, state: dict[str, Any], state_file: Pat
799
887
 
800
888
  save_state(state, state_file)
801
889
  print(f"Transitioned from '{stage_id}' to '{next_stage_id}'")
890
+
891
+ _record_stage_event(
892
+ state_file,
893
+ "stage_lifecycle",
894
+ "stage_completed",
895
+ {"stage_id": stage_id, "next_stage_id": next_stage_id},
896
+ )
897
+ if next_stage_id:
898
+ _record_stage_event(
899
+ state_file,
900
+ "stage_lifecycle",
901
+ "stage_started",
902
+ {"stage_id": next_stage_id, "previous_stage_id": stage_id},
903
+ )
904
+ else:
905
+ _record_stage_event(
906
+ state_file,
907
+ "session",
908
+ "workflow_completed",
909
+ {"final_stage_id": stage_id},
910
+ )
802
911
  return next_stage_id
803
912
 
804
913
 
@@ -900,6 +1009,20 @@ def action_handoff_report(stage_id: str, state: dict[str, Any], state_file: Path
900
1009
  else:
901
1010
  lines.append(f"- **Status:** {stage_state.get('status', state.get('current_run', {}).get('status', 'unknown'))}")
902
1011
  lines.append("")
1012
+
1013
+ # Condense large traces as a handoff sub-step (OpenHands-style context pressure management).
1014
+ try:
1015
+ trace_file = lincoln_trace.get_trace_file(state, state_file)
1016
+ condensation = lincoln_condenser.condense(trace_file)
1017
+ if condensation:
1018
+ lines.append("## Trace Condensation")
1019
+ lines.append(f"- **Events summarized:** {condensation['event_count']}")
1020
+ lines.append(f"- **Threshold:** {condensation.get('threshold', 200)}")
1021
+ lines.append(f"- **Top categories:** {', '.join(condensation.get('categories', {}).keys())}")
1022
+ lines.append("")
1023
+ except Exception:
1024
+ # Condensation is advisory; never break handoff report generation.
1025
+ pass
903
1026
  lines.append("## Waiting For")
904
1027
  lines.append(f"- **Waiting for:** {'human' if stage_def.get('human_gate') and not stage_state.get('gate_passed') else 'agent'}")
905
1028
  lines.append("")
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@sushanglewis/lincoln",
3
- "version": "1.6.3",
3
+ "version": "1.7.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@sushanglewis/lincoln",
9
- "version": "1.6.3",
9
+ "version": "1.7.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "ink": "^5.2.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sushanglewis/lincoln-recorder",
3
- "version": "1.6.3",
3
+ "version": "1.7.0",
4
4
  "description": "Cross-tool terminal UI for recording Lincoln interviews",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lincoln-install",
3
- "version": "1.6.3",
3
+ "version": "1.7.0",
4
4
  "description": "Terminal TUI installer for the Lincoln AI-Native R&D workflow system",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",
@@ -49,5 +49,10 @@
49
49
  "claude-code",
50
50
  "ai-workflow"
51
51
  ],
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "https://github.com/sushanglewis/Lincoln",
55
+ "directory": "tools/lincoln-installer"
56
+ },
52
57
  "license": "MIT"
53
58
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sushanglewis/lincoln",
3
- "version": "1.6.3",
3
+ "version": "1.7.0",
4
4
  "description": "Global Lincoln agent harness plugin CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -50,5 +50,10 @@
50
50
  "opencode",
51
51
  "plugin"
52
52
  ],
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "https://github.com/sushanglewis/Lincoln",
56
+ "directory": "packages/lincoln"
57
+ },
53
58
  "license": "MIT"
54
59
  }