pi-dev-flow 0.52.0 → 0.52.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/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ Format: newest first. `Unreleased` collects what's merged but not yet tagged.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.52.2] - 2026-10-21
8
+
9
+ ### Fixed
10
+
11
+ - **The `[dev-flow]` stage line printed twice per prompt.** One package reaches one runtime twice as fast as you install it — a project `git:` pin beside the global `npm:` package, or a dogfood checkout whose `.pi/extensions` pointer sits next to the installed copy — and pi dedupes extensions by **file path**, not by package, so both copies register and both answers were appended: two `[dev-flow]` lines in every prompt, in the logs and to the model. The stage-context handler now claims the run: pi builds **one ctx object per `before_agent_start`** and hands it to every registered handler, so the first pass stamps it and a rival copy answers nothing. The claim is per run rather than per process on purpose — pi-web hosts many sessions inside one Node process (dev-flow's own session map is keyed by session id for that reason), and a process-wide "only the first copy registers" rule would leave every later session without guards, without the `flow` tool and without stage context. Each copy still registers its guards, tool and command: their verdicts are identical, and pi exposes no runtime identity during load to dedupe them against.
12
+
13
+ ## [0.52.1] - 2026-10-21
14
+
15
+ ### Changed
16
+
17
+ - **The npm listing describes the flow instead of the pipeline.** The pi.dev package gallery builds its cards from name + description + keywords — its search box matches exactly that text, and the page renders no images — so the manifest now carries a description that says what the flow *is* (gated checkpoints, self-improvement reflections, one worktree per feature, changelog + publish as part of the release) plus thirteen keywords in the shape the other pi packages use. It also ships a banner (`banner.svg`, rasterized to `banner.png`, declared as `pi.image`): the five stages with the four checkpoint words over the gates, and the release stage pointing at "registry · image · release page" — deliberately generic, because where a release ships is the project's playbook, not dev-flow's. The package now names its resource directories explicitly under `pi` rather than relying on conventional discovery (the packed tarball was loaded against the real pi binary).
18
+
7
19
  ## [0.52.0] - 2026-10-21
8
20
 
9
21
  ### Added
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # dev-flow
2
2
 
3
+ ![dev-flow stages: plan, implement, pre-release, release, done — with the four operator checkpoints and the tag that publishes to npm](banner.png)
4
+
3
5
  An enforced feature workflow for [Pi](https://pi.dev), shipped as a pi package. You say what you
4
6
  want; an agent builds it; **the harness — not the agent's good manners — decides whether a stage
5
7
  may advance.** One feature at a time, five stages, and four questions asked of you —
@@ -48,7 +50,9 @@ pi install ./pi-dev-flow # or a local checkout
48
50
  ```
49
51
 
50
52
  Later releases arrive with `pi update --extensions` (an npm install reconciles to the newest version);
51
- then `/reload` — a running session keeps the code it loaded at startup.
53
+ then `/reload` — a running session keeps the code it loaded at startup. Two sources at once (a project
54
+ `git:` pin beside the global `npm:` package) load two copies — pi dedupes extensions by path, not by
55
+ package — so keep the one you actually update from.
52
56
 
53
57
  Then, once per project repo, `/flow init`. It reads the repo (default branch and forge from git,
54
58
  package manager, test/build/run conventions, version manifest) and writes **`.dev-flow/project.md`
package/banner.png ADDED
Binary file
package/banner.svg ADDED
@@ -0,0 +1,52 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1280" height="640" viewBox="0 0 1280 640" font-family="ui-monospace, SFMono-Regular, Menlo, monospace">
2
+ <rect width="1280" height="640" rx="18" fill="#0f1216"/>
3
+ <text x="60" y="112" fill="#e6edf3" font-size="46" font-weight="700">dev-flow</text>
4
+ <text x="60" y="156" fill="#8b98a9" font-size="21">enforced feature workflow for pi — one flow, one branch, one worktree per feature</text>
5
+
6
+ <!-- gates (checkpoint words the operator answers in chat) -->
7
+ <g fill="none" stroke="#f0b429" stroke-width="2">
8
+ <path d="M 260 236 l 14 14 l -14 14 l -14 -14 z"/>
9
+ <path d="M 500 236 l 14 14 l -14 14 l -14 -14 z"/>
10
+ <path d="M 740 236 l 14 14 l -14 14 l -14 -14 z"/>
11
+ <path d="M 980 236 l 14 14 l -14 14 l -14 -14 z"/>
12
+ </g>
13
+ <g fill="#f0b429" font-size="17" text-anchor="middle">
14
+ <text x="260" y="212">Approve?</text>
15
+ <text x="500" y="212">Verified?</text>
16
+ <text x="740" y="212">Release?</text>
17
+ <text x="980" y="212">Finish?</text>
18
+ </g>
19
+
20
+ <!-- stages -->
21
+ <g font-size="19" text-anchor="middle">
22
+ <rect x="60" y="270" width="200" height="62" rx="10" fill="#161b22" stroke="#39424e"/>
23
+ <text x="160" y="308" fill="#e6edf3">plan</text>
24
+ <rect x="300" y="270" width="200" height="62" rx="10" fill="#161b22" stroke="#39424e"/>
25
+ <text x="400" y="308" fill="#e6edf3">implement</text>
26
+ <rect x="540" y="270" width="200" height="62" rx="10" fill="#161b22" stroke="#39424e"/>
27
+ <text x="640" y="308" fill="#e6edf3">pre-release</text>
28
+ <rect x="780" y="270" width="200" height="62" rx="10" fill="#12261f" stroke="#3fb950"/>
29
+ <text x="880" y="308" fill="#7ee2a3">release</text>
30
+ <rect x="1020" y="270" width="200" height="62" rx="10" fill="#161b22" stroke="#39424e"/>
31
+ <text x="1120" y="308" fill="#e6edf3">done</text>
32
+ </g>
33
+ <g stroke="#4b5563" stroke-width="2" fill="#4b5563">
34
+ <line x1="260" y1="301" x2="296" y2="301"/><path d="M 296 301 l -8 -5 v 10 z"/>
35
+ <line x1="500" y1="301" x2="536" y2="301"/><path d="M 536 301 l -8 -5 v 10 z"/>
36
+ <line x1="740" y1="301" x2="776" y2="301"/><path d="M 776 301 l -8 -5 v 10 z"/>
37
+ <line x1="980" y1="301" x2="1016" y2="301"/><path d="M 1016 301 l -8 -5 v 10 z"/>
38
+ </g>
39
+
40
+ <text x="60" y="404" fill="#8b98a9" font-size="18">each gate refuses until its exit criteria hold — plan, checks, deploy, changelog, manifest, tag</text>
41
+
42
+ <!-- publishing hangs off the release stage: where it goes is the project's playbook, not dev-flow's -->
43
+ <g font-size="17">
44
+ <line x1="880" y1="332" x2="880" y2="444" stroke="#3fb950" stroke-width="2"/>
45
+ <path d="M 880 444 l -5 -8 h 10 z" fill="#3fb950"/>
46
+ <rect x="620" y="452" width="600" height="82" rx="10" fill="#12261f" stroke="#3fb950"/>
47
+ <text x="920" y="484" fill="#7ee2a3" text-anchor="middle">the release ships: registry · image · release page</text>
48
+ <text x="920" y="512" fill="#8b98a9" text-anchor="middle" font-size="15">release-done refuses to close while the artifact is missing</text>
49
+ </g>
50
+
51
+ <text x="60" y="576" fill="#5b6672" font-size="16">.dev-flow/&lt;slug&gt;/ — plan, state, worktree · guards keep edits inside the feature</text>
52
+ </svg>
@@ -194,6 +194,9 @@ const compacting = new Set<string>();
194
194
  /** Seam for the takeover's summarize call (pi's own compact()); tests replace `.run` — mutable object stands in for ESM mocking. */
195
195
  export const compactionTakeover: { run: typeof compact } = { run: compact };
196
196
 
197
+ /** Marks the before_agent_start pass that already wrote this run's [dev-flow] line — see the claim in that handler. */
198
+ const CONTEXT_EMITTED = Symbol.for("pi-dev-flow.context-emitted");
199
+
197
200
  function unfinishedStates(root: string): FlowState[] {
198
201
  if (!existsSync(dfDir(root))) return [];
199
202
  return readdirSync(dfDir(root), { withFileTypes: true })
@@ -1464,6 +1467,14 @@ export default function devFlow(pi: ExtensionAPI) {
1464
1467
  });
1465
1468
 
1466
1469
  pi.on("before_agent_start", async (_event, ctx) => {
1470
+ // One [dev-flow] line per run, whatever number of copies of this package are installed.
1471
+ // The same package reaches one runtime twice all the time (a project pin beside the npm install,
1472
+ // or this checkout's .pi/extensions pointer beside it) and pi dedupes extensions by file path
1473
+ // only, so both copies answer and the line lands twice in the prompt. pi hands every handler of
1474
+ // a run the same ctx object, so the first pass claims the run and the rival stays silent.
1475
+ const run = ctx as unknown as Record<symbol, boolean | undefined>;
1476
+ if (run[CONTEXT_EMITTED]) return undefined;
1477
+ run[CONTEXT_EMITTED] = true;
1467
1478
  if (!existsSync(dfDir(ctx.cwd))) return undefined;
1468
1479
  const cfg = loadProject(dfDir(ctx.cwd)).cfg;
1469
1480
  const state = boundFeature(ctx.cwd, sessionKey(ctx));
package/package.json CHANGED
@@ -1,10 +1,22 @@
1
1
  {
2
2
  "name": "pi-dev-flow",
3
- "version": "0.52.0",
4
- "description": "Enforced plan → implement → pre-release → release → done flow for Pi, as a pi package",
3
+ "version": "0.52.2",
4
+ "description": "Enforced feature workflow for Pi: plan → implement → pre-release → release, gated checkpoints, self-improvement reflections, one git worktree per feature, changelog + publish as part of the release",
5
5
  "type": "module",
6
6
  "keywords": [
7
- "pi-package"
7
+ "pi-package",
8
+ "pi",
9
+ "pi-coding-agent",
10
+ "extension",
11
+ "workflow",
12
+ "dev-flow",
13
+ "spec",
14
+ "plan",
15
+ "release",
16
+ "semver",
17
+ "changelog",
18
+ "git-worktree",
19
+ "guardrails"
8
20
  ],
9
21
  "license": "MIT",
10
22
  "repository": "https://github.com/dmarchevsky/pi-dev-flow",
@@ -16,10 +28,21 @@
16
28
  "src/",
17
29
  "skills/",
18
30
  "docs/",
31
+ "banner.svg",
32
+ "banner.png",
19
33
  "README.md",
20
34
  "CHANGELOG.md",
21
35
  "LICENSE"
22
36
  ],
37
+ "pi": {
38
+ "extensions": [
39
+ "./extensions/dev-flow.ts"
40
+ ],
41
+ "skills": [
42
+ "./skills"
43
+ ],
44
+ "image": "./banner.png"
45
+ },
23
46
  "peerDependencies": {
24
47
  "@earendil-works/pi-ai": "*",
25
48
  "@earendil-works/pi-coding-agent": "*",