@savvy-web/silk-effects 10.1.0 → 10.2.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/api/linter.js +2 -3
- package/changesets/utils/markdown-emit.js +27 -2
- package/commitlint/hook/diagnostics/open-issues.js +19 -14
- package/commitlint/hook/diagnostics/package-manager.js +24 -51
- package/commitlint/index.js +2 -4
- package/index.d.ts +33 -15
- package/lint/handlers/TextFiles.js +4 -7
- package/lint/utils/Command.js +2 -2
- package/package.json +7 -7
- package/repos/index.js +3 -2
- package/repos/services/manager.js +18 -7
- package/turbo/services/TurboInspector.js +1 -1
- package/changesets/utils/strip-frontmatter.js +0 -26
package/changesets/api/linter.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseKitMarkdownBody } from "../utils/markdown-emit.js";
|
|
2
2
|
import { contentStructure } from "../rules/content-structure.js";
|
|
3
3
|
import { dependencyTableFormat } from "../rules/dependency-table-format.js";
|
|
4
4
|
import { headingHierarchy } from "../rules/heading-hierarchy.js";
|
|
5
5
|
import { requiredSections } from "../rules/required-sections.js";
|
|
6
6
|
import { uncategorizedContent } from "../rules/uncategorized-content.js";
|
|
7
|
-
import { stripFrontmatter } from "../utils/strip-frontmatter.js";
|
|
8
7
|
import { readFileSync, readdirSync } from "node:fs";
|
|
9
8
|
import { join } from "node:path";
|
|
10
9
|
|
|
@@ -141,7 +140,7 @@ var ChangesetLinter = class ChangesetLinter {
|
|
|
141
140
|
* @returns Array of {@link LintMessage} diagnostics (empty if the content is valid)
|
|
142
141
|
*/
|
|
143
142
|
static validateContent(content, filePath = "<input>") {
|
|
144
|
-
const root =
|
|
143
|
+
const root = parseKitMarkdownBody(content);
|
|
145
144
|
return RULES.flatMap((rule) => rule(root).map((finding) => ({
|
|
146
145
|
file: filePath,
|
|
147
146
|
rule: finding.rule,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Result } from "effect";
|
|
2
|
-
import { Code, Markdown, MarkdownTransform, Mdast } from "@effected/markdown";
|
|
2
|
+
import { Code, Markdown, MarkdownParseOptions, MarkdownTransform, Mdast, Root } from "@effected/markdown";
|
|
3
3
|
|
|
4
4
|
// src/changesets/utils/markdown-emit.ts
|
|
5
5
|
/**
|
|
@@ -65,6 +65,31 @@ function parseKitMarkdown(text) {
|
|
|
65
65
|
const parsed = unwrap(Markdown.parseResult(text), "markdown parse: canonical parse failed");
|
|
66
66
|
return unwrap(Mdast.fromMdastResult(Mdast.toMdast(parsed)), "markdown parse: fidelity strip failed");
|
|
67
67
|
}
|
|
68
|
+
const FRONTMATTER_CAPTURE = MarkdownParseOptions.make({ frontmatter: true });
|
|
69
|
+
/**
|
|
70
|
+
* Parse a changeset file into a kit root with its frontmatter block removed.
|
|
71
|
+
*
|
|
72
|
+
* @remarks
|
|
73
|
+
* Parses with the kit's frontmatter capture on, so a `---` block at offset 0
|
|
74
|
+
* is recognized whatever its line endings (CRLF included), then drops the
|
|
75
|
+
* `frontmatter` head node. The text is never sliced, so every remaining
|
|
76
|
+
* node's position is relative to the whole file — the lines a linter reports
|
|
77
|
+
* match the lines an editor shows. A fence pair later in the document is not
|
|
78
|
+
* frontmatter and parses as ordinary content.
|
|
79
|
+
*
|
|
80
|
+
* @param text - The raw changeset source, frontmatter included
|
|
81
|
+
* @returns The parsed kit root, without its frontmatter node
|
|
82
|
+
*
|
|
83
|
+
* @internal
|
|
84
|
+
*/
|
|
85
|
+
function parseKitMarkdownBody(text) {
|
|
86
|
+
const parsed = unwrap(Markdown.parseResult(text, FRONTMATTER_CAPTURE), "markdown parse: canonical parse failed");
|
|
87
|
+
const body = new Root({
|
|
88
|
+
children: parsed.children.filter((node) => node.type !== "frontmatter"),
|
|
89
|
+
position: parsed.position
|
|
90
|
+
});
|
|
91
|
+
return unwrap(Mdast.fromMdastResult(Mdast.toMdast(body)), "markdown parse: fidelity strip failed");
|
|
92
|
+
}
|
|
68
93
|
/**
|
|
69
94
|
* Serialize a kit root, or a single kit block node, to canonical markdown.
|
|
70
95
|
*
|
|
@@ -81,4 +106,4 @@ function emitKitMarkdown(node) {
|
|
|
81
106
|
return unwrap(Markdown.stringifyResult(ensureFencedCode(node)), "markdown emit: canonical stringify failed");
|
|
82
107
|
}
|
|
83
108
|
|
|
84
|
-
export { emitKitMarkdown, parseKitMarkdown };
|
|
109
|
+
export { emitKitMarkdown, parseKitMarkdown, parseKitMarkdownBody };
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
import { readCache, writeCache } from "./cache.js";
|
|
2
|
-
import { Effect } from "effect";
|
|
2
|
+
import { Effect, Schema } from "effect";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { Git } from "@effected/git";
|
|
5
|
-
import {
|
|
5
|
+
import { Run } from "@effected/commands";
|
|
6
|
+
import { ChildProcess } from "effect/process";
|
|
6
7
|
|
|
7
8
|
// src/commitlint/hook/diagnostics/open-issues.ts
|
|
8
9
|
/**
|
|
9
10
|
* Open-issue lookup via gh CLI, cached on disk.
|
|
10
11
|
*
|
|
11
12
|
* @remarks
|
|
12
|
-
* The `gh` invocations
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* The `gh` invocations run through `@effected/commands`' `Run`: the repo
|
|
14
|
+
* lookup is `Run.text`, the issue list is `Run.json` decoded against
|
|
15
|
+
* {@link OpenIssue}. Any failure (gh missing, not logged in, no repo, a
|
|
16
|
+
* non-zero exit, output that is not JSON or not an issue list) degrades to
|
|
17
|
+
* `null` and caches nothing, preserving the never-fails contract.
|
|
17
18
|
*
|
|
18
19
|
* @internal
|
|
19
20
|
*/
|
|
21
|
+
/** One open issue as `gh issue list --json number,title` prints it. */
|
|
22
|
+
const OpenIssue = Schema.Struct({
|
|
23
|
+
number: Schema.Number,
|
|
24
|
+
title: Schema.String
|
|
25
|
+
});
|
|
26
|
+
const OpenIssues = Schema.Array(OpenIssue);
|
|
20
27
|
const ISSUES_CACHE_TTL_SECONDS = 600;
|
|
21
28
|
/** Relative path under the project root where the open-issues cache lives. */
|
|
22
29
|
const ISSUES_CACHE_RELATIVE_PATH = ".claude/cache/issues.json";
|
|
@@ -43,17 +50,16 @@ function readOpenIssuesFromCache(cachePath, ttlSeconds = 600) {
|
|
|
43
50
|
}
|
|
44
51
|
function fetchAndCacheOpenIssues(cachePath) {
|
|
45
52
|
return Effect.gen(function* () {
|
|
46
|
-
const
|
|
47
|
-
const repo = (yield* spawner.string(ChildProcess.make("gh", [
|
|
53
|
+
const repo = yield* Run.text(ChildProcess.make("gh", [
|
|
48
54
|
"repo",
|
|
49
55
|
"view",
|
|
50
56
|
"--json",
|
|
51
57
|
"nameWithOwner",
|
|
52
58
|
"-q",
|
|
53
59
|
".nameWithOwner"
|
|
54
|
-
]))
|
|
60
|
+
]));
|
|
55
61
|
if (!repo) return null;
|
|
56
|
-
const
|
|
62
|
+
const parsed = [...yield* Run.json(ChildProcess.make("gh", [
|
|
57
63
|
"issue",
|
|
58
64
|
"list",
|
|
59
65
|
"--repo",
|
|
@@ -64,8 +70,7 @@ function fetchAndCacheOpenIssues(cachePath) {
|
|
|
64
70
|
"20",
|
|
65
71
|
"--json",
|
|
66
72
|
"number,title"
|
|
67
|
-
]));
|
|
68
|
-
const parsed = yield* Effect.try(() => JSON.parse(listStdout));
|
|
73
|
+
]), OpenIssues)];
|
|
69
74
|
yield* writeCache(cachePath, parsed);
|
|
70
75
|
return parsed;
|
|
71
76
|
}).pipe(Effect.orElseSucceed(() => null));
|
|
@@ -78,4 +83,4 @@ function readOrFetchOpenIssues(cachePath) {
|
|
|
78
83
|
});
|
|
79
84
|
}
|
|
80
85
|
|
|
81
|
-
export { ISSUES_CACHE_RELATIVE_PATH, fetchAndCacheOpenIssues, readOpenIssuesFromCache, readOrFetchOpenIssues, resolveIssuesCachePath };
|
|
86
|
+
export { ISSUES_CACHE_RELATIVE_PATH, OpenIssue, fetchAndCacheOpenIssues, readOpenIssuesFromCache, readOrFetchOpenIssues, resolveIssuesCachePath };
|
|
@@ -1,62 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { Result } from "effect";
|
|
2
|
+
import { detectPackageManagerSync } from "@effected/workspaces";
|
|
3
|
+
import { nodeSyncOps } from "@effected/workspaces/node-sync";
|
|
4
4
|
|
|
5
5
|
// src/commitlint/hook/diagnostics/package-manager.ts
|
|
6
6
|
/**
|
|
7
7
|
* Package manager detection for the commit-time hooks.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Delegates to `@effected/workspaces`' `detectPackageManagerSync` — the same
|
|
10
|
+
* detector `Lint`'s `Command.detectPackageManager` runs — so silk-effects has
|
|
11
|
+
* one answer to "which manager owns this root". The kit refuses to guess when
|
|
12
|
+
* no evidence matches (and fails on an unreadable root `package.json`); the
|
|
13
|
+
* hook hints still need a command to print, so those cases fall back to `npm`.
|
|
12
14
|
*
|
|
13
15
|
* @internal
|
|
14
16
|
*/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
};
|
|
29
|
-
function parsePackageManagerField(packageJsonContent) {
|
|
30
|
-
let parsed;
|
|
31
|
-
try {
|
|
32
|
-
parsed = JSON.parse(packageJsonContent);
|
|
33
|
-
} catch {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
37
|
-
const manifest = parsed;
|
|
38
|
-
const fromDevEngines = toPackageManager(devEnginesName(manifest));
|
|
39
|
-
if (fromDevEngines !== null) return fromDevEngines;
|
|
40
|
-
const field = manifest.packageManager;
|
|
41
|
-
if (typeof field !== "string" || field.length === 0) return null;
|
|
42
|
-
return toPackageManager(field.split("@")[0]);
|
|
43
|
-
}
|
|
44
|
-
function detectFromLockfiles(presence) {
|
|
45
|
-
if (presence.pnpm) return "pnpm";
|
|
46
|
-
if (presence.yarn) return "yarn";
|
|
47
|
-
if (presence.bun) return "bun";
|
|
48
|
-
return "npm";
|
|
49
|
-
}
|
|
17
|
+
/**
|
|
18
|
+
* Detect the package manager owning `root`, falling back to `npm`.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* Precedence is the kit's (`PackageManagerDetector`): `pnpm-workspace.yaml`,
|
|
22
|
+
* then a bun or yarn lockfile only when a manifest field also names that
|
|
23
|
+
* manager, then `package.json#workspaces` (npm), `pnpm-lock.yaml`,
|
|
24
|
+
* `package-lock.json`, and finally `devEngines.packageManager` over the
|
|
25
|
+
* top-level `packageManager` field. `root` is probed as given, without ascent.
|
|
26
|
+
*
|
|
27
|
+
* @param root - The directory to probe
|
|
28
|
+
* @returns The detected manager, or `"npm"` when none can be attributed
|
|
29
|
+
*/
|
|
50
30
|
async function detectPackageManager(root) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (fromField !== null) return fromField;
|
|
54
|
-
} catch {}
|
|
55
|
-
return detectFromLockfiles({
|
|
56
|
-
pnpm: existsSync(join(root, "pnpm-lock.yaml")),
|
|
57
|
-
yarn: existsSync(join(root, "yarn.lock")),
|
|
58
|
-
bun: existsSync(join(root, "bun.lock"))
|
|
59
|
-
});
|
|
31
|
+
const detected = detectPackageManagerSync(root, nodeSyncOps);
|
|
32
|
+
return Result.isSuccess(detected) ? detected.success.name : "npm";
|
|
60
33
|
}
|
|
61
34
|
|
|
62
|
-
export {
|
|
35
|
+
export { detectPackageManager };
|
package/commitlint/index.js
CHANGED
|
@@ -18,7 +18,7 @@ import { inferTicketId, readBranchInfo } from "./hook/diagnostics/branch.js";
|
|
|
18
18
|
import { readCache, writeCache } from "./hook/diagnostics/cache.js";
|
|
19
19
|
import { parseHuskyConfigPath, readCommitlintConfigPath } from "./hook/diagnostics/commitlint-config.js";
|
|
20
20
|
import { ISSUES_CACHE_RELATIVE_PATH, fetchAndCacheOpenIssues, readOpenIssuesFromCache, readOrFetchOpenIssues, resolveIssuesCachePath } from "./hook/diagnostics/open-issues.js";
|
|
21
|
-
import {
|
|
21
|
+
import { detectPackageManager } from "./hook/diagnostics/package-manager.js";
|
|
22
22
|
import { buildSigningDiagnostic, parseGpgKeyExpiry, readSigningDiagnostic } from "./hook/diagnostics/signing.js";
|
|
23
23
|
import { closesTrailerRule, hasClosingTrailer } from "./hook/rules/closes-trailer.js";
|
|
24
24
|
import { forbiddenContentRule } from "./hook/rules/forbidden-content.js";
|
|
@@ -69,7 +69,6 @@ var commitlint_exports = /* @__PURE__ */ __exportAll({
|
|
|
69
69
|
default: () => CommitlintConfig,
|
|
70
70
|
defaultPromptConfig: () => defaultPromptConfig,
|
|
71
71
|
detectDCO: () => detectDCO,
|
|
72
|
-
detectFromLockfiles: () => detectFromLockfiles,
|
|
73
72
|
detectPackageManager: () => detectPackageManager,
|
|
74
73
|
detectScopes: () => detectScopes,
|
|
75
74
|
emojiPromptConfig: () => emojiPromptConfig,
|
|
@@ -84,7 +83,6 @@ var commitlint_exports = /* @__PURE__ */ __exportAll({
|
|
|
84
83
|
parseBashCommand: () => parseBashCommand,
|
|
85
84
|
parseGpgKeyExpiry: () => parseGpgKeyExpiry,
|
|
86
85
|
parseHuskyConfigPath: () => parseHuskyConfigPath,
|
|
87
|
-
parsePackageManagerField: () => parsePackageManagerField,
|
|
88
86
|
partitionHits: () => partitionHits,
|
|
89
87
|
planLeakageRule: () => planLeakageRule,
|
|
90
88
|
postToolUseAdvise: () => postToolUseAdvise,
|
|
@@ -141,4 +139,4 @@ var CommitlintConfig = class {
|
|
|
141
139
|
constructor() {}
|
|
142
140
|
};
|
|
143
141
|
|
|
144
|
-
export { COMMIT_TYPES, COMMIT_TYPE_DEFINITIONS, CommitlintConfig, CommitlintConfig as default, DCO_SIGNOFF_TEXT, ERROR_EXPLANATIONS, ERROR_SUGGESTIONS, HookSilencer, ISSUES_CACHE_RELATIVE_PATH, PostToolUseEnvelope, PreToolUseEnvelope, SessionStartEnvelope, TDD_SCOPE_PATTERN, TDD_STATES, TYPE_EMOJIS, TYPE_EMOJIS_UNICODE, buildSigningDiagnostic, closesTrailerRule, commitlint_exports, createPromptConfig, createTypeEnum, defaultPromptConfig, detectDCO,
|
|
142
|
+
export { COMMIT_TYPES, COMMIT_TYPE_DEFINITIONS, CommitlintConfig, CommitlintConfig as default, DCO_SIGNOFF_TEXT, ERROR_EXPLANATIONS, ERROR_SUGGESTIONS, HookSilencer, ISSUES_CACHE_RELATIVE_PATH, PostToolUseEnvelope, PreToolUseEnvelope, SessionStartEnvelope, TDD_SCOPE_PATTERN, TDD_STATES, TYPE_EMOJIS, TYPE_EMOJIS_UNICODE, buildSigningDiagnostic, closesTrailerRule, commitlint_exports, createPromptConfig, createTypeEnum, defaultPromptConfig, detectDCO, detectPackageManager, detectScopes, emojiPromptConfig, fetchAndCacheOpenIssues, forbiddenContentRule, format, getExplanation, getSuggestion, getTypeEmoji, hasClosingTrailer, inferTicketId, parseBashCommand, parseGpgKeyExpiry, parseHuskyConfigPath, partitionHits, planLeakageRule, postToolUseAdvise, preToolUseAdvise, preToolUseAllow, preToolUseDeny, preToolUseSilent, prompter, readBranchInfo, readCache, readCommitlintConfigPath, readOpenIssuesFromCache, readOrFetchOpenIssues, readSigningDiagnostic, resolveIssuesCachePath, sessionStartContext, signingFlagConflictRule, softWrapRule, staticConfig, verbosityRule, writeCache };
|
package/index.d.ts
CHANGED
|
@@ -975,8 +975,8 @@ interface LintMessage {
|
|
|
975
975
|
* Line number where the issue was detected (1-based).
|
|
976
976
|
*
|
|
977
977
|
* @remarks
|
|
978
|
-
* Line numbers are relative to the
|
|
979
|
-
*
|
|
978
|
+
* Line numbers are relative to the whole file, frontmatter block
|
|
979
|
+
* included, so they match the lines an editor shows.
|
|
980
980
|
*/
|
|
981
981
|
line: number;
|
|
982
982
|
/**
|
|
@@ -5456,10 +5456,13 @@ declare function readCache<T>(path: string, ttlSeconds: number): Effect.Effect<T
|
|
|
5456
5456
|
declare function writeCache<T>(path: string, data: T, when?: Date): Effect.Effect<void>;
|
|
5457
5457
|
declare function parseHuskyConfigPath(huskyContent: string, root: string): string | null;
|
|
5458
5458
|
declare function readCommitlintConfigPath(root: string): Promise<string | null>;
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5459
|
+
/** One open issue as `gh issue list --json number,title` prints it. */
|
|
5460
|
+
declare const OpenIssue: Schema.Struct<{
|
|
5461
|
+
readonly number: Schema.Number;
|
|
5462
|
+
readonly title: Schema.String;
|
|
5463
|
+
}>;
|
|
5464
|
+
/** The decoded {@link (OpenIssue:variable)}. */
|
|
5465
|
+
type OpenIssue = typeof OpenIssue.Type;
|
|
5463
5466
|
declare const ISSUES_CACHE_TTL_SECONDS = 600;
|
|
5464
5467
|
/** Relative path under the project root where the open-issues cache lives. */
|
|
5465
5468
|
declare const ISSUES_CACHE_RELATIVE_PATH = ".claude/cache/issues.json";
|
|
@@ -5480,13 +5483,19 @@ declare function readOpenIssuesFromCache(cachePath: string, ttlSeconds?: number)
|
|
|
5480
5483
|
declare function fetchAndCacheOpenIssues(cachePath: string): Effect.Effect<OpenIssue[] | null, never, ChildProcessSpawner.ChildProcessSpawner>;
|
|
5481
5484
|
declare function readOrFetchOpenIssues(cachePath: string): Effect.Effect<OpenIssue[] | null, never, ChildProcessSpawner.ChildProcessSpawner>;
|
|
5482
5485
|
type PackageManager$1 = "pnpm" | "yarn" | "bun" | "npm";
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5486
|
+
/**
|
|
5487
|
+
* Detect the package manager owning `root`, falling back to `npm`.
|
|
5488
|
+
*
|
|
5489
|
+
* @remarks
|
|
5490
|
+
* Precedence is the kit's (`PackageManagerDetector`): `pnpm-workspace.yaml`,
|
|
5491
|
+
* then a bun or yarn lockfile only when a manifest field also names that
|
|
5492
|
+
* manager, then `package.json#workspaces` (npm), `pnpm-lock.yaml`,
|
|
5493
|
+
* `package-lock.json`, and finally `devEngines.packageManager` over the
|
|
5494
|
+
* top-level `packageManager` field. `root` is probed as given, without ascent.
|
|
5495
|
+
*
|
|
5496
|
+
* @param root - The directory to probe
|
|
5497
|
+
* @returns The detected manager, or `"npm"` when none can be attributed
|
|
5498
|
+
*/
|
|
5490
5499
|
declare function detectPackageManager(root: string): Promise<PackageManager$1>;
|
|
5491
5500
|
interface SigningDiagnostic {
|
|
5492
5501
|
format: "gpg" | "ssh" | "none";
|
|
@@ -5591,7 +5600,7 @@ declare const VERBOSITY_LINE_THRESHOLD = 12;
|
|
|
5591
5600
|
declare const VERBOSITY_WORD_THRESHOLD = 150;
|
|
5592
5601
|
declare const verbosityRule: Rule<VerbosityInput, never>;
|
|
5593
5602
|
declare namespace index_d_exports$1 {
|
|
5594
|
-
export { BranchInfo, COMMIT_TYPES, COMMIT_TYPE_DEFINITIONS, ClosesTrailerCtx, ClosesTrailerInput, CommitType, CommitTypeDefinition, CommitlintConfig, CommitlintPlugin, CommitlintUserConfig, ConfigOptions, DCO_SIGNOFF_TEXT, DEFAULT_BODY_MAX_LINE_LENGTH, ERROR_EXPLANATIONS, ERROR_SUGGESTIONS, ForbiddenContentInput, FormatterResult, HookOutput, RuleSeverity$1 as HookRuleSeverity, HookSilencer, ISSUES_CACHE_RELATIVE_PATH, ISSUES_CACHE_TTL_SECONDS, Inquirer, LintOutcome,
|
|
5603
|
+
export { BranchInfo, COMMIT_TYPES, COMMIT_TYPE_DEFINITIONS, ClosesTrailerCtx, ClosesTrailerInput, CommitType, CommitTypeDefinition, CommitlintConfig, CommitlintPlugin, CommitlintUserConfig, ConfigOptions, DCO_SIGNOFF_TEXT, DEFAULT_BODY_MAX_LINE_LENGTH, ERROR_EXPLANATIONS, ERROR_SUGGESTIONS, ForbiddenContentInput, FormatterResult, HookOutput, RuleSeverity$1 as HookRuleSeverity, HookSilencer, ISSUES_CACHE_RELATIVE_PATH, ISSUES_CACHE_TTL_SECONDS, Inquirer, LintOutcome, OpenIssue, PackageManager$1 as PackageManager, ParsedCommit, ParsedKind, PlanLeakageInput, PostToolUseEnvelope, PostToolUseEnvelope as PostToolUseEnvelopeType, PreToolUseEnvelope, PreToolUseEnvelope as PreToolUseEnvelopeType, PromptConfig, PromptConfigOptions, PromptQuestion, PromptSettings, PrompterOptions, Question, RawSigningInputs, ReleaseFormat, ResolvedPromptConfig, Rule, RuleApplicability, RuleConfigTuple, RuleHit, RuleResult, RuleSeverity, RulesConfig, SessionStartEnvelope, SessionStartEnvelope as SessionStartEnvelopeType, SigningDiagnostic, SigningFlagCtx, SigningFlagInput, SoftWrapInput, TDD_SCOPE_PATTERN, TDD_STATES, TYPE_EMOJIS, TYPE_EMOJIS_UNICODE, TypeEnumEntry, VERBOSITY_LINE_THRESHOLD, VERBOSITY_WORD_THRESHOLD, VerbosityInput, buildSigningDiagnostic, closesTrailerRule, createPromptConfig, createTypeEnum, CommitlintConfig as default, defaultPromptConfig, detectDCO, detectPackageManager, detectScopes, emojiPromptConfig, fetchAndCacheOpenIssues, forbiddenContentRule, format, getExplanation, getSuggestion, getTypeEmoji, hasClosingTrailer, inferTicketId, parseBashCommand, parseGpgKeyExpiry, parseHuskyConfigPath, partitionHits, planLeakageRule, postToolUseAdvise, preToolUseAdvise, preToolUseAllow, preToolUseDeny, preToolUseSilent, prompter, readBranchInfo, readCache, readCommitlintConfigPath, readOpenIssuesFromCache, readOrFetchOpenIssues, readSigningDiagnostic, resolveIssuesCachePath, sessionStartContext, signingFlagConflictRule, softWrapRule, staticConfig, verbosityRule, writeCache };
|
|
5595
5604
|
}
|
|
5596
5605
|
/**
|
|
5597
5606
|
* Dynamic commitlint configuration factory.
|
|
@@ -8021,6 +8030,15 @@ declare class ReposLockdown extends ReposLockdown_base {
|
|
|
8021
8030
|
*/
|
|
8022
8031
|
static readonly layer: Layer.Layer<ReposLockdown, never, FileSystem.FileSystem | Path.Path>;
|
|
8023
8032
|
}
|
|
8033
|
+
/**
|
|
8034
|
+
* Default repo name for `add`: the last segment of the remote's repository
|
|
8035
|
+
* path, as `@effected/git`'s `GitRemote.repositoryPath` reads it (one trailing
|
|
8036
|
+
* `/` and one trailing `.git` dropped). Every remote form git accepts is
|
|
8037
|
+
* covered, scp without a slash included — `git@host:repo.git` is `repo`.
|
|
8038
|
+
*
|
|
8039
|
+
* @internal
|
|
8040
|
+
*/
|
|
8041
|
+
declare const repoSlug: (url: string) => string;
|
|
8024
8042
|
/**
|
|
8025
8043
|
* Minimum age (in milliseconds) a `.lock` file must reach before `sync` will
|
|
8026
8044
|
* remove it. An ACTIVE git process can legitimately hold
|
|
@@ -8151,7 +8169,7 @@ declare class ReposManager extends ReposManager_base {
|
|
|
8151
8169
|
static readonly layer: Layer.Layer<ReposManager, never, ReposConfigStore | Git | FileSystem.FileSystem | Path.Path | ReposLockdown>;
|
|
8152
8170
|
}
|
|
8153
8171
|
declare namespace index_d_exports$3 {
|
|
8154
|
-
export { DriftKind, GitSubmoduleError, GitSubmoduleErrorBase, MANIFEST_PATH, NOTE_LIMIT, NoteNotFoundError, NoteNotFoundErrorBase, REPOS_DIR, RepoDrift, RepoEntry, RepoName, RepoNotFoundError, RepoNotFoundErrorBase, RepoNote, RepoOrientation, RepoStatusEntry, ReposAddResult, ReposConfigError, ReposConfigErrorBase, ReposConfigStore, ReposConfigStoreShape, ReposDeregisterResult, ReposDrift, ReposDriftReport, ReposDriftShape, ReposLockdown, ReposLockdownError, ReposLockdownErrorBase, ReposLockdownShape, ReposManager, ReposManagerShape, ReposManifestFile, ReposNoteResult, ReposPinResult, ReposRemoveResult, ReposRenameResult, ReposRestoreResult, ReposStatusReport, ReposSyncReport, STALE_LOCK_MAX_AGE_MS, resolveModuleDir, submoduleNameFromKey };
|
|
8172
|
+
export { DriftKind, GitSubmoduleError, GitSubmoduleErrorBase, MANIFEST_PATH, NOTE_LIMIT, NoteNotFoundError, NoteNotFoundErrorBase, REPOS_DIR, RepoDrift, RepoEntry, RepoName, RepoNotFoundError, RepoNotFoundErrorBase, RepoNote, RepoOrientation, RepoStatusEntry, ReposAddResult, ReposConfigError, ReposConfigErrorBase, ReposConfigStore, ReposConfigStoreShape, ReposDeregisterResult, ReposDrift, ReposDriftReport, ReposDriftShape, ReposLockdown, ReposLockdownError, ReposLockdownErrorBase, ReposLockdownShape, ReposManager, ReposManagerShape, ReposManifestFile, ReposNoteResult, ReposPinResult, ReposRemoveResult, ReposRenameResult, ReposRestoreResult, ReposStatusReport, ReposSyncReport, STALE_LOCK_MAX_AGE_MS, repoSlug, resolveModuleDir, submoduleNameFromKey };
|
|
8155
8173
|
}
|
|
8156
8174
|
/**
|
|
8157
8175
|
* Strip leading semver range operators from a version string.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Command } from "../utils/Command.js";
|
|
2
2
|
import { Filter } from "../utils/Filter.js";
|
|
3
|
-
import { Data, Effect, FileSystem, Path, Schema, Stream } from "effect";
|
|
3
|
+
import { Data, Effect, FileSystem, Option, Path, Schema, Stream } from "effect";
|
|
4
4
|
import { Git } from "@effected/git";
|
|
5
|
+
import { Walker } from "@effected/walker";
|
|
5
6
|
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
6
7
|
|
|
7
8
|
// src/lint/handlers/TextFiles.ts
|
|
@@ -279,12 +280,8 @@ var TextFiles = class TextFiles {
|
|
|
279
280
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
280
281
|
const fs = yield* FileSystem.FileSystem;
|
|
281
282
|
const pathService = yield* Path.Path;
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
const parent = pathService.dirname(cwd);
|
|
285
|
-
if (parent === cwd) break;
|
|
286
|
-
cwd = parent;
|
|
287
|
-
}
|
|
283
|
+
const chain = yield* Walker.ascend(pathService.dirname(path));
|
|
284
|
+
const cwd = Option.getOrElse(yield* Walker.firstMatch(chain, (dir) => fs.exists(dir)), () => chain[chain.length - 1] ?? pathService.dirname(path));
|
|
288
285
|
const relative = pathService.relative(cwd, path).split(pathService.sep).join("/");
|
|
289
286
|
const command = ChildProcess.make("git", [
|
|
290
287
|
"cat-file",
|
package/lint/utils/Command.js
CHANGED
|
@@ -2,10 +2,10 @@ import { Result } from "effect";
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { detectPackageManagerSync } from "@effected/workspaces";
|
|
5
|
-
import { execSync } from "node:child_process";
|
|
6
5
|
import { LocalExec, Tool, makeToolDiscoverySync } from "@effected/commands";
|
|
7
|
-
import { nodeSpawnSync } from "@effected/commands/node-sync";
|
|
8
6
|
import { nodeSyncOps } from "@effected/workspaces/node-sync";
|
|
7
|
+
import { execSync } from "node:child_process";
|
|
8
|
+
import { nodeSpawnSync } from "@effected/commands/node-sync";
|
|
9
9
|
|
|
10
10
|
// src/lint/utils/Command.ts
|
|
11
11
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@savvy-web/silk-effects",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared Effect library for Silk Suite conventions",
|
|
6
6
|
"homepage": "https://github.com/savvy-web/systems/tree/main/packages/silk-effects",
|
|
@@ -38,20 +38,20 @@
|
|
|
38
38
|
"@changesets/pre": "^3.0.0",
|
|
39
39
|
"@changesets/read": "^1.0.1",
|
|
40
40
|
"@effected/github-references": "^0.11.0",
|
|
41
|
-
"@effected/glob": "^0.
|
|
42
|
-
"@effected/jsonc": "^0.20.
|
|
41
|
+
"@effected/glob": "^0.15.0",
|
|
42
|
+
"@effected/jsonc": "^0.20.1",
|
|
43
43
|
"@effected/markdown": "^0.23.0",
|
|
44
|
-
"@effected/package-json": "^0.26.
|
|
44
|
+
"@effected/package-json": "^0.26.1",
|
|
45
45
|
"@effected/toml": "^0.16.0",
|
|
46
|
-
"@effected/walker": "^0.
|
|
46
|
+
"@effected/walker": "^0.21.0",
|
|
47
47
|
"@effected/yaml": "^0.25.1",
|
|
48
48
|
"@manypkg/get-packages": "^3.1.0",
|
|
49
49
|
"@savvy-web/silk-core": "^0.5.2",
|
|
50
50
|
"shell-quote": "^1.12.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@effected/commands": "^0.
|
|
54
|
-
"@effected/git": "^0.
|
|
53
|
+
"@effected/commands": "^0.17.0",
|
|
54
|
+
"@effected/git": "^0.26.0",
|
|
55
55
|
"@effected/templates": "^0.14.0",
|
|
56
56
|
"@effected/workspaces": "^0.39.0",
|
|
57
57
|
"effect": "^4.0.0"
|
package/repos/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { RepoStatusEntry, ReposAddResult, ReposDeregisterResult, ReposNoteResult
|
|
|
7
7
|
import { ReposConfigStore } from "./services/config-store.js";
|
|
8
8
|
import { ReposLockdown, resolveModuleDir } from "./services/lockdown.js";
|
|
9
9
|
import { ReposDrift, submoduleNameFromKey } from "./services/drift.js";
|
|
10
|
-
import { ReposManager, STALE_LOCK_MAX_AGE_MS } from "./services/manager.js";
|
|
10
|
+
import { ReposManager, STALE_LOCK_MAX_AGE_MS, repoSlug } from "./services/manager.js";
|
|
11
11
|
|
|
12
12
|
// src/repos/index.ts
|
|
13
13
|
var repos_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -47,8 +47,9 @@ var repos_exports = /* @__PURE__ */ __exportAll({
|
|
|
47
47
|
ReposStatusReport: () => ReposStatusReport,
|
|
48
48
|
ReposSyncReport: () => ReposSyncReport,
|
|
49
49
|
STALE_LOCK_MAX_AGE_MS: () => STALE_LOCK_MAX_AGE_MS,
|
|
50
|
+
repoSlug: () => repoSlug,
|
|
50
51
|
resolveModuleDir: () => resolveModuleDir,
|
|
51
52
|
submoduleNameFromKey: () => submoduleNameFromKey
|
|
52
53
|
});
|
|
53
54
|
|
|
54
|
-
export { DriftKind, GitSubmoduleError, GitSubmoduleErrorBase, MANIFEST_PATH, NoteNotFoundError, NoteNotFoundErrorBase, REPOS_DIR, RepoDrift, RepoEntry, RepoName, RepoNotFoundError, RepoNotFoundErrorBase, RepoNote, RepoOrientation, RepoStatusEntry, ReposAddResult, ReposConfigError, ReposConfigErrorBase, ReposConfigStore, ReposDeregisterResult, ReposDrift, ReposDriftReport, ReposLockdown, ReposLockdownError, ReposLockdownErrorBase, ReposManager, ReposManifestFile, ReposNoteResult, ReposPinResult, ReposRemoveResult, ReposRenameResult, ReposRestoreResult, ReposStatusReport, ReposSyncReport, STALE_LOCK_MAX_AGE_MS, repos_exports, resolveModuleDir, submoduleNameFromKey };
|
|
55
|
+
export { DriftKind, GitSubmoduleError, GitSubmoduleErrorBase, MANIFEST_PATH, NoteNotFoundError, NoteNotFoundErrorBase, REPOS_DIR, RepoDrift, RepoEntry, RepoName, RepoNotFoundError, RepoNotFoundErrorBase, RepoNote, RepoOrientation, RepoStatusEntry, ReposAddResult, ReposConfigError, ReposConfigErrorBase, ReposConfigStore, ReposDeregisterResult, ReposDrift, ReposDriftReport, ReposLockdown, ReposLockdownError, ReposLockdownErrorBase, ReposManager, ReposManifestFile, ReposNoteResult, ReposPinResult, ReposRemoveResult, ReposRenameResult, ReposRestoreResult, ReposStatusReport, ReposSyncReport, STALE_LOCK_MAX_AGE_MS, repoSlug, repos_exports, resolveModuleDir, submoduleNameFromKey };
|
|
@@ -5,7 +5,7 @@ import { ReposConfigStore } from "./config-store.js";
|
|
|
5
5
|
import { ReposLockdown, resolveModuleDir } from "./lockdown.js";
|
|
6
6
|
import { submoduleNameFromKey } from "./drift.js";
|
|
7
7
|
import { Clock, Context, Effect, Exit, FileSystem, Layer, Option, Path, Result, Schema } from "effect";
|
|
8
|
-
import { Git, GitConfig, Gitmodules, LsRemoteEntry } from "@effected/git";
|
|
8
|
+
import { Git, GitConfig, GitRemote, Gitmodules, LsRemoteEntry } from "@effected/git";
|
|
9
9
|
import { createHash } from "node:crypto";
|
|
10
10
|
|
|
11
11
|
// src/repos/services/manager.ts
|
|
@@ -15,6 +15,22 @@ import { createHash } from "node:crypto";
|
|
|
15
15
|
*/
|
|
16
16
|
const STALE_LOCKS = ["index.lock", "shallow.lock"];
|
|
17
17
|
/**
|
|
18
|
+
* Default repo name for `add`: the last segment of the remote's repository
|
|
19
|
+
* path, as `@effected/git`'s `GitRemote.repositoryPath` reads it (one trailing
|
|
20
|
+
* `/` and one trailing `.git` dropped). Every remote form git accepts is
|
|
21
|
+
* covered, scp without a slash included — `git@host:repo.git` is `repo`.
|
|
22
|
+
*
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
const repoSlug = (url) => {
|
|
26
|
+
const trimmed = url.trim();
|
|
27
|
+
const path = Option.match(GitRemote.parse(trimmed), {
|
|
28
|
+
onNone: () => trimmed,
|
|
29
|
+
onSome: GitRemote.repositoryPath
|
|
30
|
+
});
|
|
31
|
+
return path.split("/").filter((segment) => segment.length > 0).pop() ?? path;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
18
34
|
* Minimum age (in milliseconds) a `.lock` file must reach before `sync` will
|
|
19
35
|
* remove it. An ACTIVE git process can legitimately hold
|
|
20
36
|
* `index.lock`/`shallow.lock` for the duration of its own run; removing a
|
|
@@ -191,11 +207,6 @@ var ReposManager = class extends Context.Service()("@savvy-web/silk-effects/Repo
|
|
|
191
207
|
boundaryMarked
|
|
192
208
|
};
|
|
193
209
|
});
|
|
194
|
-
/** Last path segment of a repo URL, with a trailing `.git` stripped. */
|
|
195
|
-
const repoSlug = (url) => {
|
|
196
|
-
const last = url.split("/").filter((segment) => segment.length > 0).pop() ?? url;
|
|
197
|
-
return last.endsWith(".git") ? last.slice(0, -4) : last;
|
|
198
|
-
};
|
|
199
210
|
/**
|
|
200
211
|
* Fetch `ref` shallow into a submodule via the kit's `Git.fetchAny`:
|
|
201
212
|
* tag-form fetch first (tags need the explicit `fetch origin tag <ref>`
|
|
@@ -728,4 +739,4 @@ var ReposManager = class extends Context.Service()("@savvy-web/silk-effects/Repo
|
|
|
728
739
|
}));
|
|
729
740
|
};
|
|
730
741
|
|
|
731
|
-
export { ReposManager, STALE_LOCK_MAX_AGE_MS };
|
|
742
|
+
export { ReposManager, STALE_LOCK_MAX_AGE_MS, repoSlug };
|
|
@@ -3,8 +3,8 @@ import { DryRunParseError, NotATurboRepoError, TurboExecError, TurboNotInstalled
|
|
|
3
3
|
import { TurboDryRun } from "../schemas/DryRun.js";
|
|
4
4
|
import { Context, Effect, FileSystem, Layer, Schema } from "effect";
|
|
5
5
|
import { Git } from "@effected/git";
|
|
6
|
-
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
7
6
|
import { Run, Tool, ToolDiscovery } from "@effected/commands";
|
|
7
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
8
8
|
|
|
9
9
|
// src/turbo/services/TurboInspector.ts
|
|
10
10
|
/**
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// src/changesets/utils/strip-frontmatter.ts
|
|
2
|
-
/**
|
|
3
|
-
* Strip leading YAML frontmatter from a markdown string.
|
|
4
|
-
*
|
|
5
|
-
* Removes the `---\n...\n---\n` block at the start of the content.
|
|
6
|
-
* If no frontmatter is present, the content is returned as-is.
|
|
7
|
-
*
|
|
8
|
-
* @param content - Raw markdown string potentially containing frontmatter
|
|
9
|
-
* @returns The markdown content with frontmatter removed
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```typescript
|
|
13
|
-
* import { stripFrontmatter } from "../utils/strip-frontmatter.js";
|
|
14
|
-
*
|
|
15
|
-
* const raw = "---\n\"pkg\": minor\n---\n\n## Features\n\n- New API";
|
|
16
|
-
* const body = stripFrontmatter(raw);
|
|
17
|
-
* // "\n## Features\n\n- New API"
|
|
18
|
-
* ```
|
|
19
|
-
*
|
|
20
|
-
* @internal
|
|
21
|
-
*/
|
|
22
|
-
function stripFrontmatter(content) {
|
|
23
|
-
return content.replace(/^---\n[\s\S]*?\n---\n?/, "");
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export { stripFrontmatter };
|