@lmctl-ai/lmctl 0.1.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/LICENSE +36 -0
- package/README.md +36 -0
- package/bin/lmctl +4 -0
- package/dist/cli/index.js +2180 -0
- package/dist/cli/schema.sql +660 -0
- package/dist/cli/side_effect_classifier.json +19 -0
- package/dist/config/ai_test_templates/example-test.md.template +50 -0
- package/dist/config/ai_test_templates/index.md.template +27 -0
- package/dist/config/durable_memory_templates/index.md.template +29 -0
- package/dist/config/durable_memory_templates/skills_general.md.template +42 -0
- package/dist/config/durable_memory_templates/skills_lmdebug.md.template +31 -0
- package/dist/config/durable_memory_templates/skills_lmprobe.md.template +31 -0
- package/package.json +42 -0
- package/workflows/bugfix-extended-v2.compound.json +1018 -0
- package/workflows/bugfix-v2.compound.json +856 -0
- package/workflows/claim-check-spike-v2.compound.json +136 -0
- package/workflows/document-creation.compound.json +200 -0
- package/workflows/durable-memory-consolidation-v2.compound.json +185 -0
- package/workflows/example-v2.compound.json +200 -0
- package/workflows/image-qa.compound.json +128 -0
- package/workflows/index.jsonl +15 -0
- package/workflows/info-qa.compound.json +120 -0
- package/workflows/newspaper.compound.json +129 -0
- package/workflows/pr-fix.compound.json +183 -0
- package/workflows/pr-followup-v2.compound.json +969 -0
- package/workflows/provider-probe.compound.json +107 -0
- package/workflows/qa-suite.compound.json +186 -0
- package/workflows/spec-driven-task.compound.json +460 -0
- package/workflows/triage-v2.compound.json +721 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": "lmctl/v3",
|
|
3
|
+
"definition_schema_version": 3,
|
|
4
|
+
"name": "pr-fix",
|
|
5
|
+
"version": 1,
|
|
6
|
+
"description": "Claims one project issue, reads the failing test chapter, fixes the project with coder/reviewer loop, commits, and closes the issue.",
|
|
7
|
+
"estimated_duration_ms": 300000,
|
|
8
|
+
"requires": {
|
|
9
|
+
"tools": ["git", "node"]
|
|
10
|
+
},
|
|
11
|
+
"errors": {
|
|
12
|
+
"on_unhandled_failure": {
|
|
13
|
+
"attention_kind": "workflow_failed",
|
|
14
|
+
"severity": "error",
|
|
15
|
+
"capture_evidence": true
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"inputs": [
|
|
19
|
+
{
|
|
20
|
+
"name": "project_name",
|
|
21
|
+
"type": "string",
|
|
22
|
+
"required": true,
|
|
23
|
+
"description": "Project issue queue to drain. The project's team should include Coder and Reviewer aliases."
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"outputs": [
|
|
27
|
+
{
|
|
28
|
+
"name": "issue_id",
|
|
29
|
+
"type": "number",
|
|
30
|
+
"source_step_id": "s-claim-issue-b1c2",
|
|
31
|
+
"source_field": "id",
|
|
32
|
+
"description": "Claimed project_issue id."
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "commit_hash",
|
|
36
|
+
"type": "string",
|
|
37
|
+
"source_step_id": "s-commit-result-f5a6",
|
|
38
|
+
"source_field": "hash",
|
|
39
|
+
"description": "Commit hash recorded before closing the issue."
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"steps": [
|
|
43
|
+
{
|
|
44
|
+
"id": "s-claim-issue-b1c2",
|
|
45
|
+
"name": "claim_issue",
|
|
46
|
+
"type": "lmctl/shell-step",
|
|
47
|
+
"typeVersion": 1,
|
|
48
|
+
"parameters": {
|
|
49
|
+
"command": "node -e 'const fs=require(\"fs\"), cp=require(\"child_process\"); const project=process.argv[1], runId=process.argv[2]; const claim=cp.spawnSync(\"lmctl\",[\"api\",\"--direct\",\"issues\",\"claim-next\",project,\"--assigned-run-id\",runId,\"--json\"],{encoding:\"utf8\",env:process.env}); const out=(claim.stdout||\"\").trim(); if(claim.status===0 && out.length>0){ fs.writeFileSync(`/tmp/lmctl-next-run-${runId}-claimed-issue.json`,out); console.log(out); process.exit(0); } if(/queue_empty/.test(out) || /404/.test(claim.stderr||\"\") || /404/.test(out)){ console.log(JSON.stringify({status:\"nothing-to-do\"})); process.exit(2); } process.stderr.write(claim.stderr||out||\"issue claim-next failed\"); process.exit(claim.status||1);' \"{{project.name}}\" \"{{run_id}}\"",
|
|
50
|
+
"capture_output_to": "claimed_issue_json",
|
|
51
|
+
"outcomes_from_exit": {
|
|
52
|
+
"0": "@terminal:exit_0",
|
|
53
|
+
"2": "@terminal:exit_2",
|
|
54
|
+
"default": "@terminal:exit_default"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": "s-read-chapter-d3e4",
|
|
60
|
+
"name": "read_chapter",
|
|
61
|
+
"type": "lmctl/shell-step",
|
|
62
|
+
"typeVersion": 1,
|
|
63
|
+
"parameters": {
|
|
64
|
+
"command": "node -e 'const fs=require(\"fs\"), path=require(\"path\"); const root=path.resolve(process.argv[1]), runId=process.argv[2]; const issue=JSON.parse(fs.readFileSync(`/tmp/lmctl-next-run-${runId}-claimed-issue.json`,\"utf8\")); const rel=issue.ai_test_path; if(typeof rel!==\"string\"||rel.length===0){ process.stderr.write(\"claimed issue has no ai_test_path\"); process.exit(1); } const full=path.resolve(root,rel); if(full!==root && !full.startsWith(root+path.sep)){ process.stderr.write(\"ai_test_path escapes project root\"); process.exit(1); } const body=fs.readFileSync(full,\"utf8\"); fs.writeFileSync(`/tmp/lmctl-next-run-${runId}-ai-test.md`,body); console.log(body);' \"{{project.local_path}}\" \"{{run_id}}\"",
|
|
65
|
+
"capture_output_to": "claimed_ai_test_chapter",
|
|
66
|
+
"outcomes_from_exit": {
|
|
67
|
+
"0": "@terminal:exit_0",
|
|
68
|
+
"default": "@terminal:exit_default"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"id": "s-fix-loop-e4f5",
|
|
74
|
+
"name": "fix_loop",
|
|
75
|
+
"type": "lmctl/review",
|
|
76
|
+
"typeVersion": 1,
|
|
77
|
+
"parameters": {
|
|
78
|
+
"max_loops": 3,
|
|
79
|
+
"writes_to_project_path": true,
|
|
80
|
+
"loop_feedback_artifact": "pr_fix_review_feedback"
|
|
81
|
+
},
|
|
82
|
+
"members": {
|
|
83
|
+
"coder": {
|
|
84
|
+
"team": "default",
|
|
85
|
+
"alias": "Coder",
|
|
86
|
+
"prompt_template": "You are fixing one project_issue claimed by pr-fix.\n\nRead these local artifacts first:\n- Claimed issue JSON: /tmp/lmctl-next-run-{{run_id}}-claimed-issue.json\n- AI test chapter: /tmp/lmctl-next-run-{{run_id}}-ai-test.md\n\nApply a focused code change in {{project.local_path}} that makes the AI test pass. Keep the diff narrow and update tests where appropriate. Do not close the issue yourself; the workflow closes it after review and commit.\n\nEnd with STANCE: ready when the patch is ready for review, or STANCE: failed if blocked."
|
|
87
|
+
},
|
|
88
|
+
"reviewers": [
|
|
89
|
+
{
|
|
90
|
+
"team": "default",
|
|
91
|
+
"alias": "Reviewer",
|
|
92
|
+
"prompt_template": "Review the Coder patch against the claimed project_issue and AI test chapter. Approve only if the issue is fixed narrowly and verification evidence is credible.\n\nRespond with STANCE: approve or STANCE: request_changes."
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"id": "s-commit-result-f5a6",
|
|
99
|
+
"name": "commit_result",
|
|
100
|
+
"type": "lmctl/shell-step",
|
|
101
|
+
"typeVersion": 1,
|
|
102
|
+
"parameters": {
|
|
103
|
+
"command": "node -e 'const fs=require(\"fs\"), cp=require(\"child_process\"); const runId=process.argv[1]; const issue=JSON.parse(fs.readFileSync(`/tmp/lmctl-next-run-${runId}-claimed-issue.json`,\"utf8\")); const title=String(issue.title||\"AI test issue\").replace(/[\\r\\n]+/g,\" \").slice(0,80); const add=cp.spawnSync(\"git\",[\"add\",\"-A\"],{encoding:\"utf8\",env:process.env}); if(add.status!==0){ process.stderr.write(add.stderr||add.stdout||\"git add failed\"); process.exit(add.status||1); } const diff=cp.spawnSync(\"git\",[\"diff\",\"--cached\",\"--quiet\"],{encoding:\"utf8\",env:process.env}); if(diff.status!==0){ const commit=cp.spawnSync(\"git\",[\"commit\",\"-m\",`Fix: ${title} (#${issue.id})`],{encoding:\"utf8\",env:process.env}); if(commit.status!==0){ process.stderr.write(commit.stderr||commit.stdout||\"git commit failed\"); process.exit(commit.status||1); }} const rev=cp.spawnSync(\"git\",[\"rev-parse\",\"HEAD\"],{encoding:\"utf8\",env:process.env}); if(rev.status!==0){ process.stderr.write(rev.stderr||rev.stdout||\"git rev-parse failed\"); process.exit(rev.status||1); } const hash=rev.stdout.trim(); fs.writeFileSync(`/tmp/lmctl-next-run-${runId}-commit.txt`,hash); console.log(JSON.stringify({hash}));' \"{{run_id}}\"",
|
|
104
|
+
"capture_output_to": "pr_fix_commit_json",
|
|
105
|
+
"writes_to_project_path": true,
|
|
106
|
+
"outcomes_from_exit": {
|
|
107
|
+
"0": "@terminal:exit_0",
|
|
108
|
+
"default": "@terminal:exit_default"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"id": "s-close-issue-a6b7",
|
|
114
|
+
"name": "close_issue",
|
|
115
|
+
"type": "lmctl/shell-step",
|
|
116
|
+
"typeVersion": 1,
|
|
117
|
+
"parameters": {
|
|
118
|
+
"command": "node -e 'const fs=require(\"fs\"), cp=require(\"child_process\"); const runId=process.argv[1]; const issue=JSON.parse(fs.readFileSync(`/tmp/lmctl-next-run-${runId}-claimed-issue.json`,\"utf8\")); const hash=fs.readFileSync(`/tmp/lmctl-next-run-${runId}-commit.txt`,\"utf8\").trim(); const result=cp.spawnSync(\"lmctl\",[\"api\",\"--direct\",\"issues\",\"close\",String(issue.id),\"--closed-run-id\",runId,\"--commit-hash\",hash,\"--json\"],{encoding:\"utf8\",env:process.env}); if(result.status!==0){ process.stderr.write(result.stderr||result.stdout||\"issue close failed\"); process.exit(result.status||1); } console.log(result.stdout.trim());' \"{{run_id}}\"",
|
|
119
|
+
"capture_output_to": "closed_issue_json",
|
|
120
|
+
"outcomes_from_exit": {
|
|
121
|
+
"0": "@terminal:exit_0",
|
|
122
|
+
"default": "@terminal:exit_default"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"id": "s-terminal-fixed-1a2b",
|
|
128
|
+
"name": "terminal:fixed",
|
|
129
|
+
"type": "lmctl/terminal",
|
|
130
|
+
"typeVersion": 1,
|
|
131
|
+
"parameters": {
|
|
132
|
+
"name": "fixed",
|
|
133
|
+
"kind": "success"
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"id": "s-terminal-idle-2b3c",
|
|
138
|
+
"name": "terminal:idle",
|
|
139
|
+
"type": "lmctl/terminal",
|
|
140
|
+
"typeVersion": 1,
|
|
141
|
+
"parameters": {
|
|
142
|
+
"name": "idle",
|
|
143
|
+
"kind": "neutral"
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"id": "s-terminal-aborted-3c4d",
|
|
148
|
+
"name": "terminal:aborted",
|
|
149
|
+
"type": "lmctl/terminal",
|
|
150
|
+
"typeVersion": 1,
|
|
151
|
+
"parameters": {
|
|
152
|
+
"name": "aborted",
|
|
153
|
+
"kind": "failure"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
"connections": {
|
|
158
|
+
"s-claim-issue-b1c2": {
|
|
159
|
+
"exit_0": [[{ "step_id": "s-read-chapter-d3e4", "type": "main", "index": 0 }]],
|
|
160
|
+
"exit_2": [[{ "step_id": "s-terminal-idle-2b3c", "type": "main", "index": 0 }]],
|
|
161
|
+
"exit_default": [[{ "step_id": "s-terminal-aborted-3c4d", "type": "main", "index": 0 }]]
|
|
162
|
+
},
|
|
163
|
+
"s-read-chapter-d3e4": {
|
|
164
|
+
"exit_0": [[{ "step_id": "s-fix-loop-e4f5", "type": "main", "index": 0 }]],
|
|
165
|
+
"exit_default": [[{ "step_id": "s-terminal-aborted-3c4d", "type": "main", "index": 0 }]]
|
|
166
|
+
},
|
|
167
|
+
"s-fix-loop-e4f5": {
|
|
168
|
+
"approve": [[{ "step_id": "s-commit-result-f5a6", "type": "main", "index": 0 }]],
|
|
169
|
+
"request_changes": [[{ "step_id": "s-fix-loop-e4f5", "type": "main", "index": 0 }]],
|
|
170
|
+
"max_loops_exceeded": [[{ "step_id": "s-terminal-aborted-3c4d", "type": "main", "index": 0 }]],
|
|
171
|
+
"failed": [[{ "step_id": "s-terminal-aborted-3c4d", "type": "main", "index": 0 }]]
|
|
172
|
+
},
|
|
173
|
+
"s-commit-result-f5a6": {
|
|
174
|
+
"exit_0": [[{ "step_id": "s-close-issue-a6b7", "type": "main", "index": 0 }]],
|
|
175
|
+
"exit_default": [[{ "step_id": "s-terminal-aborted-3c4d", "type": "main", "index": 0 }]]
|
|
176
|
+
},
|
|
177
|
+
"s-close-issue-a6b7": {
|
|
178
|
+
"exit_0": [[{ "step_id": "s-terminal-fixed-1a2b", "type": "main", "index": 0 }]],
|
|
179
|
+
"exit_default": [[{ "step_id": "s-terminal-aborted-3c4d", "type": "main", "index": 0 }]]
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
"entry_step_id": "s-claim-issue-b1c2"
|
|
183
|
+
}
|