@curdx/flow 6.0.5 → 6.0.6
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 +9 -45
- package/dist/index.mjs +9 -96
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@curdx/flow` are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/) and the project follows [Semantic Versioning](https://semver.org/).
|
|
4
4
|
|
|
5
|
+
## 6.0.6 — 2026-04-29
|
|
6
|
+
|
|
7
|
+
### Removed
|
|
8
|
+
|
|
9
|
+
- **Legacy plugin migration code path.** `LEGACY_PLUGIN_IDS`, `uninstallLegacyIfPresent`, and the entire `src/runner/legacy-cleanup.ts` file removed. Users still on v3.x slugs will need to manually `claude plugin uninstall` the old slug before upgrading — the auto-cleanup is gone.
|
|
10
|
+
- **Historical CHANGELOG entries for the v3.x rename releases** (3.4.0, 3.5.0, 4.0.0, 4.0.1) deleted. Keep-a-Changelog convention deliberately violated at the user's request.
|
|
11
|
+
- LICENSE copyright line and NOTICE.md attribution intentionally untouched (MIT licensing requires these).
|
|
12
|
+
|
|
5
13
|
## 6.0.5 — 2026-04-29
|
|
6
14
|
|
|
7
15
|
### Changed
|
|
8
16
|
|
|
9
|
-
- **Drop legacy upstream-attribution chrome from user-facing surfaces.**
|
|
17
|
+
- **Drop legacy upstream-attribution chrome from user-facing surfaces.** Install description and README tools table / migration notes block scrubbed. MIT `LICENSE` copyright line and `NOTICE.md` attribution preserved verbatim (legal requirement).
|
|
10
18
|
|
|
11
19
|
## 6.0.4 — 2026-04-29
|
|
12
20
|
|
|
@@ -31,50 +39,6 @@ All notable changes to `@curdx/flow` are documented here. Format follows [Keep a
|
|
|
31
39
|
|
|
32
40
|
- Both additions are repo-internal — neither file ships in the npm tarball (`files: ["dist", "CHANGELOG.md"]` is unchanged), so the published artifact is byte-identical to 6.0.1 modulo version metadata. This release exists to dogfood the new `bump-version` flow end-to-end.
|
|
33
41
|
|
|
34
|
-
## 4.0.1 — 2026-04-27
|
|
35
|
-
|
|
36
|
-
### Fixed
|
|
37
|
-
|
|
38
|
-
- **Migration cleanup is now exhaustive.** v4.0.0's auto-migration for the `ralph-specum` → `curdx-flow` rename only invoked `claude plugin uninstall`, which leaves substantial residue when the marketplace's plugin id has been renamed (the CLI can't resolve the legacy id and bails). The installer now manually purges every leftover artifact for legacy slugs (`ralph-specum@curdx-flow`, `ralph-specum@smart-ralph`):
|
|
39
|
-
- `~/.claude/settings.json` → removes `enabledPlugins[<legacyId>]`
|
|
40
|
-
- `~/.claude/plugins/installed_plugins.json` → removes `plugins[<legacyId>]`
|
|
41
|
-
- `~/.claude/plugins/cache/<marketplace>/<name>/` → recursive remove
|
|
42
|
-
- `~/.claude/plugins/data/<name>-<marketplace>/` → recursive remove
|
|
43
|
-
- Marketplace registrations (`known_marketplaces.json`, `extraKnownMarketplaces`) are deliberately left alone — those are user-managed.
|
|
44
|
-
- Implementation lives in `src/runner/legacy-cleanup.ts::purgeLegacyPluginArtifacts`. Idempotent and safe: every step swallows ENOENT silently and reports JSON / IO errors via the install task log without failing the flow.
|
|
45
|
-
|
|
46
|
-
## 4.0.0 — 2026-04-27
|
|
47
|
-
|
|
48
|
-
### Breaking
|
|
49
|
-
|
|
50
|
-
- **Plugin renamed `ralph-specum` → `curdx-flow`.** The bundled spec-driven workflow plugin now lives under the `curdx-flow` brand, slash namespace `/curdx-flow:*`, full slug `curdx-flow@curdx`. The marketplace identifier was simultaneously shortened from `curdx-flow` to `curdx` (the GitHub repo source `curdx/curdx-flow` is unchanged). All in-plugin slash references, env vars (`RALPH_SPECUM_*` → `CURDX_FLOW_*`), and labels were updated accordingly.
|
|
51
|
-
- **Auto-migration:** the installer now detects legacy `ralph-specum@curdx-flow` and `ralph-specum@smart-ralph` installs and uninstalls them automatically before installing the new slug, so users on v3.4 / v3.5 transparently transition. Your `specs/` directory and any in-progress spec state files are not touched — the rename is purely a plugin-identity change.
|
|
52
|
-
- **Manual fallback:** if you'd rather run the migration yourself, execute `claude plugin uninstall ralph-specum@curdx-flow` (or `@smart-ralph`) before re-running `npx @curdx/flow install`. The old marketplace `curdx-flow` may remain registered alongside the new `curdx` marketplace; this is harmless and you can `claude plugin marketplace remove curdx-flow` if you want to clean up.
|
|
53
|
-
|
|
54
|
-
### Notes
|
|
55
|
-
|
|
56
|
-
- The plugin's authorship and license lineage (smart-ralph by tzachbon → ralph-specum fork → curdx-flow) is recorded in `plugins/curdx-flow/NOTICE.md`. MIT License preserved.
|
|
57
|
-
- `.claude-plugin/marketplace.json` now declares one plugin: `curdx-flow` v4.9.1 sourced from `./plugins/curdx-flow`.
|
|
58
|
-
|
|
59
|
-
## 3.5.0 — 2026-04-27
|
|
60
|
-
|
|
61
|
-
### Changed
|
|
62
|
-
|
|
63
|
-
- **`ralph-specum` is now a required bundled plugin** — it no longer appears as an optional checkbox in the install multiselect. Instead, it's listed in a dedicated "always installed" header above the prompt, alongside its current state (not installed / up-to-date / update available). When the flow runs, ralph-specum is auto-installed or auto-updated whenever it needs action; up-to-date installs are silently skipped. The other six items (pua, claude-mem, chrome-devtools-mcp, frontend-design, sequential-thinking, context7) remain optional. `--ids X` now also auto-includes required plugins that need action; users can still explicitly run `--ids ralph-specum` to force a reinstall confirmation. Uninstall flow is unchanged — users may still uninstall ralph-specum, and the next install will re-add it.
|
|
64
|
-
- **Internal:** `Pkg` type gains a `required?: boolean` field so future bundled plugins can opt into the same "always installed" semantics without touching install-flow code.
|
|
65
|
-
|
|
66
|
-
## 3.4.0 — 2026-04-27
|
|
67
|
-
|
|
68
|
-
### Added
|
|
69
|
-
|
|
70
|
-
- **`ralph-specum` is now a bundled plugin** — spec-driven development with autonomous task-by-task execution (research → requirements → design → tasks → implement, plus epic triage). Originally authored by [tzachbon](https://github.com/tzachbon/smart-ralph); ralph-specum v4.9.1 has been migrated into this repository as the canonical home and is no longer tracked against upstream. MIT license and authorship are preserved at `plugins/ralph-specum/LICENSE` and `plugins/ralph-specum/NOTICE.md`.
|
|
71
|
-
- **curdx-flow itself is now a Claude Code marketplace** — the repo ships `.claude-plugin/marketplace.json` so Claude CLI can install bundled plugins via `claude plugin marketplace add curdx/curdx-flow` + `claude plugin install ralph-specum@curdx-flow`. The flow installer wires this up automatically; users just run `npx @curdx/flow install` and ralph-specum is pre-checked in the multiselect along with the other not-installed items.
|
|
72
|
-
|
|
73
|
-
### Notes
|
|
74
|
-
|
|
75
|
-
- If you previously installed ralph-specum from the upstream `tzachbon/smart-ralph` marketplace, run `claude plugin uninstall ralph-specum@smart-ralph` before installing this version to avoid a name collision. Going forward, only the `ralph-specum@curdx-flow` build is maintained.
|
|
76
|
-
- Plugin files are not shipped in the npm tarball (`package.json` `files` is unchanged: `["dist", "CHANGELOG.md"]`). They live in the GitHub repo and are pulled by Claude CLI when the marketplace is added — so a `git push` of this repo must precede `npm publish` for a new release to be installable.
|
|
77
|
-
|
|
78
42
|
## 3.3.2 — 2026-04-27
|
|
79
43
|
|
|
80
44
|
### Fixed
|
package/dist/index.mjs
CHANGED
|
@@ -576,94 +576,11 @@ var frontendDesign = {
|
|
|
576
576
|
};
|
|
577
577
|
var frontend_design_default = frontendDesign;
|
|
578
578
|
|
|
579
|
-
// src/runner/legacy-cleanup.ts
|
|
580
|
-
import { promises as fs2 } from "fs";
|
|
581
|
-
import path2 from "path";
|
|
582
|
-
import os2 from "os";
|
|
583
|
-
async function purgeLegacyPluginArtifacts(legacyId, ctx) {
|
|
584
|
-
const at = legacyId.indexOf("@");
|
|
585
|
-
if (at <= 0 || at === legacyId.length - 1) return;
|
|
586
|
-
const name = legacyId.slice(0, at);
|
|
587
|
-
const marketplace = legacyId.slice(at + 1);
|
|
588
|
-
const home = os2.homedir();
|
|
589
|
-
const settingsPath = path2.join(home, ".claude", "settings.json");
|
|
590
|
-
const installedPath = path2.join(home, ".claude", "plugins", "installed_plugins.json");
|
|
591
|
-
const cacheDir = path2.join(home, ".claude", "plugins", "cache", marketplace, name);
|
|
592
|
-
const dataDir = path2.join(home, ".claude", "plugins", "data", `${name}-${marketplace}`);
|
|
593
|
-
let removedAny = false;
|
|
594
|
-
removedAny = await deleteJsonKey(settingsPath, ["enabledPlugins", legacyId], ctx) || removedAny;
|
|
595
|
-
removedAny = await deleteJsonKey(installedPath, ["plugins", legacyId], ctx) || removedAny;
|
|
596
|
-
removedAny = await rmDir(cacheDir, ctx) || removedAny;
|
|
597
|
-
removedAny = await rmDir(dataDir, ctx) || removedAny;
|
|
598
|
-
if (removedAny) {
|
|
599
|
-
ctx.log.message(`Purged legacy artifacts for ${legacyId}.`);
|
|
600
|
-
clearStateCache();
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
async function deleteJsonKey(filePath, keyPath, ctx) {
|
|
604
|
-
let raw;
|
|
605
|
-
try {
|
|
606
|
-
raw = await fs2.readFile(filePath, "utf8");
|
|
607
|
-
} catch (err) {
|
|
608
|
-
if (err.code === "ENOENT") return false;
|
|
609
|
-
ctx.log.message(`Skip purge of ${filePath}: ${err.message}`);
|
|
610
|
-
return false;
|
|
611
|
-
}
|
|
612
|
-
let json;
|
|
613
|
-
try {
|
|
614
|
-
json = JSON.parse(raw);
|
|
615
|
-
} catch (err) {
|
|
616
|
-
ctx.log.message(`Skip purge of ${filePath}: invalid JSON (${err.message})`);
|
|
617
|
-
return false;
|
|
618
|
-
}
|
|
619
|
-
let cursor = json;
|
|
620
|
-
for (let i = 0; i < keyPath.length - 1; i++) {
|
|
621
|
-
const next = cursor?.[keyPath[i]];
|
|
622
|
-
if (!next || typeof next !== "object") return false;
|
|
623
|
-
cursor = next;
|
|
624
|
-
}
|
|
625
|
-
const finalKey = keyPath[keyPath.length - 1];
|
|
626
|
-
if (!cursor || !(finalKey in cursor)) return false;
|
|
627
|
-
delete cursor[finalKey];
|
|
628
|
-
try {
|
|
629
|
-
await fs2.writeFile(filePath, JSON.stringify(json, null, 2) + "\n", "utf8");
|
|
630
|
-
return true;
|
|
631
|
-
} catch (err) {
|
|
632
|
-
ctx.log.message(`Failed to rewrite ${filePath}: ${err.message}`);
|
|
633
|
-
return false;
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
async function rmDir(dirPath, ctx) {
|
|
637
|
-
try {
|
|
638
|
-
await fs2.access(dirPath);
|
|
639
|
-
} catch {
|
|
640
|
-
return false;
|
|
641
|
-
}
|
|
642
|
-
try {
|
|
643
|
-
await fs2.rm(dirPath, { recursive: true, force: true });
|
|
644
|
-
return true;
|
|
645
|
-
} catch (err) {
|
|
646
|
-
ctx.log.message(`Failed to remove ${dirPath}: ${err.message}`);
|
|
647
|
-
return false;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
579
|
// src/registry/plugins/curdx-flow.ts
|
|
652
580
|
var PLUGIN_ID5 = "curdx-flow@curdx";
|
|
653
581
|
var PLUGIN_NAME3 = "curdx-flow";
|
|
654
582
|
var MARKETPLACE_NAME4 = "curdx";
|
|
655
583
|
var MARKETPLACE_SOURCE4 = "curdx/curdx-flow";
|
|
656
|
-
var LEGACY_PLUGIN_IDS = ["ralph-specum@curdx-flow", "ralph-specum@smart-ralph"];
|
|
657
|
-
async function uninstallLegacyIfPresent(ctx) {
|
|
658
|
-
for (const legacyId of LEGACY_PLUGIN_IDS) {
|
|
659
|
-
const installed = await isPluginInstalled(legacyId);
|
|
660
|
-
if (installed) {
|
|
661
|
-
ctx.log.message(`Removing legacy plugin ${legacyId} (renamed to ${PLUGIN_ID5})\u2026`);
|
|
662
|
-
await uninstallPluginById(legacyId, ctx);
|
|
663
|
-
}
|
|
664
|
-
await purgeLegacyPluginArtifacts(legacyId, ctx);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
584
|
var curdxFlow = {
|
|
668
585
|
id: "curdx-flow",
|
|
669
586
|
name: "curdx-flow",
|
|
@@ -681,15 +598,11 @@ var curdxFlow = {
|
|
|
681
598
|
},
|
|
682
599
|
latestVersion: () => getMarketplacePluginVersion(MARKETPLACE_NAME4, PLUGIN_NAME3),
|
|
683
600
|
install: async (ctx) => {
|
|
684
|
-
await uninstallLegacyIfPresent(ctx);
|
|
685
601
|
await ensureMarketplace(MARKETPLACE_NAME4, MARKETPLACE_SOURCE4, ctx);
|
|
686
602
|
await installPluginById(PLUGIN_ID5, ctx);
|
|
687
603
|
},
|
|
688
604
|
uninstall: (ctx) => uninstallPluginById(PLUGIN_ID5, ctx),
|
|
689
|
-
update:
|
|
690
|
-
await uninstallLegacyIfPresent(ctx);
|
|
691
|
-
await updatePluginById(PLUGIN_ID5, ctx);
|
|
692
|
-
}
|
|
605
|
+
update: (ctx) => updatePluginById(PLUGIN_ID5, ctx)
|
|
693
606
|
};
|
|
694
607
|
var curdx_flow_default = curdxFlow;
|
|
695
608
|
|
|
@@ -799,15 +712,15 @@ function findPkg(id) {
|
|
|
799
712
|
}
|
|
800
713
|
|
|
801
714
|
// src/runner/claudeMd.ts
|
|
802
|
-
import { promises as
|
|
803
|
-
import
|
|
804
|
-
import
|
|
715
|
+
import { promises as fs2 } from "fs";
|
|
716
|
+
import path2 from "path";
|
|
717
|
+
import os2 from "os";
|
|
805
718
|
import * as p3 from "@clack/prompts";
|
|
806
719
|
var BEGIN_MARKER = "<!-- BEGIN @curdx/flow v1 -->";
|
|
807
720
|
var END_MARKER = "<!-- END @curdx/flow v1 -->";
|
|
808
721
|
var BLOCK_RE = /<!-- BEGIN @curdx\/flow v\d+[^>]*-->[\s\S]*?<!-- END @curdx\/flow v\d+ -->/;
|
|
809
722
|
function claudeMdPath() {
|
|
810
|
-
return
|
|
723
|
+
return path2.join(os2.homedir(), ".claude", "CLAUDE.md");
|
|
811
724
|
}
|
|
812
725
|
function buildCombinationPatterns(ids) {
|
|
813
726
|
const has = (k) => ids.has(k);
|
|
@@ -961,7 +874,7 @@ async function syncClaudeMd(opts) {
|
|
|
961
874
|
let existing = "";
|
|
962
875
|
let existed = true;
|
|
963
876
|
try {
|
|
964
|
-
existing = await
|
|
877
|
+
existing = await fs2.readFile(file, "utf8");
|
|
965
878
|
} catch (err) {
|
|
966
879
|
if (err.code === "ENOENT") {
|
|
967
880
|
existed = false;
|
|
@@ -983,10 +896,10 @@ async function syncClaudeMd(opts) {
|
|
|
983
896
|
if (next === existing) {
|
|
984
897
|
return { status: "unchanged", path: file };
|
|
985
898
|
}
|
|
986
|
-
await
|
|
899
|
+
await fs2.mkdir(path2.dirname(file), { recursive: true });
|
|
987
900
|
const tmp = `${file}.tmp.${process.pid}`;
|
|
988
|
-
await
|
|
989
|
-
await
|
|
901
|
+
await fs2.writeFile(tmp, next, "utf8");
|
|
902
|
+
await fs2.rename(tmp, file);
|
|
990
903
|
if (!existed) return { status: "created", path: file };
|
|
991
904
|
if (hadBlock && items.length === 0) return { status: "removed", path: file };
|
|
992
905
|
return { status: "updated", path: file };
|