claude-dev-env 1.65.0 → 1.66.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/agents/plan-packet-validator.md +34 -0
- package/audit-rubrics/category_rubrics/category-n-test-name-scenario-verifier.md +6 -0
- package/commands/plan.md +6 -52
- package/hooks/blocking/code_rules_dead_module_constant.py +111 -24
- package/hooks/blocking/code_rules_enforcer.py +2 -0
- package/hooks/blocking/code_rules_test_assertions.py +123 -1
- package/hooks/blocking/open_questions_in_plans_blocker.py +8 -1
- package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +88 -0
- package/hooks/blocking/test_code_rules_enforcer_split_test_assertions.py +90 -0
- package/hooks/blocking/test_open_questions_in_plans_blocker.py +43 -0
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -0
- package/hooks/hooks_constants/dead_module_constant_constants.py +1 -0
- package/hooks/hooks_constants/open_questions_in_plans_blocker_constants.py +4 -0
- package/hooks/hooks_constants/test_open_questions_in_plans_blocker_constants.py +13 -1
- package/package.json +1 -1
- package/skills/anthropic-plan/SKILL.md +46 -85
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/__init__.py +0 -0
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/validate_packet_constants.py +33 -0
- package/skills/anthropic-plan/scripts/test_validate_packet.py +405 -0
- package/skills/anthropic-plan/scripts/validate_packet.py +397 -0
- package/skills/anthropic-plan/templates/README.md +20 -0
- package/skills/anthropic-plan/templates/build-prompt.md +9 -0
- package/skills/anthropic-plan/templates/source-map.md +5 -0
- package/skills/anthropic-plan/test_skill_contract.py +53 -0
- package/skills/anthropic-plan/workflow/plan-packet.contract.test.mjs +79 -0
- package/skills/anthropic-plan/workflow/plan-packet.mjs +299 -0
- package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +8 -1
- package/skills/autoconverge/workflow/converge.mjs +9 -1
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
name: 'plan-packet',
|
|
3
|
+
description: 'Create a repo-local implementation planning packet under docs/plans/<slug>, validate it deterministically, verify it with a fresh validator agent, repair findings, and stop before implementation.',
|
|
4
|
+
whenToUse: 'Launched by the anthropic-plan skill for non-trivial implementation planning, scoping, design, or plan-first requests.',
|
|
5
|
+
phases: [
|
|
6
|
+
{ title: 'Discover', detail: 'Resolve repo root, read instructions, inspect matching source files, tests, configs, docs, skills, hooks, agents, and workflows.' },
|
|
7
|
+
{ title: 'Write packet', detail: 'Create the required docs/plans/<slug>/ tree with a thin README hub and detailed second-level docs.' },
|
|
8
|
+
{ title: 'Validate', detail: 'Run scripts/validate_packet.py, spawn plan-packet-validator in fresh context, and repair findings up to the cap.' },
|
|
9
|
+
{ title: 'Approval', detail: 'Return the packet path and validation verdict, then stop before implementation work.' },
|
|
10
|
+
],
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function validationSchema() {
|
|
14
|
+
return {
|
|
15
|
+
type: 'object',
|
|
16
|
+
additionalProperties: false,
|
|
17
|
+
properties: {
|
|
18
|
+
allPassed: { type: 'boolean' },
|
|
19
|
+
findings: {
|
|
20
|
+
type: 'array',
|
|
21
|
+
items: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
additionalProperties: false,
|
|
24
|
+
properties: {
|
|
25
|
+
file: { type: 'string' },
|
|
26
|
+
check: { type: 'string' },
|
|
27
|
+
detail: { type: 'string' },
|
|
28
|
+
},
|
|
29
|
+
required: ['file', 'check', 'detail'],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
summary: { type: 'string' },
|
|
33
|
+
},
|
|
34
|
+
required: ['allPassed', 'findings', 'summary'],
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function packetWriteSchema() {
|
|
39
|
+
return {
|
|
40
|
+
type: 'object',
|
|
41
|
+
additionalProperties: false,
|
|
42
|
+
properties: {
|
|
43
|
+
packetPath: { type: 'string' },
|
|
44
|
+
slug: { type: 'string' },
|
|
45
|
+
filesWritten: { type: 'array', items: { type: 'string' } },
|
|
46
|
+
summary: { type: 'string' },
|
|
47
|
+
},
|
|
48
|
+
required: ['packetPath', 'slug', 'filesWritten', 'summary'],
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function deterministicSchema() {
|
|
53
|
+
return {
|
|
54
|
+
type: 'object',
|
|
55
|
+
additionalProperties: false,
|
|
56
|
+
properties: {
|
|
57
|
+
passed: { type: 'boolean' },
|
|
58
|
+
stdout: { type: 'string' },
|
|
59
|
+
stderr: { type: 'string' },
|
|
60
|
+
findings: { type: 'array', items: { type: 'string' } },
|
|
61
|
+
},
|
|
62
|
+
required: ['passed', 'stdout', 'stderr', 'findings'],
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function repairSchema() {
|
|
67
|
+
return {
|
|
68
|
+
type: 'object',
|
|
69
|
+
additionalProperties: false,
|
|
70
|
+
properties: {
|
|
71
|
+
repaired: { type: 'boolean' },
|
|
72
|
+
summary: { type: 'string' },
|
|
73
|
+
},
|
|
74
|
+
required: ['repaired', 'summary'],
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function normalizeRunInput(rawInput) {
|
|
79
|
+
if (rawInput && typeof rawInput === 'object') return rawInput
|
|
80
|
+
if (typeof rawInput !== 'string' || rawInput.trim() === '') return {}
|
|
81
|
+
try {
|
|
82
|
+
const parsedInput = JSON.parse(rawInput)
|
|
83
|
+
return parsedInput && typeof parsedInput === 'object' ? parsedInput : {}
|
|
84
|
+
} catch {
|
|
85
|
+
return { task: rawInput }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function slugFromTask(taskText) {
|
|
90
|
+
const words = String(taskText || 'implementation-plan')
|
|
91
|
+
.toLowerCase()
|
|
92
|
+
.replace(/[^a-z0-9\s-]/g, ' ')
|
|
93
|
+
.split(/\s+/)
|
|
94
|
+
.filter(Boolean)
|
|
95
|
+
.filter((eachWord) => !['the', 'and', 'for', 'with', 'this', 'that'].includes(eachWord))
|
|
96
|
+
.slice(0, 4)
|
|
97
|
+
return words.length ? words.join('-') : 'implementation-plan'
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function buildPacketPath(runInput) {
|
|
101
|
+
const cwd = runInput.cwd || runInput.repoRoot || '.'
|
|
102
|
+
const slug = runInput.slug || slugFromTask(runInput.task || runInput.prompt || runInput.arguments)
|
|
103
|
+
return `${cwd.replace(/[\\/]$/, '')}/docs/plans/${slug}`
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function requiredPacketTree() {
|
|
107
|
+
return [
|
|
108
|
+
'README.md',
|
|
109
|
+
'packet.json',
|
|
110
|
+
'context/user-request.md',
|
|
111
|
+
'context/source-map.md',
|
|
112
|
+
'context/current-state.md',
|
|
113
|
+
'context/existing-patterns.md',
|
|
114
|
+
'context/constraints.md',
|
|
115
|
+
'context/glossary.md',
|
|
116
|
+
'spec/scope.md',
|
|
117
|
+
'spec/behavior.md',
|
|
118
|
+
'spec/interfaces.md',
|
|
119
|
+
'spec/data-flow.md',
|
|
120
|
+
'spec/failure-modes.md',
|
|
121
|
+
'spec/acceptance.md',
|
|
122
|
+
'implementation/strategy.md',
|
|
123
|
+
'implementation/steps.md',
|
|
124
|
+
'implementation/tdd-plan.md',
|
|
125
|
+
'implementation/file-plan.md',
|
|
126
|
+
'implementation/refactor-checkpoints.md',
|
|
127
|
+
'validation/validator-report.md',
|
|
128
|
+
'validation/deterministic-checks.md',
|
|
129
|
+
'validation/unresolved-risks.md',
|
|
130
|
+
'handoff/build-prompt.md',
|
|
131
|
+
'handoff/review-prompt.md',
|
|
132
|
+
'handoff/verification-commands.md',
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function packetContractText() {
|
|
137
|
+
return (
|
|
138
|
+
`Create this exact packet tree under docs/plans/<slug>/:\n${requiredPacketTree().map((eachPath) => `- ${eachPath}`).join('\n')}\n\n` +
|
|
139
|
+
`README.md stays a thin hub. First-level folders group purpose. Second-level files carry real detail. Do not add deeper nesting unless more than twelve source files or more than three subsystems are found; then add context/subsystems/<name>.md.\n\n` +
|
|
140
|
+
`Every material claim must be source-backed in context/source-map.md, user-confirmed in context/user-request.md, or listed as an assumption in packet.json. Do not write an Open Questions section. Resolve discoverable unknowns by reading/searching. Ask the user only for product choices that cannot be derived.\n\n` +
|
|
141
|
+
`The packet must stop before implementation. The build prompt must stand alone for a blind build agent and say to use only this packet.`
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function discoveryPrompt(runInput, packetPath) {
|
|
146
|
+
return (
|
|
147
|
+
`Plan packet discovery for: ${runInput.task || runInput.prompt || runInput.arguments || 'the current user request'}\n\n` +
|
|
148
|
+
`Target packet path: ${packetPath}\n\n` +
|
|
149
|
+
`Collect context before writing:\n` +
|
|
150
|
+
`1. Resolve the repo root and current working directory.\n` +
|
|
151
|
+
`2. Read project instructions in priority order: AGENTS.md or CLAUDE.md, nearest .claude rules, relevant skill docs, package manifests, tool manifests.\n` +
|
|
152
|
+
`3. Search for user terms and likely entrypoints: commands, hooks, agents, skills, configs, schemas, tests, docs, scripts, workflows.\n` +
|
|
153
|
+
`4. Build a source inventory with production files, tests, configs/constants, docs, and workflow scripts.\n` +
|
|
154
|
+
`5. Extract exact facts for source-map.md: path, relevant symbol or section, observed behavior, and plan implication.\n\n` +
|
|
155
|
+
`Return a concise discovery summary. Do not edit files.`
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function writePacketPrompt(runInput, packetPath, discoverySummary) {
|
|
160
|
+
return (
|
|
161
|
+
`Write the plan packet for: ${runInput.task || runInput.prompt || runInput.arguments || 'the current user request'}\n\n` +
|
|
162
|
+
`Packet path: ${packetPath}\n\n` +
|
|
163
|
+
`Discovery summary:\n${discoverySummary}\n\n` +
|
|
164
|
+
`${packetContractText()}\n\n` +
|
|
165
|
+
`Use the templates in the anthropic-plan skill if helpful. Write docs only. Do not edit source code. Do not run implementation commands. ` +
|
|
166
|
+
`After writing, ensure packet.json includes schemaVersion 1, slug, repoRoot, packetPath, sourceFiles, assumptions, and validator fields.`
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function deterministicValidationPrompt(packetPath) {
|
|
171
|
+
return (
|
|
172
|
+
`Run the deterministic packet validator exactly:\n` +
|
|
173
|
+
`python "$HOME/.claude/skills/anthropic-plan/scripts/validate_packet.py" "${packetPath}"\n\n` +
|
|
174
|
+
`Return passed=true only when the command exits 0. Put stdout, stderr, and each stderr line as findings. Do not edit files.`
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function semanticValidationPrompt(packetPath) {
|
|
179
|
+
return (
|
|
180
|
+
`Validate the plan packet at ${packetPath}. Re-read the packet and the source files it cites. ` +
|
|
181
|
+
`Every material claim must be source-backed, user-confirmed, or an explicit assumption. ` +
|
|
182
|
+
`Check that referenced paths exist or are clearly proposed as new, source facts match actual files, implementation steps are enough for a blind build agent, the TDD sequence is real, scope matches the user request, no commands/APIs/schemas/conventions are invented, and acceptance criteria prove the behavior end to end. ` +
|
|
183
|
+
`Return allPassed=true only when the packet is accurate and complete. Do not edit files.`
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function repairPrompt(packetPath, deterministicValidation, semanticValidation) {
|
|
188
|
+
return (
|
|
189
|
+
`Repair only the plan packet at ${packetPath}. Do not edit source code.\n\n` +
|
|
190
|
+
`Deterministic validation findings:\n${JSON.stringify(deterministicValidation.findings || [])}\n\n` +
|
|
191
|
+
`Semantic validation findings:\n${JSON.stringify(semanticValidation.findings || [])}\n\n` +
|
|
192
|
+
`Make the packet pass by correcting documentation, adding missing source grounding, removing placeholders, strengthening TDD steps, and updating validation/validator-report.md.`
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function discoverContext(runInput, packetPath) {
|
|
197
|
+
return agent(discoveryPrompt(runInput, packetPath), {
|
|
198
|
+
label: `${meta.name}-discover`,
|
|
199
|
+
phase: 'Discover',
|
|
200
|
+
agentType: 'general-purpose',
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function writePacket(runInput, packetPath, discoverySummary) {
|
|
205
|
+
return agent(writePacketPrompt(runInput, packetPath, discoverySummary), {
|
|
206
|
+
label: `${meta.name}-write`,
|
|
207
|
+
phase: 'Write packet',
|
|
208
|
+
schema: packetWriteSchema(),
|
|
209
|
+
agentType: 'docs-agent',
|
|
210
|
+
})
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function runDeterministicValidation(packetPath) {
|
|
214
|
+
return agent(deterministicValidationPrompt(packetPath), {
|
|
215
|
+
label: `${meta.name}-deterministic-validation`,
|
|
216
|
+
phase: 'Validate',
|
|
217
|
+
schema: deterministicSchema(),
|
|
218
|
+
agentType: 'general-purpose',
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async function runSemanticValidator(packetPath) {
|
|
223
|
+
const prompt =
|
|
224
|
+
`${semanticValidationPrompt(packetPath)}\n\n` +
|
|
225
|
+
`Confirm the packet is source-backed and complete enough for a blind build agent.`
|
|
226
|
+
return agent(prompt, {
|
|
227
|
+
label: `${meta.name}-semantic-validator`,
|
|
228
|
+
phase: 'Validate',
|
|
229
|
+
schema: validationSchema(),
|
|
230
|
+
agentType: 'plan-packet-validator',
|
|
231
|
+
})
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function repairPacket(packetPath, deterministicValidation, semanticValidation) {
|
|
235
|
+
return agent(repairPrompt(packetPath, deterministicValidation, semanticValidation), {
|
|
236
|
+
label: `${meta.name}-repair`,
|
|
237
|
+
phase: 'Validate',
|
|
238
|
+
schema: repairSchema(),
|
|
239
|
+
agentType: 'docs-agent',
|
|
240
|
+
})
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function runPlanPacketWorkflow(rawInput) {
|
|
244
|
+
const runInput = normalizeRunInput(rawInput)
|
|
245
|
+
const policy = { maxRepairLoops: 3 }
|
|
246
|
+
const packetPath = buildPacketPath(runInput)
|
|
247
|
+
let repairLoops = 0
|
|
248
|
+
let packetWrite = null
|
|
249
|
+
let deterministicValidation = null
|
|
250
|
+
let semanticValidation = null
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
const discoverySummary = await discoverContext(runInput, packetPath)
|
|
254
|
+
packetWrite = await writePacket(runInput, packetPath, discoverySummary)
|
|
255
|
+
deterministicValidation = await runDeterministicValidation(packetPath)
|
|
256
|
+
semanticValidation = await runSemanticValidator(packetPath)
|
|
257
|
+
const hasCleanValidation = () =>
|
|
258
|
+
deterministicValidation?.passed === true && semanticValidation && semanticValidation.allPassed === true
|
|
259
|
+
|
|
260
|
+
while (!hasCleanValidation() && repairLoops < policy.maxRepairLoops) {
|
|
261
|
+
repairLoops += 1
|
|
262
|
+
await repairPacket(packetPath, deterministicValidation, semanticValidation)
|
|
263
|
+
deterministicValidation = await runDeterministicValidation(packetPath)
|
|
264
|
+
semanticValidation = await runSemanticValidator(packetPath)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const passed = hasCleanValidation()
|
|
268
|
+
return {
|
|
269
|
+
packetPath: packetWrite?.packetPath || packetPath,
|
|
270
|
+
slug: packetWrite?.slug || slugFromTask(runInput.task || runInput.prompt || runInput.arguments),
|
|
271
|
+
validationPassed: passed,
|
|
272
|
+
repairLoops,
|
|
273
|
+
deterministicFindings: deterministicValidation?.findings || [],
|
|
274
|
+
semanticFindings: semanticValidation?.findings || [],
|
|
275
|
+
implementationStarted: false,
|
|
276
|
+
approvalRequired: true,
|
|
277
|
+
}
|
|
278
|
+
} catch (workflowError) {
|
|
279
|
+
return {
|
|
280
|
+
packetPath,
|
|
281
|
+
slug: packetWrite?.slug || slugFromTask(runInput.task || runInput.prompt || runInput.arguments),
|
|
282
|
+
validationPassed: false,
|
|
283
|
+
repairLoops,
|
|
284
|
+
deterministicFindings: deterministicValidation?.findings || [],
|
|
285
|
+
semanticFindings: [
|
|
286
|
+
...(semanticValidation?.findings || []),
|
|
287
|
+
{
|
|
288
|
+
file: 'workflow/plan-packet.mjs',
|
|
289
|
+
check: 'workflow phase error',
|
|
290
|
+
detail: String(workflowError?.message || workflowError),
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
implementationStarted: false,
|
|
294
|
+
approvalRequired: true,
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return await runPlanPacketWorkflow(input)
|
|
@@ -96,7 +96,7 @@ test('FIX_SCHEMA requires blockedNeedingEdit and blockerDetail', () => {
|
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
test('FIX_RECOVERY_MAX_ATTEMPTS is declared and bounds the recovery loop at 2', () => {
|
|
99
|
-
assert.match(constantLine('FIX_RECOVERY_MAX_ATTEMPTS'), /=\s*2
|
|
99
|
+
assert.match(constantLine('FIX_RECOVERY_MAX_ATTEMPTS'), /=\s*2\s*$/);
|
|
100
100
|
});
|
|
101
101
|
|
|
102
102
|
for (const commitFunctionName of ['commitVerifiedFixes', 'commitRepairFixes']) {
|
|
@@ -154,6 +154,13 @@ test('commitWithRecovery bounds the loop, re-verifies, and retries the commit on
|
|
|
154
154
|
editGuardIndex < verifyGateIndex,
|
|
155
155
|
'expected the no-edit break to precede the re-verify gate',
|
|
156
156
|
);
|
|
157
|
+
const recoverEditIndex = recoveryBody.search(/runRecoverEdit\(/);
|
|
158
|
+
const reverifyIndex = recoveryBody.search(/runVerify\(/);
|
|
159
|
+
const retryCommitIndex = recoveryBody.lastIndexOf('runCommit(');
|
|
160
|
+
assert.ok(
|
|
161
|
+
recoverEditIndex < reverifyIndex && reverifyIndex < retryCommitIndex,
|
|
162
|
+
'expected order recover-edit -> re-verify -> retry commit, so a verify/commit swap fails',
|
|
163
|
+
);
|
|
157
164
|
});
|
|
158
165
|
|
|
159
166
|
test('applyFixes routes its commit through commitWithRecovery wired to the fix-path steps', () => {
|
|
@@ -808,7 +808,7 @@ function recoverCommitBlockEdit(head, blockerDetail, sourceLabel, attempt) {
|
|
|
808
808
|
)
|
|
809
809
|
}
|
|
810
810
|
|
|
811
|
-
const FIX_RECOVERY_MAX_ATTEMPTS =
|
|
811
|
+
const FIX_RECOVERY_MAX_ATTEMPTS = 2
|
|
812
812
|
|
|
813
813
|
/**
|
|
814
814
|
* Run a commit step and, when it is blocked by a commit-time hook or gate that
|
|
@@ -858,6 +858,8 @@ async function applyFixes(head, findings, sourceLabel) {
|
|
|
858
858
|
pushed: false,
|
|
859
859
|
resolvedWithoutCommit: true,
|
|
860
860
|
summary: editResult?.summary || 'fixes resolved without a code change',
|
|
861
|
+
blockedNeedingEdit: false,
|
|
862
|
+
blockerDetail: '',
|
|
861
863
|
}
|
|
862
864
|
}
|
|
863
865
|
const verifyTranscript = await verifyFixesInWorkingTree(head, findings, sourceLabel)
|
|
@@ -867,6 +869,8 @@ async function applyFixes(head, findings, sourceLabel) {
|
|
|
867
869
|
pushed: false,
|
|
868
870
|
resolvedWithoutCommit: false,
|
|
869
871
|
summary: `verify step did not pass the working-tree fixes for ${findings.length} finding(s) — not committing`,
|
|
872
|
+
blockedNeedingEdit: false,
|
|
873
|
+
blockerDetail: '',
|
|
870
874
|
}
|
|
871
875
|
}
|
|
872
876
|
return commitWithRecovery({
|
|
@@ -1091,6 +1095,8 @@ async function repairConvergence(head, failures) {
|
|
|
1091
1095
|
pushed: false,
|
|
1092
1096
|
resolvedWithoutCommit: true,
|
|
1093
1097
|
summary: editResult?.summary || 'convergence gates resolved without a code change or rebase',
|
|
1098
|
+
blockedNeedingEdit: false,
|
|
1099
|
+
blockerDetail: '',
|
|
1094
1100
|
}
|
|
1095
1101
|
}
|
|
1096
1102
|
const verifyTranscript = await verifyRepairChanges(head, failures)
|
|
@@ -1100,6 +1106,8 @@ async function repairConvergence(head, failures) {
|
|
|
1100
1106
|
pushed: false,
|
|
1101
1107
|
resolvedWithoutCommit: false,
|
|
1102
1108
|
summary: `repair verify step did not pass the working-tree repair on HEAD ${head} — not pushing`,
|
|
1109
|
+
blockedNeedingEdit: false,
|
|
1110
|
+
blockerDetail: '',
|
|
1103
1111
|
}
|
|
1104
1112
|
}
|
|
1105
1113
|
const wasRebased = editResult?.rebased === true
|