contract-driven-delivery 2.0.1 → 2.0.3
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 +32 -0
- package/bin/postinstall.js +20 -0
- package/dist/cli/index.js +64 -36
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.0.3] - 2026-04-30
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- `cdd-kit update` now syncs all installed skills (`cdd-new`, `cdd-close`,
|
|
8
|
+
`cdd-resume`, `cdd-init`, `contract-driven-delivery`) instead of only
|
|
9
|
+
`contract-driven-delivery`. Previously the four standalone skills were silently
|
|
10
|
+
left stale after an npm upgrade.
|
|
11
|
+
- Backup path corrected from `.cdd-kit-backup/<ts>/skill/` to `.../skills/`
|
|
12
|
+
to cover all skill directories.
|
|
13
|
+
|
|
14
|
+
## [2.0.2] - 2026-04-30
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- `npm postinstall` hook: after `npm install -g` or `npm update -g`, skills and
|
|
19
|
+
agents in `~/.claude/` are automatically synced to the newly installed version.
|
|
20
|
+
The sync is a no-op when `cdd-kit init` has never been run (safe for CI and
|
|
21
|
+
local dev installs of the package itself). A backup of any locally modified
|
|
22
|
+
files is created in `~/.claude/.cdd-kit-backup/<timestamp>/` before overwriting,
|
|
23
|
+
matching the existing `cdd-kit update --yes` behaviour.
|
|
24
|
+
- `cdd-kit update --postinstall` flag (internal): quiet mode that implies
|
|
25
|
+
`--yes`, locks provider to `claude`, and silently exits when the skill
|
|
26
|
+
directory is absent. Not intended for direct user invocation.
|
|
27
|
+
|
|
28
|
+
### Migration note
|
|
29
|
+
|
|
30
|
+
The first `npm update -g contract-driven-delivery` that brings in this version
|
|
31
|
+
will **not** auto-sync (the postinstall hook did not exist in the previously
|
|
32
|
+
installed version). Run `cdd-kit update --yes` once after this upgrade; all
|
|
33
|
+
subsequent upgrades will auto-sync.
|
|
34
|
+
|
|
3
35
|
## [2.0.1] - 2026-04-30
|
|
4
36
|
|
|
5
37
|
### Fixed
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { join, dirname } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
const cliPath = join(__dirname, '..', 'dist', 'cli', 'index.js');
|
|
11
|
+
if (!existsSync(cliPath)) process.exit(0);
|
|
12
|
+
|
|
13
|
+
spawnSync(process.execPath, [cliPath, 'update', '--postinstall'], {
|
|
14
|
+
stdio: 'inherit',
|
|
15
|
+
timeout: 30_000,
|
|
16
|
+
});
|
|
17
|
+
process.exit(0);
|
|
18
|
+
} catch {
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -11673,7 +11673,16 @@ function backupDir(dir, backupDest) {
|
|
|
11673
11673
|
walk(dir, backupDest);
|
|
11674
11674
|
}
|
|
11675
11675
|
async function update(opts) {
|
|
11676
|
-
|
|
11676
|
+
if (opts.postinstall) {
|
|
11677
|
+
if (!existsSync5(join6(SKILLS_HOME, "contract-driven-delivery"))) {
|
|
11678
|
+
return;
|
|
11679
|
+
}
|
|
11680
|
+
opts.yes = true;
|
|
11681
|
+
opts.provider = "claude";
|
|
11682
|
+
}
|
|
11683
|
+
const quiet = !!opts.postinstall;
|
|
11684
|
+
if (!quiet)
|
|
11685
|
+
log.blank();
|
|
11677
11686
|
const cwd = process.cwd();
|
|
11678
11687
|
const requestedProvider = opts.provider ?? "auto";
|
|
11679
11688
|
if (!validateProviderOption(requestedProvider)) {
|
|
@@ -11682,35 +11691,38 @@ async function update(opts) {
|
|
|
11682
11691
|
}
|
|
11683
11692
|
const provider = inferProvider(cwd, requestedProvider);
|
|
11684
11693
|
const updateClaudeAssets = provider === "claude" || provider === "both";
|
|
11685
|
-
const skillDest = join6(SKILLS_HOME, "contract-driven-delivery");
|
|
11686
11694
|
const agentDiff = updateClaudeAssets ? diffDir(ASSET.agents, AGENTS_HOME) : [];
|
|
11687
|
-
const skillDiff = updateClaudeAssets ? diffDir(ASSET.
|
|
11695
|
+
const skillDiff = updateClaudeAssets ? readdirSync3(ASSET.skills, { withFileTypes: true }).filter((d) => d.isDirectory()).flatMap((d) => diffDir(join6(ASSET.skills, d.name), join6(SKILLS_HOME, d.name))) : [];
|
|
11688
11696
|
const toWrite = [...agentDiff, ...skillDiff].filter((e) => e.action !== "skip");
|
|
11689
11697
|
const toAdd = toWrite.filter((e) => e.action === "add");
|
|
11690
11698
|
const toOver = toWrite.filter((e) => e.action === "overwrite");
|
|
11691
11699
|
const toSkip = [...agentDiff, ...skillDiff].filter((e) => e.action === "skip");
|
|
11692
|
-
|
|
11693
|
-
|
|
11694
|
-
|
|
11695
|
-
|
|
11696
|
-
|
|
11697
|
-
|
|
11698
|
-
|
|
11700
|
+
if (!quiet) {
|
|
11701
|
+
log.info(`Provider: ${provider}`);
|
|
11702
|
+
if (updateClaudeAssets) {
|
|
11703
|
+
log.info(`Dry-run diff \u2014 agents: ${AGENTS_HOME}`);
|
|
11704
|
+
log.info(`Dry-run diff \u2014 skills: ${SKILLS_HOME}`);
|
|
11705
|
+
} else {
|
|
11706
|
+
log.info("Codex provider has no global cdd-kit assets to update.");
|
|
11707
|
+
log.info("Project files are preserved; run cdd-kit init --local-only --provider codex to add missing local guidance.");
|
|
11708
|
+
}
|
|
11709
|
+
log.blank();
|
|
11710
|
+
if (toAdd.length)
|
|
11711
|
+
log.info(` + ${toAdd.length} file(s) would be added`);
|
|
11712
|
+
if (toOver.length)
|
|
11713
|
+
log.warn(` ~ ${toOver.length} file(s) would be overwritten (user edits lost without backup)`);
|
|
11714
|
+
if (toSkip.length)
|
|
11715
|
+
log.dim(` ${toSkip.length} file(s) unchanged (skipped)`);
|
|
11699
11716
|
}
|
|
11700
|
-
log.blank();
|
|
11701
|
-
if (toAdd.length)
|
|
11702
|
-
log.info(` + ${toAdd.length} file(s) would be added`);
|
|
11703
|
-
if (toOver.length)
|
|
11704
|
-
log.warn(` ~ ${toOver.length} file(s) would be overwritten (user edits lost without backup)`);
|
|
11705
|
-
if (toSkip.length)
|
|
11706
|
-
log.dim(` ${toSkip.length} file(s) unchanged (skipped)`);
|
|
11707
11717
|
if (toWrite.length === 0) {
|
|
11708
|
-
|
|
11709
|
-
|
|
11710
|
-
|
|
11718
|
+
if (!quiet) {
|
|
11719
|
+
log.blank();
|
|
11720
|
+
log.ok("Already up to date \u2014 nothing to write.");
|
|
11721
|
+
log.blank();
|
|
11722
|
+
}
|
|
11711
11723
|
return;
|
|
11712
11724
|
}
|
|
11713
|
-
if (!opts.yes) {
|
|
11725
|
+
if (!quiet && !opts.yes) {
|
|
11714
11726
|
log.blank();
|
|
11715
11727
|
log.info("Run with --yes to apply changes. Example:");
|
|
11716
11728
|
log.dim(" cdd-kit update --yes");
|
|
@@ -11719,25 +11731,41 @@ async function update(opts) {
|
|
|
11719
11731
|
}
|
|
11720
11732
|
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
11721
11733
|
const backupRoot = join6(homedir2(), ".claude", ".cdd-kit-backup", timestamp2);
|
|
11722
|
-
|
|
11723
|
-
|
|
11734
|
+
if (!quiet) {
|
|
11735
|
+
log.blank();
|
|
11736
|
+
log.info(`Backing up to ${backupRoot} \u2026`);
|
|
11737
|
+
}
|
|
11724
11738
|
backupDir(AGENTS_HOME, join6(backupRoot, "agents"));
|
|
11725
|
-
backupDir(
|
|
11726
|
-
|
|
11727
|
-
|
|
11739
|
+
backupDir(SKILLS_HOME, join6(backupRoot, "skills"));
|
|
11740
|
+
if (!quiet)
|
|
11741
|
+
log.ok(`Backup complete: ${backupRoot}`);
|
|
11742
|
+
if (!quiet)
|
|
11743
|
+
log.blank();
|
|
11744
|
+
let totalSynced = 0;
|
|
11728
11745
|
if (updateClaudeAssets) {
|
|
11729
|
-
|
|
11746
|
+
if (!quiet)
|
|
11747
|
+
log.info(`Updating agents \u2192 ${AGENTS_HOME}`);
|
|
11730
11748
|
const agentCount = applyDir(agentDiff);
|
|
11731
|
-
|
|
11732
|
-
|
|
11749
|
+
if (!quiet)
|
|
11750
|
+
log.ok(`${agentCount} agent file(s) updated.`);
|
|
11751
|
+
totalSynced += agentCount;
|
|
11752
|
+
if (!quiet)
|
|
11753
|
+
log.info(`Updating skills \u2192 ${SKILLS_HOME}`);
|
|
11733
11754
|
const skillCount = applyDir(skillDiff);
|
|
11734
|
-
|
|
11755
|
+
if (!quiet)
|
|
11756
|
+
log.ok(`${skillCount} skill file(s) updated.`);
|
|
11757
|
+
totalSynced += skillCount;
|
|
11758
|
+
}
|
|
11759
|
+
if (quiet) {
|
|
11760
|
+
if (totalSynced > 0)
|
|
11761
|
+
log.ok(`cdd-kit: synced ${totalSynced} file(s) to ~/.claude/`);
|
|
11762
|
+
} else {
|
|
11763
|
+
log.blank();
|
|
11764
|
+
log.info("Project files (contracts/, specs/, tests/, ci/) were not changed.");
|
|
11765
|
+
log.ok("Update complete.");
|
|
11766
|
+
log.info(`Backup saved to: ${backupRoot}`);
|
|
11767
|
+
log.blank();
|
|
11735
11768
|
}
|
|
11736
|
-
log.blank();
|
|
11737
|
-
log.info("Project files (contracts/, specs/, tests/, ci/) were not changed.");
|
|
11738
|
-
log.ok("Update complete.");
|
|
11739
|
-
log.info(`Backup saved to: ${backupRoot}`);
|
|
11740
|
-
log.blank();
|
|
11741
11769
|
}
|
|
11742
11770
|
|
|
11743
11771
|
// src/commands/new-change.ts
|
|
@@ -12657,7 +12685,7 @@ program.command("init").description(
|
|
|
12657
12685
|
provider: opts.provider
|
|
12658
12686
|
})
|
|
12659
12687
|
);
|
|
12660
|
-
program.command("update").description("Update provider assets for the current project (does not overwrite project guidance files)").option("--yes", "Apply changes (default is dry-run)", false).option("--provider <provider>", "Provider adapter to update: auto, claude, codex, or both", "auto").action((opts) => update({ yes: opts.yes, provider: opts.provider }));
|
|
12688
|
+
program.command("update").description("Update provider assets for the current project (does not overwrite project guidance files)").option("--yes", "Apply changes (default is dry-run)", false).option("--provider <provider>", "Provider adapter to update: auto, claude, codex, or both", "auto").option("--postinstall", "Internal: invoked by npm postinstall; no-op if cdd has not been init-ed", false).action((opts) => update({ yes: opts.yes, provider: opts.provider, postinstall: opts.postinstall }));
|
|
12661
12689
|
program.command("doctor").description("Inspect cdd-kit repo health, provider guidance, and context index freshness").option("--strict", "Treat warnings as errors", false).option("--json", "Print a machine-readable health report", false).option("--provider <provider>", "Provider adapter to inspect: auto, claude, codex, or both", "auto").option("--fix", "Auto-resolve safe warnings (stale context indexes, missing role bindings)", false).action(async (opts) => {
|
|
12662
12690
|
const { doctor: doctor2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
|
|
12663
12691
|
await doctor2({ strict: opts.strict, json: opts.json, provider: opts.provider, fix: opts.fix });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "contract-driven-delivery",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Contract-driven delivery kit for AI coding agents with deterministic context indexes, manifest-backed read-scope governance, and orchestrated contracts-first delivery.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"contract-driven",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"build": "node build.js",
|
|
41
41
|
"test": "vitest run",
|
|
42
42
|
"test:watch": "vitest",
|
|
43
|
-
"prepublishOnly": "node build.js && vitest run"
|
|
43
|
+
"prepublishOnly": "node build.js && vitest run",
|
|
44
|
+
"postinstall": "node bin/postinstall.js"
|
|
44
45
|
},
|
|
45
46
|
"engines": {
|
|
46
47
|
"node": ">=18.0.0"
|