@savvy-web/silk 2.2.3 → 2.3.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.
- package/changesets-changelog.cjs +67 -5
- package/changesets-changelog.d.cts +19 -0
- package/changesets-changelog.d.ts +19 -0
- package/changesets-changelog.js +67 -5
- package/changesets-markdownlint.cjs +67 -5
- package/changesets-markdownlint.d.cts +19 -0
- package/changesets-markdownlint.d.ts +19 -0
- package/changesets-markdownlint.js +67 -5
- package/package.json +4 -4
- package/tsconfig/node/dist/tsconfig.tsbuildinfo +1 -1
package/changesets-changelog.cjs
CHANGED
|
@@ -380,7 +380,8 @@ const ChangesetConfigLive = effect.Layer.effect(ChangesetConfig, effect.Effect.g
|
|
|
380
380
|
fixed: (root) => read(root).pipe(effect.Effect.map(effect.Option.match({
|
|
381
381
|
onNone: () => [],
|
|
382
382
|
onSome: (cfg) => cfg.fixed ?? []
|
|
383
|
-
})))
|
|
383
|
+
}))),
|
|
384
|
+
refresh: () => effect.Effect.sync(() => cache.clear())
|
|
384
385
|
};
|
|
385
386
|
}));
|
|
386
387
|
//#endregion
|
|
@@ -38513,9 +38514,14 @@ function makeShape$3(reader, discovery, fs) {
|
|
|
38513
38514
|
const inspected = yield* inspect(cwd);
|
|
38514
38515
|
return paths.map((p) => classifyOne(inspected, p));
|
|
38515
38516
|
});
|
|
38517
|
+
const refresh = () => effect.Effect.gen(function* () {
|
|
38518
|
+
cache.clear();
|
|
38519
|
+
yield* discovery.refresh();
|
|
38520
|
+
});
|
|
38516
38521
|
return {
|
|
38517
38522
|
inspect,
|
|
38518
|
-
classify
|
|
38523
|
+
classify,
|
|
38524
|
+
refresh
|
|
38519
38525
|
};
|
|
38520
38526
|
}
|
|
38521
38527
|
/**
|
|
@@ -38585,7 +38591,8 @@ const ConfigInspectorLive = effect.Layer.effect(ConfigInspector, effect.Effect.g
|
|
|
38585
38591
|
function makeConfigInspectorTest(fixed) {
|
|
38586
38592
|
return effect.Layer.succeed(ConfigInspector, {
|
|
38587
38593
|
inspect: () => effect.Effect.succeed(fixed),
|
|
38588
|
-
classify: (_cwd, paths) => effect.Effect.succeed(paths.map((p) => classifyOne(fixed, p)))
|
|
38594
|
+
classify: (_cwd, paths) => effect.Effect.succeed(paths.map((p) => classifyOne(fixed, p))),
|
|
38595
|
+
refresh: () => effect.Effect.void
|
|
38589
38596
|
});
|
|
38590
38597
|
}
|
|
38591
38598
|
//#endregion
|
|
@@ -39099,6 +39106,48 @@ function gitMergeBase(cwd, base) {
|
|
|
39099
39106
|
}
|
|
39100
39107
|
});
|
|
39101
39108
|
}
|
|
39109
|
+
/**
|
|
39110
|
+
* List the basenames of `.changeset/*.md` files tracked at `ref` (e.g. the
|
|
39111
|
+
* merge base), via `git ls-tree -r --name-only`. Used by `DepsRegen.plan()`
|
|
39112
|
+
* to protect changesets authored by already-merged PRs from being deleted by
|
|
39113
|
+
* an unrelated branch's regen run (#258).
|
|
39114
|
+
*
|
|
39115
|
+
* @remarks
|
|
39116
|
+
* Deliberately tolerant, unlike {@link gitMergeBase}: `cwd` may not be a git
|
|
39117
|
+
* repository at all (many `DepsRegen` unit tests pass synthetic refs like
|
|
39118
|
+
* `"BEFORE"`/`"AFTER"` against a bare tmpdir), and an unresolvable ref is a
|
|
39119
|
+
* plausible caller mistake rather than a fatal condition. Either failure mode
|
|
39120
|
+
* resolves to an empty set — "nothing protected" — rather than propagating a
|
|
39121
|
+
* {@link GitError}, so a missing/invalid git context degrades the
|
|
39122
|
+
* authorship filter to a no-op instead of blocking the whole plan.
|
|
39123
|
+
*
|
|
39124
|
+
* @internal
|
|
39125
|
+
*/
|
|
39126
|
+
function gitListChangesetFilesAtRef(cwd, ref) {
|
|
39127
|
+
return effect.Effect.sync(() => {
|
|
39128
|
+
try {
|
|
39129
|
+
const out = (0, node_child_process.execFileSync)("git", [
|
|
39130
|
+
"ls-tree",
|
|
39131
|
+
"-r",
|
|
39132
|
+
"--name-only",
|
|
39133
|
+
ref,
|
|
39134
|
+
"--",
|
|
39135
|
+
".changeset"
|
|
39136
|
+
], {
|
|
39137
|
+
cwd,
|
|
39138
|
+
encoding: "utf8",
|
|
39139
|
+
stdio: [
|
|
39140
|
+
"ignore",
|
|
39141
|
+
"pipe",
|
|
39142
|
+
"pipe"
|
|
39143
|
+
]
|
|
39144
|
+
});
|
|
39145
|
+
return new Set(out.split(/\r?\n/).filter((line) => line.trim().length > 0).map((path) => (0, node_path.basename)(path)));
|
|
39146
|
+
} catch {
|
|
39147
|
+
return /* @__PURE__ */ new Set();
|
|
39148
|
+
}
|
|
39149
|
+
});
|
|
39150
|
+
}
|
|
39102
39151
|
//#endregion
|
|
39103
39152
|
//#region ../silk-effects/dist/dev/pkg/changesets/utils/publishability.js
|
|
39104
39153
|
/**
|
|
@@ -39163,6 +39212,15 @@ function listPublishablePackageNames(packages, root) {
|
|
|
39163
39212
|
* first, then deleting the stale pure-dependency ones (so an interrupted
|
|
39164
39213
|
* run loses nothing and is safely re-runnable).
|
|
39165
39214
|
*
|
|
39215
|
+
* A pure dependency changeset is only ever a delete candidate when BOTH:
|
|
39216
|
+
* its package is in scope AND actually produced a fresh diff this run
|
|
39217
|
+
* (present in {@link RegenPlan.toWrite}), and the file was authored on
|
|
39218
|
+
* this branch rather than already committed at the merge-base ref. Either
|
|
39219
|
+
* gap silently destroyed a still-relevant release note before this was
|
|
39220
|
+
* fixed (#258) — a devDependency-only diff drops all its rows and was
|
|
39221
|
+
* never rewritten, and a changeset an earlier, already-merged PR
|
|
39222
|
+
* committed was swept away by an unrelated branch's regen run.
|
|
39223
|
+
*
|
|
39166
39224
|
* This is the single source of truth for regen/detect: the CLI commands
|
|
39167
39225
|
* and MCP tools are thin adapters over this service.
|
|
39168
39226
|
*
|
|
@@ -39382,7 +39440,8 @@ function makeShape$1(pit, inspector, discovery, detector, config, fs) {
|
|
|
39382
39440
|
const plan = (options) => effect.Effect.gen(function* () {
|
|
39383
39441
|
const resolvedCwd = (0, node_path.resolve)(options.cwd);
|
|
39384
39442
|
const changesetDir = (0, node_path.join)(resolvedCwd, ".changeset");
|
|
39385
|
-
yield*
|
|
39443
|
+
yield* inspector.refresh();
|
|
39444
|
+
yield* config.refresh();
|
|
39386
39445
|
let fromRef = options.from;
|
|
39387
39446
|
if (!fromRef) {
|
|
39388
39447
|
let baseBranch = options.base;
|
|
@@ -39419,7 +39478,10 @@ function makeShape$1(pit, inspector, discovery, detector, config, fs) {
|
|
|
39419
39478
|
}
|
|
39420
39479
|
const existingPure = yield* findPureDependencyChangesets(fs, changesetDir);
|
|
39421
39480
|
const skippedMixed = yield* findMixedDependencyChangesets(fs, changesetDir);
|
|
39422
|
-
const
|
|
39481
|
+
const rewrittenPackages = new Set(resolved.map((d) => d.package));
|
|
39482
|
+
const atMergeBase = yield* gitListChangesetFilesAtRef(resolvedCwd, fromRef);
|
|
39483
|
+
const authoredOnBranch = (file) => !atMergeBase.has((0, node_path.basename)(file));
|
|
39484
|
+
const toDelete = existingPure.filter((p) => inScopeFor(p.package) && rewrittenPackages.has(p.package) && authoredOnBranch(p.file));
|
|
39423
39485
|
const chosenFilenames = /* @__PURE__ */ new Set();
|
|
39424
39486
|
const toWrite = [];
|
|
39425
39487
|
for (const diff of resolved) {
|
|
@@ -7333,6 +7333,17 @@ interface ConfigInspectorShape {
|
|
|
7333
7333
|
* input path, in the same order
|
|
7334
7334
|
*/
|
|
7335
7335
|
readonly classify: (cwd: string, paths: ReadonlyArray<string>) => Effect.Effect<ReadonlyArray<Classification>, ConfigurationError>;
|
|
7336
|
+
/**
|
|
7337
|
+
* Drop the cached {@link InspectedConfig} for every previously-inspected
|
|
7338
|
+
* root, and refresh the underlying `WorkspaceDiscovery` snapshot. Callers
|
|
7339
|
+
* that hold this service across multiple logical operations in a single
|
|
7340
|
+
* process (e.g. a long-lived MCP server) must call this before an
|
|
7341
|
+
* operation that needs to observe on-disk edits made since the last
|
|
7342
|
+
* `inspect`/`classify` call — the cache never expires on its own.
|
|
7343
|
+
*
|
|
7344
|
+
* @returns An Effect that clears the cache and succeeds with `void`.
|
|
7345
|
+
*/
|
|
7346
|
+
readonly refresh: () => Effect.Effect<void>;
|
|
7336
7347
|
}
|
|
7337
7348
|
/**
|
|
7338
7349
|
* Base class for {@link ConfigInspector}.
|
|
@@ -8028,6 +8039,14 @@ declare const ChangesetConfig_base: Context.TagClass<ChangesetConfig, "@savvy-we
|
|
|
8028
8039
|
readonly ignorePatterns: (root: string) => Effect.Effect<ReadonlyArray<string>>;
|
|
8029
8040
|
readonly isIgnored: (name: string, root: string) => Effect.Effect<boolean>;
|
|
8030
8041
|
readonly fixed: (root: string) => Effect.Effect<ReadonlyArray<ReadonlyArray<string>>>;
|
|
8042
|
+
/**
|
|
8043
|
+
* Drop the cached read for every previously-read root. Callers that hold
|
|
8044
|
+
* this service across multiple logical operations in a single process
|
|
8045
|
+
* (e.g. a long-lived MCP server) must call this before an operation that
|
|
8046
|
+
* needs to observe an on-disk edit made since the last accessor call —
|
|
8047
|
+
* the cache never expires on its own.
|
|
8048
|
+
*/
|
|
8049
|
+
readonly refresh: () => Effect.Effect<void>;
|
|
8031
8050
|
}>;
|
|
8032
8051
|
/**
|
|
8033
8052
|
* Accessor service over a workspace root's `.changeset/config.json`.
|
|
@@ -7333,6 +7333,17 @@ interface ConfigInspectorShape {
|
|
|
7333
7333
|
* input path, in the same order
|
|
7334
7334
|
*/
|
|
7335
7335
|
readonly classify: (cwd: string, paths: ReadonlyArray<string>) => Effect.Effect<ReadonlyArray<Classification>, ConfigurationError>;
|
|
7336
|
+
/**
|
|
7337
|
+
* Drop the cached {@link InspectedConfig} for every previously-inspected
|
|
7338
|
+
* root, and refresh the underlying `WorkspaceDiscovery` snapshot. Callers
|
|
7339
|
+
* that hold this service across multiple logical operations in a single
|
|
7340
|
+
* process (e.g. a long-lived MCP server) must call this before an
|
|
7341
|
+
* operation that needs to observe on-disk edits made since the last
|
|
7342
|
+
* `inspect`/`classify` call — the cache never expires on its own.
|
|
7343
|
+
*
|
|
7344
|
+
* @returns An Effect that clears the cache and succeeds with `void`.
|
|
7345
|
+
*/
|
|
7346
|
+
readonly refresh: () => Effect.Effect<void>;
|
|
7336
7347
|
}
|
|
7337
7348
|
/**
|
|
7338
7349
|
* Base class for {@link ConfigInspector}.
|
|
@@ -8028,6 +8039,14 @@ declare const ChangesetConfig_base: Context.TagClass<ChangesetConfig, "@savvy-we
|
|
|
8028
8039
|
readonly ignorePatterns: (root: string) => Effect.Effect<ReadonlyArray<string>>;
|
|
8029
8040
|
readonly isIgnored: (name: string, root: string) => Effect.Effect<boolean>;
|
|
8030
8041
|
readonly fixed: (root: string) => Effect.Effect<ReadonlyArray<ReadonlyArray<string>>>;
|
|
8042
|
+
/**
|
|
8043
|
+
* Drop the cached read for every previously-read root. Callers that hold
|
|
8044
|
+
* this service across multiple logical operations in a single process
|
|
8045
|
+
* (e.g. a long-lived MCP server) must call this before an operation that
|
|
8046
|
+
* needs to observe an on-disk edit made since the last accessor call —
|
|
8047
|
+
* the cache never expires on its own.
|
|
8048
|
+
*/
|
|
8049
|
+
readonly refresh: () => Effect.Effect<void>;
|
|
8031
8050
|
}>;
|
|
8032
8051
|
/**
|
|
8033
8052
|
* Accessor service over a workspace root's `.changeset/config.json`.
|
package/changesets-changelog.js
CHANGED
|
@@ -394,7 +394,8 @@ const ChangesetConfigLive = Layer.effect(ChangesetConfig, Effect.gen(function* (
|
|
|
394
394
|
fixed: (root) => read(root).pipe(Effect.map(Option.match({
|
|
395
395
|
onNone: () => [],
|
|
396
396
|
onSome: (cfg) => cfg.fixed ?? []
|
|
397
|
-
})))
|
|
397
|
+
}))),
|
|
398
|
+
refresh: () => Effect.sync(() => cache.clear())
|
|
398
399
|
};
|
|
399
400
|
}));
|
|
400
401
|
|
|
@@ -38958,9 +38959,14 @@ function makeShape$3(reader, discovery, fs) {
|
|
|
38958
38959
|
const inspected = yield* inspect(cwd);
|
|
38959
38960
|
return paths.map((p) => classifyOne(inspected, p));
|
|
38960
38961
|
});
|
|
38962
|
+
const refresh = () => Effect.gen(function* () {
|
|
38963
|
+
cache.clear();
|
|
38964
|
+
yield* discovery.refresh();
|
|
38965
|
+
});
|
|
38961
38966
|
return {
|
|
38962
38967
|
inspect,
|
|
38963
|
-
classify
|
|
38968
|
+
classify,
|
|
38969
|
+
refresh
|
|
38964
38970
|
};
|
|
38965
38971
|
}
|
|
38966
38972
|
/**
|
|
@@ -39030,7 +39036,8 @@ const ConfigInspectorLive = Layer.effect(ConfigInspector, Effect.gen(function* (
|
|
|
39030
39036
|
function makeConfigInspectorTest(fixed) {
|
|
39031
39037
|
return Layer.succeed(ConfigInspector, {
|
|
39032
39038
|
inspect: () => Effect.succeed(fixed),
|
|
39033
|
-
classify: (_cwd, paths) => Effect.succeed(paths.map((p) => classifyOne(fixed, p)))
|
|
39039
|
+
classify: (_cwd, paths) => Effect.succeed(paths.map((p) => classifyOne(fixed, p))),
|
|
39040
|
+
refresh: () => Effect.void
|
|
39034
39041
|
});
|
|
39035
39042
|
}
|
|
39036
39043
|
|
|
@@ -39548,6 +39555,48 @@ function gitMergeBase(cwd, base) {
|
|
|
39548
39555
|
}
|
|
39549
39556
|
});
|
|
39550
39557
|
}
|
|
39558
|
+
/**
|
|
39559
|
+
* List the basenames of `.changeset/*.md` files tracked at `ref` (e.g. the
|
|
39560
|
+
* merge base), via `git ls-tree -r --name-only`. Used by `DepsRegen.plan()`
|
|
39561
|
+
* to protect changesets authored by already-merged PRs from being deleted by
|
|
39562
|
+
* an unrelated branch's regen run (#258).
|
|
39563
|
+
*
|
|
39564
|
+
* @remarks
|
|
39565
|
+
* Deliberately tolerant, unlike {@link gitMergeBase}: `cwd` may not be a git
|
|
39566
|
+
* repository at all (many `DepsRegen` unit tests pass synthetic refs like
|
|
39567
|
+
* `"BEFORE"`/`"AFTER"` against a bare tmpdir), and an unresolvable ref is a
|
|
39568
|
+
* plausible caller mistake rather than a fatal condition. Either failure mode
|
|
39569
|
+
* resolves to an empty set — "nothing protected" — rather than propagating a
|
|
39570
|
+
* {@link GitError}, so a missing/invalid git context degrades the
|
|
39571
|
+
* authorship filter to a no-op instead of blocking the whole plan.
|
|
39572
|
+
*
|
|
39573
|
+
* @internal
|
|
39574
|
+
*/
|
|
39575
|
+
function gitListChangesetFilesAtRef(cwd, ref) {
|
|
39576
|
+
return Effect.sync(() => {
|
|
39577
|
+
try {
|
|
39578
|
+
const out = execFileSync("git", [
|
|
39579
|
+
"ls-tree",
|
|
39580
|
+
"-r",
|
|
39581
|
+
"--name-only",
|
|
39582
|
+
ref,
|
|
39583
|
+
"--",
|
|
39584
|
+
".changeset"
|
|
39585
|
+
], {
|
|
39586
|
+
cwd,
|
|
39587
|
+
encoding: "utf8",
|
|
39588
|
+
stdio: [
|
|
39589
|
+
"ignore",
|
|
39590
|
+
"pipe",
|
|
39591
|
+
"pipe"
|
|
39592
|
+
]
|
|
39593
|
+
});
|
|
39594
|
+
return new Set(out.split(/\r?\n/).filter((line) => line.trim().length > 0).map((path) => basename(path)));
|
|
39595
|
+
} catch {
|
|
39596
|
+
return /* @__PURE__ */ new Set();
|
|
39597
|
+
}
|
|
39598
|
+
});
|
|
39599
|
+
}
|
|
39551
39600
|
|
|
39552
39601
|
//#endregion
|
|
39553
39602
|
//#region ../silk-effects/dist/dev/pkg/changesets/utils/publishability.js
|
|
@@ -39614,6 +39663,15 @@ function listPublishablePackageNames(packages, root) {
|
|
|
39614
39663
|
* first, then deleting the stale pure-dependency ones (so an interrupted
|
|
39615
39664
|
* run loses nothing and is safely re-runnable).
|
|
39616
39665
|
*
|
|
39666
|
+
* A pure dependency changeset is only ever a delete candidate when BOTH:
|
|
39667
|
+
* its package is in scope AND actually produced a fresh diff this run
|
|
39668
|
+
* (present in {@link RegenPlan.toWrite}), and the file was authored on
|
|
39669
|
+
* this branch rather than already committed at the merge-base ref. Either
|
|
39670
|
+
* gap silently destroyed a still-relevant release note before this was
|
|
39671
|
+
* fixed (#258) — a devDependency-only diff drops all its rows and was
|
|
39672
|
+
* never rewritten, and a changeset an earlier, already-merged PR
|
|
39673
|
+
* committed was swept away by an unrelated branch's regen run.
|
|
39674
|
+
*
|
|
39617
39675
|
* This is the single source of truth for regen/detect: the CLI commands
|
|
39618
39676
|
* and MCP tools are thin adapters over this service.
|
|
39619
39677
|
*
|
|
@@ -39833,7 +39891,8 @@ function makeShape$1(pit, inspector, discovery, detector, config, fs) {
|
|
|
39833
39891
|
const plan = (options) => Effect.gen(function* () {
|
|
39834
39892
|
const resolvedCwd = resolve(options.cwd);
|
|
39835
39893
|
const changesetDir = join(resolvedCwd, ".changeset");
|
|
39836
|
-
yield*
|
|
39894
|
+
yield* inspector.refresh();
|
|
39895
|
+
yield* config.refresh();
|
|
39837
39896
|
let fromRef = options.from;
|
|
39838
39897
|
if (!fromRef) {
|
|
39839
39898
|
let baseBranch = options.base;
|
|
@@ -39870,7 +39929,10 @@ function makeShape$1(pit, inspector, discovery, detector, config, fs) {
|
|
|
39870
39929
|
}
|
|
39871
39930
|
const existingPure = yield* findPureDependencyChangesets(fs, changesetDir);
|
|
39872
39931
|
const skippedMixed = yield* findMixedDependencyChangesets(fs, changesetDir);
|
|
39873
|
-
const
|
|
39932
|
+
const rewrittenPackages = new Set(resolved.map((d) => d.package));
|
|
39933
|
+
const atMergeBase = yield* gitListChangesetFilesAtRef(resolvedCwd, fromRef);
|
|
39934
|
+
const authoredOnBranch = (file) => !atMergeBase.has(basename(file));
|
|
39935
|
+
const toDelete = existingPure.filter((p) => inScopeFor(p.package) && rewrittenPackages.has(p.package) && authoredOnBranch(p.file));
|
|
39874
39936
|
const chosenFilenames = /* @__PURE__ */ new Set();
|
|
39875
39937
|
const toWrite = [];
|
|
39876
39938
|
for (const diff of resolved) {
|
|
@@ -384,7 +384,8 @@ const ChangesetConfigLive = effect.Layer.effect(ChangesetConfig, effect.Effect.g
|
|
|
384
384
|
fixed: (root) => read(root).pipe(effect.Effect.map(effect.Option.match({
|
|
385
385
|
onNone: () => [],
|
|
386
386
|
onSome: (cfg) => cfg.fixed ?? []
|
|
387
|
-
})))
|
|
387
|
+
}))),
|
|
388
|
+
refresh: () => effect.Effect.sync(() => cache.clear())
|
|
388
389
|
};
|
|
389
390
|
}));
|
|
390
391
|
//#endregion
|
|
@@ -38517,9 +38518,14 @@ function makeShape$3(reader, discovery, fs) {
|
|
|
38517
38518
|
const inspected = yield* inspect(cwd);
|
|
38518
38519
|
return paths.map((p) => classifyOne(inspected, p));
|
|
38519
38520
|
});
|
|
38521
|
+
const refresh = () => effect.Effect.gen(function* () {
|
|
38522
|
+
cache.clear();
|
|
38523
|
+
yield* discovery.refresh();
|
|
38524
|
+
});
|
|
38520
38525
|
return {
|
|
38521
38526
|
inspect,
|
|
38522
|
-
classify
|
|
38527
|
+
classify,
|
|
38528
|
+
refresh
|
|
38523
38529
|
};
|
|
38524
38530
|
}
|
|
38525
38531
|
/**
|
|
@@ -38589,7 +38595,8 @@ const ConfigInspectorLive = effect.Layer.effect(ConfigInspector, effect.Effect.g
|
|
|
38589
38595
|
function makeConfigInspectorTest(fixed) {
|
|
38590
38596
|
return effect.Layer.succeed(ConfigInspector, {
|
|
38591
38597
|
inspect: () => effect.Effect.succeed(fixed),
|
|
38592
|
-
classify: (_cwd, paths) => effect.Effect.succeed(paths.map((p) => classifyOne(fixed, p)))
|
|
38598
|
+
classify: (_cwd, paths) => effect.Effect.succeed(paths.map((p) => classifyOne(fixed, p))),
|
|
38599
|
+
refresh: () => effect.Effect.void
|
|
38593
38600
|
});
|
|
38594
38601
|
}
|
|
38595
38602
|
//#endregion
|
|
@@ -39103,6 +39110,48 @@ function gitMergeBase(cwd, base) {
|
|
|
39103
39110
|
}
|
|
39104
39111
|
});
|
|
39105
39112
|
}
|
|
39113
|
+
/**
|
|
39114
|
+
* List the basenames of `.changeset/*.md` files tracked at `ref` (e.g. the
|
|
39115
|
+
* merge base), via `git ls-tree -r --name-only`. Used by `DepsRegen.plan()`
|
|
39116
|
+
* to protect changesets authored by already-merged PRs from being deleted by
|
|
39117
|
+
* an unrelated branch's regen run (#258).
|
|
39118
|
+
*
|
|
39119
|
+
* @remarks
|
|
39120
|
+
* Deliberately tolerant, unlike {@link gitMergeBase}: `cwd` may not be a git
|
|
39121
|
+
* repository at all (many `DepsRegen` unit tests pass synthetic refs like
|
|
39122
|
+
* `"BEFORE"`/`"AFTER"` against a bare tmpdir), and an unresolvable ref is a
|
|
39123
|
+
* plausible caller mistake rather than a fatal condition. Either failure mode
|
|
39124
|
+
* resolves to an empty set — "nothing protected" — rather than propagating a
|
|
39125
|
+
* {@link GitError}, so a missing/invalid git context degrades the
|
|
39126
|
+
* authorship filter to a no-op instead of blocking the whole plan.
|
|
39127
|
+
*
|
|
39128
|
+
* @internal
|
|
39129
|
+
*/
|
|
39130
|
+
function gitListChangesetFilesAtRef(cwd, ref) {
|
|
39131
|
+
return effect.Effect.sync(() => {
|
|
39132
|
+
try {
|
|
39133
|
+
const out = (0, node_child_process.execFileSync)("git", [
|
|
39134
|
+
"ls-tree",
|
|
39135
|
+
"-r",
|
|
39136
|
+
"--name-only",
|
|
39137
|
+
ref,
|
|
39138
|
+
"--",
|
|
39139
|
+
".changeset"
|
|
39140
|
+
], {
|
|
39141
|
+
cwd,
|
|
39142
|
+
encoding: "utf8",
|
|
39143
|
+
stdio: [
|
|
39144
|
+
"ignore",
|
|
39145
|
+
"pipe",
|
|
39146
|
+
"pipe"
|
|
39147
|
+
]
|
|
39148
|
+
});
|
|
39149
|
+
return new Set(out.split(/\r?\n/).filter((line) => line.trim().length > 0).map((path) => (0, node_path.basename)(path)));
|
|
39150
|
+
} catch {
|
|
39151
|
+
return /* @__PURE__ */ new Set();
|
|
39152
|
+
}
|
|
39153
|
+
});
|
|
39154
|
+
}
|
|
39106
39155
|
//#endregion
|
|
39107
39156
|
//#region ../silk-effects/dist/dev/pkg/changesets/utils/publishability.js
|
|
39108
39157
|
/**
|
|
@@ -39167,6 +39216,15 @@ function listPublishablePackageNames(packages, root) {
|
|
|
39167
39216
|
* first, then deleting the stale pure-dependency ones (so an interrupted
|
|
39168
39217
|
* run loses nothing and is safely re-runnable).
|
|
39169
39218
|
*
|
|
39219
|
+
* A pure dependency changeset is only ever a delete candidate when BOTH:
|
|
39220
|
+
* its package is in scope AND actually produced a fresh diff this run
|
|
39221
|
+
* (present in {@link RegenPlan.toWrite}), and the file was authored on
|
|
39222
|
+
* this branch rather than already committed at the merge-base ref. Either
|
|
39223
|
+
* gap silently destroyed a still-relevant release note before this was
|
|
39224
|
+
* fixed (#258) — a devDependency-only diff drops all its rows and was
|
|
39225
|
+
* never rewritten, and a changeset an earlier, already-merged PR
|
|
39226
|
+
* committed was swept away by an unrelated branch's regen run.
|
|
39227
|
+
*
|
|
39170
39228
|
* This is the single source of truth for regen/detect: the CLI commands
|
|
39171
39229
|
* and MCP tools are thin adapters over this service.
|
|
39172
39230
|
*
|
|
@@ -39386,7 +39444,8 @@ function makeShape$1(pit, inspector, discovery, detector, config, fs) {
|
|
|
39386
39444
|
const plan = (options) => effect.Effect.gen(function* () {
|
|
39387
39445
|
const resolvedCwd = (0, node_path.resolve)(options.cwd);
|
|
39388
39446
|
const changesetDir = (0, node_path.join)(resolvedCwd, ".changeset");
|
|
39389
|
-
yield*
|
|
39447
|
+
yield* inspector.refresh();
|
|
39448
|
+
yield* config.refresh();
|
|
39390
39449
|
let fromRef = options.from;
|
|
39391
39450
|
if (!fromRef) {
|
|
39392
39451
|
let baseBranch = options.base;
|
|
@@ -39423,7 +39482,10 @@ function makeShape$1(pit, inspector, discovery, detector, config, fs) {
|
|
|
39423
39482
|
}
|
|
39424
39483
|
const existingPure = yield* findPureDependencyChangesets(fs, changesetDir);
|
|
39425
39484
|
const skippedMixed = yield* findMixedDependencyChangesets(fs, changesetDir);
|
|
39426
|
-
const
|
|
39485
|
+
const rewrittenPackages = new Set(resolved.map((d) => d.package));
|
|
39486
|
+
const atMergeBase = yield* gitListChangesetFilesAtRef(resolvedCwd, fromRef);
|
|
39487
|
+
const authoredOnBranch = (file) => !atMergeBase.has((0, node_path.basename)(file));
|
|
39488
|
+
const toDelete = existingPure.filter((p) => inScopeFor(p.package) && rewrittenPackages.has(p.package) && authoredOnBranch(p.file));
|
|
39427
39489
|
const chosenFilenames = /* @__PURE__ */ new Set();
|
|
39428
39490
|
const toWrite = [];
|
|
39429
39491
|
for (const diff of resolved) {
|
|
@@ -7333,6 +7333,17 @@ interface ConfigInspectorShape {
|
|
|
7333
7333
|
* input path, in the same order
|
|
7334
7334
|
*/
|
|
7335
7335
|
readonly classify: (cwd: string, paths: ReadonlyArray<string>) => Effect.Effect<ReadonlyArray<Classification>, ConfigurationError>;
|
|
7336
|
+
/**
|
|
7337
|
+
* Drop the cached {@link InspectedConfig} for every previously-inspected
|
|
7338
|
+
* root, and refresh the underlying `WorkspaceDiscovery` snapshot. Callers
|
|
7339
|
+
* that hold this service across multiple logical operations in a single
|
|
7340
|
+
* process (e.g. a long-lived MCP server) must call this before an
|
|
7341
|
+
* operation that needs to observe on-disk edits made since the last
|
|
7342
|
+
* `inspect`/`classify` call — the cache never expires on its own.
|
|
7343
|
+
*
|
|
7344
|
+
* @returns An Effect that clears the cache and succeeds with `void`.
|
|
7345
|
+
*/
|
|
7346
|
+
readonly refresh: () => Effect.Effect<void>;
|
|
7336
7347
|
}
|
|
7337
7348
|
/**
|
|
7338
7349
|
* Base class for {@link ConfigInspector}.
|
|
@@ -8028,6 +8039,14 @@ declare const ChangesetConfig_base: Context.TagClass<ChangesetConfig, "@savvy-we
|
|
|
8028
8039
|
readonly ignorePatterns: (root: string) => Effect.Effect<ReadonlyArray<string>>;
|
|
8029
8040
|
readonly isIgnored: (name: string, root: string) => Effect.Effect<boolean>;
|
|
8030
8041
|
readonly fixed: (root: string) => Effect.Effect<ReadonlyArray<ReadonlyArray<string>>>;
|
|
8042
|
+
/**
|
|
8043
|
+
* Drop the cached read for every previously-read root. Callers that hold
|
|
8044
|
+
* this service across multiple logical operations in a single process
|
|
8045
|
+
* (e.g. a long-lived MCP server) must call this before an operation that
|
|
8046
|
+
* needs to observe an on-disk edit made since the last accessor call —
|
|
8047
|
+
* the cache never expires on its own.
|
|
8048
|
+
*/
|
|
8049
|
+
readonly refresh: () => Effect.Effect<void>;
|
|
8031
8050
|
}>;
|
|
8032
8051
|
/**
|
|
8033
8052
|
* Accessor service over a workspace root's `.changeset/config.json`.
|
|
@@ -7333,6 +7333,17 @@ interface ConfigInspectorShape {
|
|
|
7333
7333
|
* input path, in the same order
|
|
7334
7334
|
*/
|
|
7335
7335
|
readonly classify: (cwd: string, paths: ReadonlyArray<string>) => Effect.Effect<ReadonlyArray<Classification>, ConfigurationError>;
|
|
7336
|
+
/**
|
|
7337
|
+
* Drop the cached {@link InspectedConfig} for every previously-inspected
|
|
7338
|
+
* root, and refresh the underlying `WorkspaceDiscovery` snapshot. Callers
|
|
7339
|
+
* that hold this service across multiple logical operations in a single
|
|
7340
|
+
* process (e.g. a long-lived MCP server) must call this before an
|
|
7341
|
+
* operation that needs to observe on-disk edits made since the last
|
|
7342
|
+
* `inspect`/`classify` call — the cache never expires on its own.
|
|
7343
|
+
*
|
|
7344
|
+
* @returns An Effect that clears the cache and succeeds with `void`.
|
|
7345
|
+
*/
|
|
7346
|
+
readonly refresh: () => Effect.Effect<void>;
|
|
7336
7347
|
}
|
|
7337
7348
|
/**
|
|
7338
7349
|
* Base class for {@link ConfigInspector}.
|
|
@@ -8028,6 +8039,14 @@ declare const ChangesetConfig_base: Context.TagClass<ChangesetConfig, "@savvy-we
|
|
|
8028
8039
|
readonly ignorePatterns: (root: string) => Effect.Effect<ReadonlyArray<string>>;
|
|
8029
8040
|
readonly isIgnored: (name: string, root: string) => Effect.Effect<boolean>;
|
|
8030
8041
|
readonly fixed: (root: string) => Effect.Effect<ReadonlyArray<ReadonlyArray<string>>>;
|
|
8042
|
+
/**
|
|
8043
|
+
* Drop the cached read for every previously-read root. Callers that hold
|
|
8044
|
+
* this service across multiple logical operations in a single process
|
|
8045
|
+
* (e.g. a long-lived MCP server) must call this before an operation that
|
|
8046
|
+
* needs to observe an on-disk edit made since the last accessor call —
|
|
8047
|
+
* the cache never expires on its own.
|
|
8048
|
+
*/
|
|
8049
|
+
readonly refresh: () => Effect.Effect<void>;
|
|
8031
8050
|
}>;
|
|
8032
8051
|
/**
|
|
8033
8052
|
* Accessor service over a workspace root's `.changeset/config.json`.
|
|
@@ -394,7 +394,8 @@ const ChangesetConfigLive = Layer.effect(ChangesetConfig, Effect.gen(function* (
|
|
|
394
394
|
fixed: (root) => read(root).pipe(Effect.map(Option.match({
|
|
395
395
|
onNone: () => [],
|
|
396
396
|
onSome: (cfg) => cfg.fixed ?? []
|
|
397
|
-
})))
|
|
397
|
+
}))),
|
|
398
|
+
refresh: () => Effect.sync(() => cache.clear())
|
|
398
399
|
};
|
|
399
400
|
}));
|
|
400
401
|
|
|
@@ -38958,9 +38959,14 @@ function makeShape$3(reader, discovery, fs) {
|
|
|
38958
38959
|
const inspected = yield* inspect(cwd);
|
|
38959
38960
|
return paths.map((p) => classifyOne(inspected, p));
|
|
38960
38961
|
});
|
|
38962
|
+
const refresh = () => Effect.gen(function* () {
|
|
38963
|
+
cache.clear();
|
|
38964
|
+
yield* discovery.refresh();
|
|
38965
|
+
});
|
|
38961
38966
|
return {
|
|
38962
38967
|
inspect,
|
|
38963
|
-
classify
|
|
38968
|
+
classify,
|
|
38969
|
+
refresh
|
|
38964
38970
|
};
|
|
38965
38971
|
}
|
|
38966
38972
|
/**
|
|
@@ -39030,7 +39036,8 @@ const ConfigInspectorLive = Layer.effect(ConfigInspector, Effect.gen(function* (
|
|
|
39030
39036
|
function makeConfigInspectorTest(fixed) {
|
|
39031
39037
|
return Layer.succeed(ConfigInspector, {
|
|
39032
39038
|
inspect: () => Effect.succeed(fixed),
|
|
39033
|
-
classify: (_cwd, paths) => Effect.succeed(paths.map((p) => classifyOne(fixed, p)))
|
|
39039
|
+
classify: (_cwd, paths) => Effect.succeed(paths.map((p) => classifyOne(fixed, p))),
|
|
39040
|
+
refresh: () => Effect.void
|
|
39034
39041
|
});
|
|
39035
39042
|
}
|
|
39036
39043
|
|
|
@@ -39548,6 +39555,48 @@ function gitMergeBase(cwd, base) {
|
|
|
39548
39555
|
}
|
|
39549
39556
|
});
|
|
39550
39557
|
}
|
|
39558
|
+
/**
|
|
39559
|
+
* List the basenames of `.changeset/*.md` files tracked at `ref` (e.g. the
|
|
39560
|
+
* merge base), via `git ls-tree -r --name-only`. Used by `DepsRegen.plan()`
|
|
39561
|
+
* to protect changesets authored by already-merged PRs from being deleted by
|
|
39562
|
+
* an unrelated branch's regen run (#258).
|
|
39563
|
+
*
|
|
39564
|
+
* @remarks
|
|
39565
|
+
* Deliberately tolerant, unlike {@link gitMergeBase}: `cwd` may not be a git
|
|
39566
|
+
* repository at all (many `DepsRegen` unit tests pass synthetic refs like
|
|
39567
|
+
* `"BEFORE"`/`"AFTER"` against a bare tmpdir), and an unresolvable ref is a
|
|
39568
|
+
* plausible caller mistake rather than a fatal condition. Either failure mode
|
|
39569
|
+
* resolves to an empty set — "nothing protected" — rather than propagating a
|
|
39570
|
+
* {@link GitError}, so a missing/invalid git context degrades the
|
|
39571
|
+
* authorship filter to a no-op instead of blocking the whole plan.
|
|
39572
|
+
*
|
|
39573
|
+
* @internal
|
|
39574
|
+
*/
|
|
39575
|
+
function gitListChangesetFilesAtRef(cwd, ref) {
|
|
39576
|
+
return Effect.sync(() => {
|
|
39577
|
+
try {
|
|
39578
|
+
const out = execFileSync("git", [
|
|
39579
|
+
"ls-tree",
|
|
39580
|
+
"-r",
|
|
39581
|
+
"--name-only",
|
|
39582
|
+
ref,
|
|
39583
|
+
"--",
|
|
39584
|
+
".changeset"
|
|
39585
|
+
], {
|
|
39586
|
+
cwd,
|
|
39587
|
+
encoding: "utf8",
|
|
39588
|
+
stdio: [
|
|
39589
|
+
"ignore",
|
|
39590
|
+
"pipe",
|
|
39591
|
+
"pipe"
|
|
39592
|
+
]
|
|
39593
|
+
});
|
|
39594
|
+
return new Set(out.split(/\r?\n/).filter((line) => line.trim().length > 0).map((path) => basename(path)));
|
|
39595
|
+
} catch {
|
|
39596
|
+
return /* @__PURE__ */ new Set();
|
|
39597
|
+
}
|
|
39598
|
+
});
|
|
39599
|
+
}
|
|
39551
39600
|
|
|
39552
39601
|
//#endregion
|
|
39553
39602
|
//#region ../silk-effects/dist/dev/pkg/changesets/utils/publishability.js
|
|
@@ -39614,6 +39663,15 @@ function listPublishablePackageNames(packages, root) {
|
|
|
39614
39663
|
* first, then deleting the stale pure-dependency ones (so an interrupted
|
|
39615
39664
|
* run loses nothing and is safely re-runnable).
|
|
39616
39665
|
*
|
|
39666
|
+
* A pure dependency changeset is only ever a delete candidate when BOTH:
|
|
39667
|
+
* its package is in scope AND actually produced a fresh diff this run
|
|
39668
|
+
* (present in {@link RegenPlan.toWrite}), and the file was authored on
|
|
39669
|
+
* this branch rather than already committed at the merge-base ref. Either
|
|
39670
|
+
* gap silently destroyed a still-relevant release note before this was
|
|
39671
|
+
* fixed (#258) — a devDependency-only diff drops all its rows and was
|
|
39672
|
+
* never rewritten, and a changeset an earlier, already-merged PR
|
|
39673
|
+
* committed was swept away by an unrelated branch's regen run.
|
|
39674
|
+
*
|
|
39617
39675
|
* This is the single source of truth for regen/detect: the CLI commands
|
|
39618
39676
|
* and MCP tools are thin adapters over this service.
|
|
39619
39677
|
*
|
|
@@ -39833,7 +39891,8 @@ function makeShape$1(pit, inspector, discovery, detector, config, fs) {
|
|
|
39833
39891
|
const plan = (options) => Effect.gen(function* () {
|
|
39834
39892
|
const resolvedCwd = resolve(options.cwd);
|
|
39835
39893
|
const changesetDir = join(resolvedCwd, ".changeset");
|
|
39836
|
-
yield*
|
|
39894
|
+
yield* inspector.refresh();
|
|
39895
|
+
yield* config.refresh();
|
|
39837
39896
|
let fromRef = options.from;
|
|
39838
39897
|
if (!fromRef) {
|
|
39839
39898
|
let baseBranch = options.base;
|
|
@@ -39870,7 +39929,10 @@ function makeShape$1(pit, inspector, discovery, detector, config, fs) {
|
|
|
39870
39929
|
}
|
|
39871
39930
|
const existingPure = yield* findPureDependencyChangesets(fs, changesetDir);
|
|
39872
39931
|
const skippedMixed = yield* findMixedDependencyChangesets(fs, changesetDir);
|
|
39873
|
-
const
|
|
39932
|
+
const rewrittenPackages = new Set(resolved.map((d) => d.package));
|
|
39933
|
+
const atMergeBase = yield* gitListChangesetFilesAtRef(resolvedCwd, fromRef);
|
|
39934
|
+
const authoredOnBranch = (file) => !atMergeBase.has(basename(file));
|
|
39935
|
+
const toDelete = existingPure.filter((p) => inScopeFor(p.package) && rewrittenPackages.has(p.package) && authoredOnBranch(p.file));
|
|
39874
39936
|
const chosenFilenames = /* @__PURE__ */ new Set();
|
|
39875
39937
|
const toWrite = [];
|
|
39876
39938
|
for (const diff of resolved) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@savvy-web/silk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The single Silk Suite dev-tooling package — changeset, commitlint, lint, and biome conventions",
|
|
6
6
|
"homepage": "https://github.com/savvy-web/systems/tree/main/packages/silk",
|
|
@@ -67,9 +67,9 @@
|
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@effect/platform": "^0.96.2",
|
|
69
69
|
"@savvy-web/changelog": "0.1.1",
|
|
70
|
-
"@savvy-web/cli": "1.5.
|
|
71
|
-
"@savvy-web/mcp": "1.7.
|
|
72
|
-
"@savvy-web/silk-effects": "3.2.
|
|
70
|
+
"@savvy-web/cli": "1.5.8",
|
|
71
|
+
"@savvy-web/mcp": "1.7.4",
|
|
72
|
+
"@savvy-web/silk-effects": "3.2.3",
|
|
73
73
|
"effect": "^3.21.4",
|
|
74
74
|
"semver": "^7.8.5"
|
|
75
75
|
},
|