@jwilger/pi-development-system 0.68.0 → 0.70.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.
|
@@ -19,6 +19,7 @@ import { registerRedFirstGuard } from "../src/gates/red-first-guard.ts";
|
|
|
19
19
|
import { createRequestApprovalTool } from "../src/gates/request-approval-tool.ts";
|
|
20
20
|
import { registerTestGuard } from "../src/gates/test-guard.ts";
|
|
21
21
|
import { createJevHolder } from "../src/jev/holder.ts";
|
|
22
|
+
import { createBeginWorkTool } from "../src/planning/begin-tool.ts";
|
|
22
23
|
import { createIntakeTool } from "../src/planning/intake-tool.ts";
|
|
23
24
|
import { createTaskCheckTool } from "../src/planning/task-check-tool.ts";
|
|
24
25
|
import { createReviewRecordTool, createReviewStartTool } from "../src/review/review-tools.ts";
|
|
@@ -141,6 +142,7 @@ export function createDevelopmentSystem(pi: ExtensionAPI) {
|
|
|
141
142
|
pi.registerTool(createRequestApprovalTool({ pi, approvals }));
|
|
142
143
|
pi.registerTool(createModelsTool());
|
|
143
144
|
pi.registerTool(createRouteTaskTool({ jev: (ctx) => jevHolder.forContext(ctx) }));
|
|
145
|
+
pi.registerTool(createBeginWorkTool({ state }));
|
|
144
146
|
pi.registerTool(createIntakeTool({ pi, state, jev: (ctx) => jevHolder.forContext(ctx) }));
|
|
145
147
|
pi.registerTool(createTaskCheckTool({ jev: (ctx) => jevHolder.forContext(ctx) }));
|
|
146
148
|
pi.registerTool(createWorkItemTool({ exec }));
|
package/package.json
CHANGED
package/prompts/devsys-plan.md
CHANGED
|
@@ -9,4 +9,4 @@ Write the plan for the current work with the work-intake-and-slicing skill.
|
|
|
9
9
|
3. Write each task so that someone who sees only that task could finish it. Never write `TBD`.
|
|
10
10
|
4. Run `devsys_task_check` on every task record you wrote and fix each one until it says ready. Split any that come back too-big.
|
|
11
11
|
5. Stop and ask the user to review the plan before any implementation starts. Do not start a goal yet: a goal tool may continue on its own and begin implementing before the review.
|
|
12
|
-
6. Only after the user approves the plan: if a `create_goal` tool exists in this session, call it with the objective "complete docs/plan/<slug>.md honouring its Constraints and Progress checklist, one increment at a time, stopping after each increment's Release step". Otherwise tell the user the plan path so they can start a goal on it. Do not depend on any goal tool's file format.
|
|
12
|
+
6. Only after the user approves the plan: call `devsys_begin_work` (so the review and red-first gates are on while the plan is built). Then, if a `create_goal` tool exists in this session, call it with the objective "complete docs/plan/<slug>.md honouring its Constraints and Progress checklist, one increment at a time, stopping after each increment's Release step". Otherwise tell the user the plan path so they can start a goal on it. Do not depend on any goal tool's file format.
|
package/prompts/devsys-start.md
CHANGED
|
@@ -6,5 +6,6 @@ Start new work with the work-intake-and-slicing skill.
|
|
|
6
6
|
|
|
7
7
|
1. Call `devsys_intake` with `request` set to: $ARGUMENTS (if empty, ask the user what they want done first).
|
|
8
8
|
2. Show the user the proposed size and artifacts. The tool asks them to confirm or change the size.
|
|
9
|
-
3.
|
|
10
|
-
4. For
|
|
9
|
+
3. Produce the planning artifacts first (brief, journeys, event model, architecture, lens review, in that order, whichever are recommended), then the task record. `review` and `adr-if-needed` are not written up front: review happens on the finished slice, and an ADR when a decision needs one. To skip one, call `devsys_record_departure` with gate `artifact.skipped:<artifact>` and the reason; do not skip silently. The event model and architecture are recommendations, never gates.
|
|
10
|
+
4. For `capability` and `product` the phase stays `planning` while you produce the artifacts; once the user approves them, call `devsys_begin_work` so the review and red-first gates switch on.
|
|
11
|
+
5. For a confirmed `fix` the user is also asked whether to skip fresh-context review (it is logged if they say yes; if no, the slice needs its review rounds). For `fix` and `change` the phase is already `implementing`: write the task record, then work it test-first.
|
|
@@ -54,4 +54,4 @@ Use `devsys_work_item` for the backlog. It reads `[tracker] kind` from `.develop
|
|
|
54
54
|
|
|
55
55
|
## Handing off
|
|
56
56
|
|
|
57
|
-
`/devsys-plan <slug>` writes `docs/plan/<slug>.md` in this structure and, when a goal tool is available
|
|
57
|
+
`/devsys-plan <slug>` writes `docs/plan/<slug>.md` in this structure and checks every task record. Then it stops for the user to review the plan. Only after they approve does it call `devsys_begin_work` (planning → implementing, which switches the review and red-first gates on) and start a goal to complete the plan, when a goal tool is available: a goal can begin implementing on its own, so it must not exist before the review.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { type Static, Type } from "typebox";
|
|
3
|
+
import type { SessionState } from "../state/session-state.ts";
|
|
4
|
+
|
|
5
|
+
const Parameters = Type.Object({});
|
|
6
|
+
|
|
7
|
+
const reply = (text: string, isError = false) => ({
|
|
8
|
+
content: [{ type: "text" as const, text }],
|
|
9
|
+
details: undefined,
|
|
10
|
+
isError,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* `devsys_begin_work`: the planning → implementing transition. Intake leaves capability and product work in
|
|
15
|
+
* `planning`; the review and red-first gates only run while implementing, so without this step the largest work
|
|
16
|
+
* would get the fewest gates. Call it once the user has approved the plan.
|
|
17
|
+
*/
|
|
18
|
+
export function createBeginWorkTool(deps: {
|
|
19
|
+
state: SessionState;
|
|
20
|
+
}): ToolDefinition<typeof Parameters> {
|
|
21
|
+
return {
|
|
22
|
+
name: "devsys_begin_work",
|
|
23
|
+
label: "Begin implementing",
|
|
24
|
+
description:
|
|
25
|
+
"Move from planning to implementing once the user has approved the plan. This switches on the review and red-first gates for the active slice.",
|
|
26
|
+
promptSnippet: "Start implementing after the plan is approved",
|
|
27
|
+
parameters: Parameters,
|
|
28
|
+
exposure: "direct",
|
|
29
|
+
execute(_id, _params: Static<typeof Parameters>) {
|
|
30
|
+
const { phase, activeSlice } = deps.state.get();
|
|
31
|
+
if (phase !== "planning" || activeSlice === undefined) {
|
|
32
|
+
return Promise.resolve(
|
|
33
|
+
reply(
|
|
34
|
+
`Nothing to begin: phase is ${phase}${activeSlice === undefined ? " with no active slice" : ""}. Use devsys_intake to size new work first.`,
|
|
35
|
+
true,
|
|
36
|
+
),
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
deps.state.update((s) => ({ ...s, phase: "implementing" }));
|
|
40
|
+
return Promise.resolve(
|
|
41
|
+
reply(
|
|
42
|
+
`Phase: implementing. Active slice: ${activeSlice}. Review and red-first gates are now on.`,
|
|
43
|
+
),
|
|
44
|
+
);
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -34,7 +34,7 @@ const STEPS_MIN = 3;
|
|
|
34
34
|
const STEPS_MAX = 7;
|
|
35
35
|
/** Words that stand in for a command or an observable result. */
|
|
36
36
|
const PLACEHOLDER =
|
|
37
|
-
/^(?:(?:tbd|tbc)\b.*|todo\s*(?::.*)?|n\/?a|none
|
|
37
|
+
/^(?:(?:tbd|tbc)\b.*|todo\s*(?::.*)?|n\/?a|none|[-—–]|…|\.\.\.|<[^<>]*>|works?|it works|passes|ok)\.?$/i;
|
|
38
38
|
|
|
39
39
|
const isSection = (name: string): name is Section => SECTIONS.some((s) => s === name);
|
|
40
40
|
|
|
@@ -176,7 +176,7 @@ function problemsOf(markdown: string, split: Sections): string[] {
|
|
|
176
176
|
}
|
|
177
177
|
const missing = SECTIONS.filter((s) => got(sections, s) === "");
|
|
178
178
|
if (missing.length > 0) problems.push(`missing section: ${missing.join(", ")}`);
|
|
179
|
-
if (/\bTBD\b
|
|
179
|
+
if (/\bTBD\b/i.test(markdown)) problems.push("contains TBD; decide it or split the task");
|
|
180
180
|
const steps = stepsOf(get(sections, "Steps"));
|
|
181
181
|
if (!missing.includes("Steps") && (steps.length < STEPS_MIN || steps.length > STEPS_MAX)) {
|
|
182
182
|
problems.push(`Steps must be ${STEPS_MIN}-${STEPS_MAX} steps, found ${steps.length}`);
|