@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.
- package/framework/.claude/agents/pm.md +2 -2
- package/framework/.claude/agents/security-reviewer.md +57 -0
- package/framework/.claude/harnesses/codex.yaml +31 -2
- package/framework/.claude/harnesses/command-map.yaml +4 -0
- package/framework/.claude/harnesses/opencode.yaml +33 -3
- package/framework/.claude/hooks/hooks.yaml +37 -0
- package/framework/.claude/hooks/on-session-start.sh +20 -5
- package/framework/.claude/hooks/on-stop.sh +22 -0
- package/framework/.claude/hooks/pre-tool-use.sh +22 -0
- package/framework/.claude/mcp/mcp.yaml +34 -0
- package/framework/.claude/policies/friction.yaml +18 -0
- package/framework/.claude/policies/security.yaml +46 -0
- package/framework/.claude/schemas/design-review-feedback.json +32 -0
- package/framework/.claude/schemas/stage-definition.schema.json +22 -0
- package/framework/.claude/skills/clarify-requirements/SKILL.md +1 -0
- package/framework/.claude/skills/clarify-requirements/prompts/main.md +44 -10
- package/framework/.claude/stages/clarify.yaml +3 -1
- package/framework/.claude/stages/phase-1-p0-design.yaml +44 -0
- package/framework/.claude/stages/phase-1-p0-implement.yaml +47 -0
- package/framework/.claude/stages/phase-2-p1-design.yaml +53 -0
- package/framework/.claude/stages/phase-2-p1-implement.yaml +45 -0
- package/framework/.claude/workflows/framework-self-improvement.yaml +100 -0
- package/framework/.claude/workflows/interview-to-knowledge.yaml +1 -0
- package/framework/.claude-plugin/marketplace.json +2 -2
- package/framework/.claude-plugin/plugin.json +1 -1
- package/framework/.version-bump.json +1 -1
- package/framework/README.en.md +24 -5
- package/framework/README.md +24 -5
- package/framework/RELEASE.md +22 -0
- package/framework/SKILL.md +15 -6
- package/framework/manifest.json +93 -37
- package/framework/scripts/check-harness-drift.sh +11 -1
- package/framework/scripts/lincoln-setup.py +17 -0
- package/framework/scripts/lincoln_condenser.py +110 -0
- package/framework/scripts/lincoln_friction.py +266 -0
- package/framework/scripts/lincoln_harness_adapter.py +185 -13
- package/framework/scripts/lincoln_mr_mine.py +146 -0
- package/framework/scripts/lincoln_recall.py +142 -0
- package/framework/scripts/lincoln_trace.py +119 -3
- package/framework/scripts/security_analyzer.py +234 -0
- package/framework/scripts/stage_loader.py +124 -1
- package/framework/tools/lincoln/package-lock.json +2 -2
- package/framework/tools/lincoln/package.json +1 -1
- package/framework/tools/lincoln-installer/package.json +6 -1
- 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.
|
|
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.
|
|
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": "lincoln-install",
|
|
3
|
-
"version": "1.
|
|
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.
|
|
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
|
}
|