@infinitedusky/indusk-mcp 1.44.0 → 1.44.2
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/admin/.next/BUILD_ID +1 -1
- package/admin/.next/build-manifest.json +3 -3
- package/admin/.next/fallback-build-manifest.json +3 -3
- package/admin/.next/prerender-manifest.json +3 -3
- package/admin/.next/server/app/_global-error.html +1 -1
- package/admin/.next/server/app/_global-error.rsc +1 -1
- package/admin/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/admin/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/admin/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/admin/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/admin/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/admin/.next/server/middleware-build-manifest.js +3 -3
- package/admin/.next/server/pages/500.html +1 -1
- package/admin/.next/server/server-reference-manifest.js +1 -1
- package/admin/.next/server/server-reference-manifest.json +1 -1
- package/admin/.next/trace +1 -1
- package/admin/.next/trace-build +1 -1
- package/dist/bin/commands/agent.js +3 -3
- package/dist/bin/commands/extensions.d.ts +11 -0
- package/dist/bin/commands/extensions.js +10 -0
- package/dist/bin/commands/run.js +21 -0
- package/dist/bin/commands/update.js +18 -14
- package/dist/bin/commands/workbench.d.ts +0 -8
- package/dist/bin/commands/workbench.js +28 -10
- package/dist/bin/commands/worktree.d.ts +10 -0
- package/dist/bin/commands/worktree.js +12 -5
- package/dist/lib/cleanup/oversized.js +16 -4
- package/dist/lib/eval/evaluator-runner.d.ts +3 -2
- package/dist/lib/stray-state-audit.js +5 -2
- package/dist/lib/trajectory/state-ops.d.ts +0 -6
- package/dist/lib/trajectory/state-ops.js +0 -15
- package/dist/lib/verify/roots.js +5 -2
- package/dist/lib/worktree/layout.js +9 -3
- package/dist/lib/worktree/repos.d.ts +10 -1
- package/dist/lib/worktree/repos.js +13 -2
- package/dist/lib/worktree/shareable.d.ts +3 -1
- package/dist/lib/worktree/shareable.js +53 -5
- package/extensions/worktree/hooks/on_enable.sh +17 -4
- package/extensions/worktree/manifest.json +1 -0
- package/extensions/worktree/scripts/lib/workbench-helpers.sh +58 -4
- package/extensions/worktree/scripts/preflight.sh +10 -46
- package/extensions/worktree/scripts/refresh-worktree.sh +18 -10
- package/extensions/worktree/scripts/setup-worktree.sh +11 -3
- package/extensions/worktree/templates/worktree-config.template.json +1 -1
- package/hooks/_hook-paths.js +129 -17
- package/hooks/_impl-phases.js +88 -0
- package/hooks/check-gates.js +3 -70
- package/hooks/eval-trigger.js +31 -5
- package/hooks/gate-reminder.js +92 -187
- package/package.json +2 -2
- package/skills/cleanup.md +1 -1
- package/skills/retrospective.md +1 -0
- /package/admin/.next/static/{4Mqj7sc33tNR898aibslD → F21UYqHRn4_drSf3X1wvn}/_buildManifest.js +0 -0
- /package/admin/.next/static/{4Mqj7sc33tNR898aibslD → F21UYqHRn4_drSf3X1wvn}/_clientMiddlewareManifest.js +0 -0
- /package/admin/.next/static/{4Mqj7sc33tNR898aibslD → F21UYqHRn4_drSf3X1wvn}/_ssgManifest.js +0 -0
package/hooks/gate-reminder.js
CHANGED
|
@@ -1,222 +1,127 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* PostToolUse hook:
|
|
3
|
+
* PostToolUse hook on Edit|Write: the phase reminder.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* When an edit to an `impl.md` closes a phase, tell the agent which trajectory
|
|
6
|
+
* rows the next phase opens with — the tests to author red before any code —
|
|
7
|
+
* and to call advance_plan. When a phase is mid-flight, name the rows that will
|
|
8
|
+
* block its close. Advisory: it never blocks.
|
|
9
|
+
*
|
|
10
|
+
* Delivery. A PostToolUse hook reaches the model in exactly one way at exit 0:
|
|
11
|
+
* a JSON envelope on stdout carrying `hookSpecificOutput.additionalContext`.
|
|
12
|
+
* stderr at exit 0 goes to the debug log and nowhere else. For its whole life
|
|
13
|
+
* this hook wrote to stderr and exited 0, so it was never once heard
|
|
14
|
+
* (workbench-trust-fixes, research F9). `console.info` writes to stdout and is
|
|
15
|
+
* on the linter's `noConsole` allowlist; a `console.log` here was swept once
|
|
16
|
+
* already and would be again.
|
|
17
|
+
*
|
|
18
|
+
* Phases. Two sequences ordered by document position (test-phase-structure):
|
|
19
|
+
* "the next phase" is the next heading in the document, whatever its kind, and
|
|
20
|
+
* trajectory cells are read through the shared `_trajectory-parser.js`, so
|
|
21
|
+
* `Build Phase 2`, `Test Phase 1` and `Phase 2` mean here exactly what they
|
|
22
|
+
* mean to check-gates. The nudge text has one definition — this file — pinned
|
|
23
|
+
* by `phase-start-nudge-single-definition.test.ts`.
|
|
7
24
|
*/
|
|
8
25
|
|
|
9
26
|
import { readFileSync } from "node:fs";
|
|
10
|
-
import {
|
|
27
|
+
import { phaseOrdinal, phaseSequence } from "./_impl-headings.js";
|
|
28
|
+
import { parseImplPhases } from "./_impl-phases.js";
|
|
29
|
+
import { parseTrajectoryFromBody, stripFrontmatter } from "./_trajectory-parser.js";
|
|
11
30
|
|
|
12
|
-
// Read hook input from stdin
|
|
13
31
|
let input = "";
|
|
14
32
|
for await (const chunk of process.stdin) {
|
|
15
33
|
input += chunk;
|
|
16
34
|
}
|
|
17
35
|
|
|
18
36
|
const event = JSON.parse(input);
|
|
19
|
-
const
|
|
20
|
-
const filePath = toolInput.file_path ?? "";
|
|
37
|
+
const filePath = event.tool_input?.file_path ?? "";
|
|
21
38
|
|
|
22
|
-
// Fast path: not an impl.md
|
|
39
|
+
// Fast path: not an impl.md. Silence is the correct output here (A2).
|
|
23
40
|
if (!filePath.endsWith("/impl.md") && !filePath.endsWith("\\impl.md")) {
|
|
24
41
|
process.exit(0);
|
|
25
42
|
}
|
|
26
43
|
|
|
27
|
-
// Read the impl file (post-edit state)
|
|
28
44
|
let content;
|
|
29
45
|
try {
|
|
30
|
-
content = readFileSync(filePath, "utf-8");
|
|
46
|
+
content = readFileSync(filePath, "utf-8"); // post-edit state
|
|
31
47
|
} catch {
|
|
32
48
|
process.exit(0);
|
|
33
49
|
}
|
|
34
50
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (line.match(FORWARD_INTELLIGENCE_HEADING)) {
|
|
66
|
-
currentGateType = "_fi";
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (currentPhase && currentGateType !== "_fi") {
|
|
71
|
-
const itemMatch = line.match(/^-\s+\[([ x])\]\s+(.*)/);
|
|
72
|
-
if (itemMatch) {
|
|
73
|
-
currentPhase.items.push({
|
|
74
|
-
checked: itemMatch[1] === "x",
|
|
75
|
-
gate: currentGateType,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (currentPhase) phases.push(currentPhase);
|
|
81
|
-
return phases;
|
|
51
|
+
const AUTHORABLE = new Set(["planned", "writable", ""]);
|
|
52
|
+
const CLOSES_PHASE = new Set(["passing", "skipped", "blocked"]);
|
|
53
|
+
|
|
54
|
+
const body = stripFrontmatter(content);
|
|
55
|
+
const sequence = phaseSequence(body);
|
|
56
|
+
const phases = parseImplPhases(content);
|
|
57
|
+
const { rows } = parseTrajectoryFromBody(body);
|
|
58
|
+
const hasTestPhases = sequence.some((p) => p.kind === "test");
|
|
59
|
+
|
|
60
|
+
const ordinalOf = (ref) => phaseOrdinal(ref, sequence);
|
|
61
|
+
const label = (p) =>
|
|
62
|
+
p.kind === "test"
|
|
63
|
+
? `Test Phase ${p.number}`
|
|
64
|
+
: hasTestPhases
|
|
65
|
+
? `Build Phase ${p.number}`
|
|
66
|
+
: `Phase ${p.number}`;
|
|
67
|
+
|
|
68
|
+
/** Rows the next phase must open by authoring, red. */
|
|
69
|
+
function writableAtNudge(next) {
|
|
70
|
+
const target = ordinalOf(next);
|
|
71
|
+
const due = rows.filter(
|
|
72
|
+
(r) =>
|
|
73
|
+
ordinalOf({ kind: r.writableAtKind, number: r.writableAt }) === target &&
|
|
74
|
+
AUTHORABLE.has(r.state),
|
|
75
|
+
);
|
|
76
|
+
if (due.length === 0) return null;
|
|
77
|
+
const lines = due.map((r) => ` [${r.id}] ${r.asserts}`);
|
|
78
|
+
return `${label(next)} opens with these tests to author (commit as failing before implementation work):\n${lines.join("\n")}`;
|
|
82
79
|
}
|
|
83
80
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
console.error(
|
|
104
|
-
`Phase ${phase.number} (${phase.name}) is fully complete. Call advance_plan to validate gates before starting Phase ${nextPhase.number}.`,
|
|
105
|
-
);
|
|
106
|
-
// Add trajectory nudges if applicable
|
|
107
|
-
const trajectory = parseTrajectoryRows(content);
|
|
108
|
-
if (trajectory.rows.length > 0) {
|
|
109
|
-
const startNudge = writableAtNudge(trajectory, nextPhase.number);
|
|
110
|
-
if (startNudge) console.error(`\n${startNudge}`);
|
|
111
|
-
}
|
|
112
|
-
process.exit(0);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
81
|
+
const parts = [];
|
|
82
|
+
|
|
83
|
+
// A phase that just became fully complete, with the next one not yet started.
|
|
84
|
+
// "Not started" means NOTHING in it is checked — once the next phase has
|
|
85
|
+
// begun, repeating the send-off on every edit is noise, and the phase in
|
|
86
|
+
// progress needs its own blockers instead (falsification A19).
|
|
87
|
+
for (let i = 0; i + 1 < phases.length; i++) {
|
|
88
|
+
const phase = phases[i];
|
|
89
|
+
const next = phases[i + 1];
|
|
90
|
+
if (phase.items.length === 0 || !phase.items.every((x) => x.checked)) continue;
|
|
91
|
+
if (next.items.some((x) => x.checked)) continue;
|
|
92
|
+
parts.push(
|
|
93
|
+
`${label(phase)} (${phase.name}) is fully complete. Call advance_plan to validate gates before starting ${label(next)}.`,
|
|
94
|
+
);
|
|
95
|
+
const nudge = writableAtNudge(next);
|
|
96
|
+
if (nudge) parts.push(nudge);
|
|
97
|
+
break;
|
|
115
98
|
}
|
|
116
99
|
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
const trajectory = parseTrajectoryRows(content);
|
|
120
|
-
if (trajectory.rows.length > 0) {
|
|
100
|
+
// Otherwise: a phase mid-flight whose trajectory rows will block its close.
|
|
101
|
+
if (parts.length === 0) {
|
|
121
102
|
for (const phase of phases) {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const blockers =
|
|
126
|
-
(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
row.state !== "skipped" &&
|
|
130
|
-
row.state !== "blocked",
|
|
103
|
+
const checked = phase.items.filter((x) => x.checked).length;
|
|
104
|
+
if (checked === 0 || checked === phase.items.length) continue;
|
|
105
|
+
const target = ordinalOf(phase);
|
|
106
|
+
const blockers = rows.filter(
|
|
107
|
+
(r) =>
|
|
108
|
+
ordinalOf({ kind: r.passesAtKind, number: r.passesAt }) === target &&
|
|
109
|
+
!CLOSES_PHASE.has(r.state),
|
|
131
110
|
);
|
|
132
|
-
if (blockers.length
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
process.exit(0);
|
|
143
|
-
|
|
144
|
-
// ------------------------------------------------------------------
|
|
145
|
-
// Trajectory parsing (minimal — just id, passesAt, state)
|
|
146
|
-
// ------------------------------------------------------------------
|
|
147
|
-
|
|
148
|
-
function parseTrajectoryRows(implContent) {
|
|
149
|
-
const fmMatch = implContent.match(/^---\n[\s\S]*?\n---\n/);
|
|
150
|
-
const body = fmMatch ? implContent.slice(fmMatch[0].length) : implContent;
|
|
151
|
-
const lines = body.split("\n");
|
|
152
|
-
|
|
153
|
-
let inTrajectory = false;
|
|
154
|
-
const tableLines = [];
|
|
155
|
-
for (const line of lines) {
|
|
156
|
-
if (/^##\s+Test Trajectory\b/.test(line)) {
|
|
157
|
-
inTrajectory = true;
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
if (!inTrajectory) continue;
|
|
161
|
-
if (/^###\s+Deferred Verification\b/.test(line)) break;
|
|
162
|
-
if (/^#{1,3}\s+/.test(line)) {
|
|
163
|
-
const depth = (line.match(/^(#{1,6})/) || ["", ""])[1].length;
|
|
164
|
-
if (depth <= 3) break;
|
|
165
|
-
}
|
|
166
|
-
tableLines.push(line);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const pipeLines = tableLines.filter((l) => l.trim().startsWith("|"));
|
|
170
|
-
if (pipeLines.length < 2) return { rows: [] };
|
|
171
|
-
const header = parseRow(pipeLines[0]);
|
|
172
|
-
const sep = parseRow(pipeLines[1]);
|
|
173
|
-
if (!sep.every((c) => /^:?-+:?$/.test(c))) return { rows: [] };
|
|
174
|
-
|
|
175
|
-
const keys = header.map((h) => {
|
|
176
|
-
const n = h.toLowerCase().trim();
|
|
177
|
-
if (n === "id") return "id";
|
|
178
|
-
if (n === "writable at") return "writableAt";
|
|
179
|
-
if (n === "passes at") return "passesAt";
|
|
180
|
-
if (n === "state") return "state";
|
|
181
|
-
if (n === "asserts") return "asserts";
|
|
182
|
-
return n;
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
const rows = [];
|
|
186
|
-
for (let i = 2; i < pipeLines.length; i++) {
|
|
187
|
-
const cells = parseRow(pipeLines[i]);
|
|
188
|
-
if (cells.length !== keys.length) continue;
|
|
189
|
-
const rec = {};
|
|
190
|
-
for (let j = 0; j < keys.length; j++) rec[keys[j]] = cells[j];
|
|
191
|
-
if (!rec.id) continue;
|
|
192
|
-
const w = (rec.writableAt || "").match(/^\s*Phase\s+(\d+)\s*$/i);
|
|
193
|
-
const p = (rec.passesAt || "").match(/^\s*Phase\s+(\d+)\s*$/i);
|
|
194
|
-
rows.push({
|
|
195
|
-
id: rec.id.trim(),
|
|
196
|
-
asserts: (rec.asserts || "").trim(),
|
|
197
|
-
writableAt: w ? Number.parseInt(w[1], 10) : Number.NaN,
|
|
198
|
-
passesAt: p ? Number.parseInt(p[1], 10) : Number.NaN,
|
|
199
|
-
state: (rec.state || "").toLowerCase().trim(),
|
|
200
|
-
});
|
|
111
|
+
if (blockers.length === 0) continue;
|
|
112
|
+
const lines = blockers.map((r) => ` [${r.id}] ${r.asserts} — state: ${r.state}`);
|
|
113
|
+
parts.push(
|
|
114
|
+
`${label(phase)} trajectory rows still not passing (will block phase close):\n${lines.join("\n")}`,
|
|
115
|
+
);
|
|
116
|
+
break; // one nudge per invocation
|
|
201
117
|
}
|
|
202
|
-
return { rows };
|
|
203
118
|
}
|
|
204
119
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
.split("|")
|
|
211
|
-
.map((c) => c.trim());
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function writableAtNudge(trajectory, phase) {
|
|
215
|
-
const rows = trajectory.rows.filter(
|
|
216
|
-
(r) =>
|
|
217
|
-
r.writableAt === phase && (r.state === "planned" || r.state === "writable" || r.state === ""),
|
|
120
|
+
if (parts.length > 0) {
|
|
121
|
+
console.info(
|
|
122
|
+
JSON.stringify({
|
|
123
|
+
hookSpecificOutput: { hookEventName: "PostToolUse", additionalContext: parts.join("\n\n") },
|
|
124
|
+
}),
|
|
218
125
|
);
|
|
219
|
-
if (rows.length === 0) return null;
|
|
220
|
-
const lines = rows.map((r) => ` [${r.id}] ${r.asserts}`);
|
|
221
|
-
return `Phase ${phase} opens with these tests to author (commit as failing before implementation work):\n${lines.join("\n")}`;
|
|
222
126
|
}
|
|
127
|
+
process.exit(0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infinitedusky/indusk-mcp",
|
|
3
|
-
"version": "1.44.
|
|
3
|
+
"version": "1.44.2",
|
|
4
4
|
"description": "InDusk development system — skills, MCP tools, and CLI for structured AI-assisted development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -109,6 +109,6 @@
|
|
|
109
109
|
"build": "tsc",
|
|
110
110
|
"start": "node dist/server/index.js",
|
|
111
111
|
"test": "vitest run",
|
|
112
|
-
"release": "npm whoami && pnpm publish --no-git-checks"
|
|
112
|
+
"release": "bash scripts/release-guard.sh && npm whoami && pnpm publish --no-git-checks"
|
|
113
113
|
}
|
|
114
114
|
}
|
package/skills/cleanup.md
CHANGED
|
@@ -39,7 +39,7 @@ Two consequences worth being explicit about:
|
|
|
39
39
|
|
|
40
40
|
This is best-practice-guided decomposition, not blanket extraction. **Extraction is not universally good** — forcing it produces 8-line "components", prop-drilling, and the wrong abstraction (which costs more than the duplication it removes). Recommend only what best practices actually warrant.
|
|
41
41
|
|
|
42
|
-
1. **Find the changed files that deserve scrutiny.** The threshold is a focus tool, not a cap. Use `listOversizedChangedFiles(planRoot, baseRef)` — import it from `@infinitedusky/indusk-mcp/cleanup/oversized` in a consumer project (or `apps/indusk-mcp/src/lib/cleanup/oversized.ts` in the dusk monorepo), invoked via `tsx` or a short Node script — it diffs the plan's branch against its merge base and returns the changed files over their resolved cleanup cap, with `{ path, loc, cap, scope, isNew }`. The caps come from the `cleanup` config block in `.indusk/config.json` (`max_file_loc` + per-scope overrides). A file being flagged means "look here", not "this fails". **Workbench caveat:** run it against the git repo/worktree where the code lives
|
|
42
|
+
1. **Find the changed files that deserve scrutiny.** The threshold is a focus tool, not a cap. Use `listOversizedChangedFiles(planRoot, baseRef)` — import it from `@infinitedusky/indusk-mcp/cleanup/oversized` in a consumer project (or `apps/indusk-mcp/src/lib/cleanup/oversized.ts` in the dusk monorepo), invoked via `tsx` or a short Node script — it diffs the plan's branch against its merge base and returns the changed files over their resolved cleanup cap, with `{ path, loc, cap, scope, isNew }`. The caps come from the `cleanup` config block in `.indusk/config.json` (`max_file_loc` + per-scope overrides). A file being flagged means "look here", not "this fails". **Workbench caveat:** run it against the git repo/worktree where the code lives. The workbench root (where `.indusk/` lives) holds the plan and none of the code, and the lib refuses there by declaration — it throws naming the declared repo dirs rather than reporting "nothing to clean" for code it never saw.
|
|
43
43
|
2. **Apply the enabled domain extensions' best practices.** What counts as a cohesive unit is domain-specific — it comes from the enabled extensions, not from this skill. Read the skills of the project's enabled domain extensions (via `extensions_status` / `get_skill_summaries`):
|
|
44
44
|
- **`nextjs`** — "minimize `"use client"` boundaries, push them as deep as possible"; "server components can't use hooks/event handlers". The concrete move on a Next.js project is often *pull the interactive `"use client"` island out of a big server component into its own file*, splitting server and client concerns.
|
|
45
45
|
- **`react`** — "one component per file for non-trivial components".
|
package/skills/retrospective.md
CHANGED
|
@@ -206,6 +206,7 @@ Re-read CLAUDE.md in full. After the entire impl is done, verify:
|
|
|
206
206
|
- **Key Decisions** — was the ADR decision added (post-ADR trigger)?
|
|
207
207
|
- **Known Gotchas** — were all surprises and corrections captured?
|
|
208
208
|
- **Current State** — does it reflect what's actually in progress?
|
|
209
|
+
- **Sequence** — does every active plan folder have exactly one fate: a step declared in the root `master.md` sequence, archived with a `closed_reason`, or standalone with a reason written in the master? A folder with none is how a close-out goes unwritten for weeks (indusk-makeover sat `completed` for 53 days in a queue labelled "any time"). Fix it here — declare it, archive it, or write the reason — and write any follow-on this plan surfaced into the brief of the step that owns it, not into this retrospective alone.
|
|
209
210
|
|
|
210
211
|
Fix any inaccuracies. The impl may have changed things that weren't anticipated in the per-phase context updates.
|
|
211
212
|
|
/package/admin/.next/static/{4Mqj7sc33tNR898aibslD → F21UYqHRn4_drSf3X1wvn}/_buildManifest.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|