@doki-land/nifty 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,13 @@
8
8
  "cli.cmd.bump": "Align workspace crate and package versions",
9
9
  "cli.cmd.publish": "Publish workspace npm packages (OIDC or token + TOTP)",
10
10
  "cli.cmd.trust": "Configure npm Trusted Publisher for workspace packages",
11
+ "cli.cmd.reword": "Rewrite commit messages at the git object layer",
12
+ "cli.cmd.reword.export": "Export a JSON reword map template",
13
+ "cli.cmd.reword.rewrite": "Rewrite commits from a JSON map and update the branch ref",
14
+ "cli.cmd.retime": "Spread commit timestamps across a date range on a new branch",
15
+ "cli.cmd.retime.root": "Retime all commits from repository root through tip",
16
+ "cli.cmd.change-logs": "Draft release reference changelogs from git tags",
17
+ "cli.cmd.change-logs.lookup": "Look up GitHub user id/login from email or login",
11
18
  "cli.opt.cwd": "Working directory",
12
19
  "cli.opt.interactive": "Prompt before applying dependency updates",
13
20
  "cli.opt.from": "Start git ref for commit range",
@@ -37,5 +44,21 @@
37
44
  "cli.opt.only": "Limit trust to one package name",
38
45
  "cli.opt.otp": "One-time npm password (6 digits)",
39
46
  "cli.opt.totp-secret": "Base32 TOTP secret (overrides env)",
40
- "cli.opt.npm-token": "npm auth token (overrides NPM_TOKEN)"
47
+ "cli.opt.npm-token": "npm auth token (overrides NPM_TOKEN)",
48
+ "cli.opt.base": "Exclusive range start commit (e.g. 34e1e665^)",
49
+ "cli.opt.ref": "Branch ref to rewrite (default: HEAD)",
50
+ "cli.opt.path": "Path to reword JSON map (default: reword.pending.json)",
51
+ "cli.opt.start-date": "Random window start (YYYY-MM-DD or ISO datetime)",
52
+ "cli.opt.end-date": "Random window end",
53
+ "cli.opt.branch": "Output branch name (default: time-travel)",
54
+ "cli.opt.tip": "Range end revision (default: HEAD)",
55
+ "cli.opt.message": "Optional new message for the root commit (retime root)",
56
+ "cli.opt.write": "Write documentation/maintenance/releases/vX.Y.Z.reference.md",
57
+ "cli.opt.tags": "List version tags with short hashes",
58
+ "cli.opt.author-map": "Path to author-github.json",
59
+ "cli.opt.releases-dir": "Releases directory for --write",
60
+ "cli.opt.email": "Author email to resolve",
61
+ "cli.opt.login": "GitHub login to resolve",
62
+ "cli.opt.github-token": "GitHub token for search-by-email",
63
+ "cli.opt.fetch": "Fetch missing numeric id from GitHub API"
41
64
  }
package/package.json CHANGED
@@ -1,16 +1,12 @@
1
1
  {
2
+ "name": "@doki-land/nifty",
3
+ "version": "0.0.2",
4
+ "description": "Gitmoji-first commit conventions and release helpers (Node-API + TypeScript)",
5
+ "type": "module",
6
+ "license": "MPL-2.0",
2
7
  "bin": {
3
8
  "nifty": "cli/nifty.mjs"
4
9
  },
5
- "dependencies": {
6
- "@vmz/commander": "^0.2.0",
7
- "jiti": "^2.4.2"
8
- },
9
- "description": "Gitmoji-first commit conventions and release helpers (Node-API + TypeScript)",
10
- "devDependencies": {
11
- "@types/node": "^22.13.10",
12
- "typescript": "^5.8.3"
13
- },
14
10
  "exports": {
15
11
  ".": "./src/index.ts",
16
12
  "./cli": "./src/cli/index.ts"
@@ -20,12 +16,17 @@
20
16
  "locales",
21
17
  "src"
22
18
  ],
23
- "license": "MPL-2.0",
24
- "name": "@doki-land/nifty",
19
+ "scripts": {
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "dependencies": {
23
+ "@vmz/commander": "^0.2.0",
24
+ "jiti": "^2.4.2"
25
+ },
25
26
  "optionalDependencies": {
26
- "@doki-land/nifty-darwin-arm64": "0.0.1",
27
- "@doki-land/nifty-linux-x64": "0.0.1",
28
- "@doki-land/nifty-win32-x64": "0.0.1"
27
+ "@doki-land/nifty-win32-x64": "0.0.2",
28
+ "@doki-land/nifty-linux-x64": "0.0.2",
29
+ "@doki-land/nifty-darwin-arm64": "0.0.2"
29
30
  },
30
31
  "publishConfig": {
31
32
  "access": "public"
@@ -33,10 +34,5 @@
33
34
  "repository": {
34
35
  "type": "git",
35
36
  "url": "git+https://github.com/oovm/npm-tools.git"
36
- },
37
- "scripts": {
38
- "typecheck": "tsc --noEmit"
39
- },
40
- "type": "module",
41
- "version": "0.0.1"
37
+ }
42
38
  }
@@ -0,0 +1,97 @@
1
+ import { join } from "node:path";
2
+
3
+ import type { Cli, ParsedOptions } from "@vmz/commander";
4
+
5
+ import { loadConfig } from "../config/loadConfig.js";
6
+ import { loadNiftyNative } from "../native.js";
7
+ import { bootstrapFromOptions } from "./context.js";
8
+ import { cwdFrom, flag, str } from "./options.js";
9
+
10
+ export function registerChangeLogsCommand(cli: Cli): void {
11
+ const changeLogs = cli.command("change-logs", "cli.cmd.change-logs")
12
+ .option("--version <version>", "cli.opt.version")
13
+ .option("--from <ref>", "cli.opt.from")
14
+ .option("--to <ref>", "cli.opt.to")
15
+ .option("--write", "cli.opt.write")
16
+ .option("--tags", "cli.opt.tags")
17
+ .option("--repo <owner/name>", "cli.opt.repo")
18
+ .option("--author-map <path>", "cli.opt.author-map")
19
+ .option("--releases-dir <path>", "cli.opt.releases-dir");
20
+
21
+ changeLogs
22
+ .command("lookup", "cli.cmd.change-logs.lookup")
23
+ .option("--email <email>", "cli.opt.email")
24
+ .option("--login <login>", "cli.opt.login")
25
+ .option("--map <path>", "cli.opt.author-map")
26
+ .option("--github-token <token>", "cli.opt.github-token")
27
+ .option("--fetch", "cli.opt.fetch")
28
+ .action(async (options) => cmdChangeLogsLookup(options));
29
+
30
+ changeLogs.action(async (options) => cmdChangeLogsRender(options));
31
+ }
32
+
33
+ export async function cmdChangeLogsRender(options: ParsedOptions): Promise<number> {
34
+ await bootstrapFromOptions(options);
35
+ const cwd = cwdFrom(options) ?? process.cwd();
36
+ const { config } = await loadConfig({ cwd, createIfMissing: false });
37
+ const native = loadNiftyNative();
38
+ const report = native.history["changelog-render"]({
39
+ cwd,
40
+ version: str(options, "version"),
41
+ fromRef: str(options, "from"),
42
+ toRef: str(options, "to"),
43
+ write: flag(options, "write"),
44
+ tags: flag(options, "tags"),
45
+ repo: str(options, "repo") ?? config.changelog?.repo,
46
+ authorMap: str(options, "author-map") ?? config.changelog?.authorMap,
47
+ releasesDir: str(options, "releases-dir") ?? config.changelog?.releasesDir,
48
+ });
49
+
50
+ if (flag(options, "tags")) {
51
+ console.log(report.notes);
52
+ return 0;
53
+ }
54
+
55
+ if (report.rangeLabel) {
56
+ console.error(`change-logs: ${report.rangeLabel} — ${report.commitCount} commit(s)`);
57
+ }
58
+ if (report.writtenPath) {
59
+ console.error(`change-logs: wrote ${report.writtenPath}`);
60
+ }
61
+ process.stdout.write(report.notes);
62
+ return 0;
63
+ }
64
+
65
+ export async function cmdChangeLogsLookup(options: ParsedOptions): Promise<number> {
66
+ await bootstrapFromOptions(options);
67
+ const cwd = cwdFrom(options) ?? process.cwd();
68
+ const { config } = await loadConfig({ cwd, createIfMissing: false });
69
+ const email = str(options, "email");
70
+ const login = str(options, "login");
71
+ if (!email && !login) {
72
+ throw new Error("lookup requires --email or --login");
73
+ }
74
+ const native = loadNiftyNative();
75
+ const author = native.history["changelog-lookup"]({
76
+ cwd,
77
+ email,
78
+ login,
79
+ map: str(options, "map") ?? config.changelog?.authorMap,
80
+ githubToken: str(options, "github-token") ?? config.githubToken ?? process.env.GITHUB_TOKEN,
81
+ fetch: flag(options, "fetch"),
82
+ });
83
+ const json: Record<string, unknown> = {};
84
+ if (author.id !== undefined) {
85
+ json.id = author.id;
86
+ }
87
+ if (author.login) {
88
+ json.login = author.login;
89
+ }
90
+ console.log(JSON.stringify(json, null, 2));
91
+ return 0;
92
+ }
93
+
94
+ /** Default author map path relative to repo root (matches git-change-logs). */
95
+ export function defaultAuthorMapPath(repoRoot: string): string {
96
+ return join(repoRoot, "documentation/maintenance/author-github.json");
97
+ }
package/src/cli/cli.ts CHANGED
@@ -4,9 +4,12 @@ import { fileURLToPath } from "node:url";
4
4
  import { createCli } from "@vmz/commander";
5
5
 
6
6
  import { registerBumpCommand } from "./bump-cmd.js";
7
+ import { registerChangeLogsCommand } from "./change-logs-cmd.js";
7
8
  import { registerInstallNativeCommand } from "./install-native-cmd.js";
8
9
  import { registerLintCommands } from "./lint-cmd.js";
9
10
  import { registerPublishCommand } from "./publish-cmd.js";
11
+ import { registerRetimeCommand } from "./retime-cmd.js";
12
+ import { registerRewordCommand } from "./reword-cmd.js";
10
13
  import { registerTrustCommand } from "./trust-cmd.js";
11
14
  import { registerUpdateCommand } from "./update-cmd.js";
12
15
  import { registerUploadCommand } from "./upload-cmd.js";
@@ -25,6 +28,9 @@ function buildNiftyCli() {
25
28
  registerBumpCommand(cli);
26
29
  registerPublishCommand(cli);
27
30
  registerTrustCommand(cli);
31
+ registerRewordCommand(cli);
32
+ registerRetimeCommand(cli);
33
+ registerChangeLogsCommand(cli);
28
34
 
29
35
  return cli;
30
36
  }
@@ -0,0 +1,62 @@
1
+ import type { Cli, ParsedOptions } from "@vmz/commander";
2
+
3
+ import { loadNiftyNative } from "../native.js";
4
+ import { bootstrapFromOptions } from "./context.js";
5
+ import { cwdFrom, str } from "./options.js";
6
+
7
+ export function registerRetimeCommand(cli: Cli): void {
8
+ const retime = cli.command("retime", "cli.cmd.retime")
9
+ .option("-s, --start-date <start>", "cli.opt.start-date")
10
+ .option("--end-date <end>", "cli.opt.end-date")
11
+ .option("-b, --branch <branch>", "cli.opt.branch")
12
+ .option("--tip <ref>", "cli.opt.tip");
13
+
14
+ retime
15
+ .command("root", "cli.cmd.retime.root")
16
+ .option("-s, --start-date <start>", "cli.opt.start-date")
17
+ .option("--end-date <end>", "cli.opt.end-date")
18
+ .option("-b, --branch <branch>", "cli.opt.branch")
19
+ .option("--tip <ref>", "cli.opt.tip")
20
+ .option("-m, --message <text>", "cli.opt.message")
21
+ .action(async (options) => cmdRetimeRoot(options));
22
+
23
+ retime.action(async (options) => cmdRetimeRange(options));
24
+ }
25
+
26
+ export async function cmdRetimeRange(options: ParsedOptions): Promise<number> {
27
+ await bootstrapFromOptions(options);
28
+ const commit = options._[0];
29
+ if (!commit) {
30
+ throw new Error("missing commit hash for range retime");
31
+ }
32
+ const native = loadNiftyNative();
33
+ const report = native.history["retime-range"]({
34
+ cwd: cwdFrom(options),
35
+ commit,
36
+ startDate: str(options, "start-date"),
37
+ endDate: str(options, "end-date"),
38
+ branch: str(options, "branch"),
39
+ tip: str(options, "tip"),
40
+ });
41
+ printRetimeSummary(report);
42
+ return 0;
43
+ }
44
+
45
+ export async function cmdRetimeRoot(options: ParsedOptions): Promise<number> {
46
+ await bootstrapFromOptions(options);
47
+ const native = loadNiftyNative();
48
+ const report = native.history["retime-root"]({
49
+ cwd: cwdFrom(options),
50
+ startDate: str(options, "start-date"),
51
+ endDate: str(options, "end-date"),
52
+ branch: str(options, "branch"),
53
+ tip: str(options, "tip"),
54
+ message: str(options, "message"),
55
+ });
56
+ printRetimeSummary(report);
57
+ return 0;
58
+ }
59
+
60
+ function printRetimeSummary(report: { rewritten: number; branch: string; newTip: string }): void {
61
+ console.log(`retimed ${report.rewritten} commit(s) on branch ${report.branch}; tip ${report.newTip}`);
62
+ }
@@ -0,0 +1,87 @@
1
+ import type { Cli, ParsedOptions } from "@vmz/commander";
2
+
3
+ import { loadNiftyNative } from "../native.js";
4
+ import { bootstrapFromOptions } from "./context.js";
5
+ import { cwdFrom, flag, str } from "./options.js";
6
+
7
+ export function registerRewordCommand(cli: Cli): void {
8
+ const reword = cli.command("reword", "cli.cmd.reword");
9
+
10
+ reword
11
+ .command("export", "cli.cmd.reword.export")
12
+ .option("--base <ref>", "cli.opt.base")
13
+ .option("--ref <ref>", "cli.opt.ref")
14
+ .option("--path <file>", "cli.opt.path")
15
+ .action(async (options) => cmdRewordExport(options));
16
+
17
+ reword
18
+ .command("rewrite", "cli.cmd.reword.rewrite")
19
+ .option("--base <ref>", "cli.opt.base")
20
+ .option("--ref <ref>", "cli.opt.ref")
21
+ .option("--path <file>", "cli.opt.path")
22
+ .option("--dry-run", "cli.opt.dry-run")
23
+ .action(async (options) => cmdRewordRewrite(options));
24
+ }
25
+
26
+ export async function cmdRewordExport(options: ParsedOptions): Promise<number> {
27
+ await bootstrapFromOptions(options);
28
+ const base = requireStr(options, "base");
29
+ const path = str(options, "path") ?? "reword.pending.json";
30
+ const native = loadNiftyNative();
31
+ const report = native.history["reword-export"]({
32
+ cwd: cwdFrom(options),
33
+ base,
34
+ ref: str(options, "ref"),
35
+ path,
36
+ });
37
+ console.log(`export: wrote ${report.count} commit entry(ies) to ${report.path}`);
38
+ return 0;
39
+ }
40
+
41
+ export async function cmdRewordRewrite(options: ParsedOptions): Promise<number> {
42
+ await bootstrapFromOptions(options);
43
+ const base = requireStr(options, "base");
44
+ const path = requireStr(options, "path");
45
+ const dryRun = flag(options, "dry-run");
46
+ const native = loadNiftyNative();
47
+ const report = native.history["reword-rewrite"]({
48
+ cwd: cwdFrom(options),
49
+ base,
50
+ ref: str(options, "ref"),
51
+ path,
52
+ dryRun,
53
+ });
54
+
55
+ if (dryRun) {
56
+ if (report.changes.length === 0) {
57
+ console.log("dry-run: no commit objects need rewriting");
58
+ return 0;
59
+ }
60
+ console.log(`dry-run: ${report.changes.length} commit object(s) would be rewritten on ${report.refName}\n`);
61
+ for (const change of report.changes) {
62
+ console.log(`${change.oldOid} ${change.oldSubject}`);
63
+ console.log(` -> ${change.newSubject}`);
64
+ if (change.parentsRelinked && !change.messageChanged) {
65
+ console.log(" (parent chain relink only)");
66
+ }
67
+ console.log();
68
+ }
69
+ return 0;
70
+ }
71
+
72
+ console.log(
73
+ `rewrote ${report.changes.length} commit object(s); ${report.oldTip} -> ${report.newTip ?? report.oldTip}`,
74
+ );
75
+ for (const change of report.changes) {
76
+ console.log(` ${change.oldOid} ${change.newSubject}`);
77
+ }
78
+ return 0;
79
+ }
80
+
81
+ function requireStr(options: ParsedOptions, key: string): string {
82
+ const value = str(options, key);
83
+ if (!value) {
84
+ throw new Error(`missing required --${key}`);
85
+ }
86
+ return value;
87
+ }
@@ -2,6 +2,7 @@ import type { Cli, ParsedOptions } from "@vmz/commander";
2
2
 
3
3
  import { loadNiftyNative } from "../native.js";
4
4
  import { authPayload } from "./authArgs.js";
5
+ import { loadConfig } from "../config/loadConfig.js";
5
6
  import { bootstrapFromOptions } from "./context.js";
6
7
  import { printTrustReport } from "./trust.js";
7
8
  import { authFromOptions, cwdFrom, flag, str } from "./options.js";
@@ -19,12 +20,14 @@ export function registerTrustCommand(cli: Cli): void {
19
20
 
20
21
  export async function cmdTrust(options: ParsedOptions): Promise<number> {
21
22
  await bootstrapFromOptions(options);
23
+ const { config } = await loadConfig({ cwd: cwdFrom(options), createIfMissing: false });
22
24
  const native = loadNiftyNative();
23
25
  const report = native.publisher["trust-workspace"]({
24
26
  cwd: cwdFrom(options),
25
27
  dryRun: flag(options, "dry-run"),
26
28
  refresh: flag(options, "refresh"),
27
29
  only: str(options, "only"),
30
+ packages: config.publish?.packages,
28
31
  ...authPayload(authFromOptions(options)),
29
32
  });
30
33
  printTrustReport(report);
@@ -16,6 +16,20 @@ export type NiftyConfig = {
16
16
  cargoRoot?: string;
17
17
  /** npm package root override. */
18
18
  npmRoot?: string;
19
+ /** npm publish / Trusted Publisher (CI uses publish-npm.yml). */
20
+ publish?: {
21
+ /** Package names to trust (includes registry-only native sidecars). */
22
+ packages?: string[];
23
+ };
24
+ /** Release reference changelog defaults (`nifty change-logs`). */
25
+ changelog?: {
26
+ /** GitHub `owner/repo` for contrib.rocks (default: parse `origin`). */
27
+ repo?: string;
28
+ /** Email → GitHub map path (default: `documentation/maintenance/author-github.json`). */
29
+ authorMap?: string;
30
+ /** `--write` output directory (default: `documentation/maintenance/releases`). */
31
+ releasesDir?: string;
32
+ };
19
33
  /** Rule-based lint configuration. */
20
34
  lint?: {
21
35
  rules?: Array<{
package/src/native.ts CHANGED
@@ -68,6 +68,81 @@ export type TrustReport = {
68
68
  failed: string[];
69
69
  };
70
70
 
71
+ export type RewordPlannedChange = {
72
+ oldOid: string;
73
+ oldSubject: string;
74
+ newSubject: string;
75
+ parentsRelinked: boolean;
76
+ messageChanged: boolean;
77
+ };
78
+
79
+ export type RewordRewriteReport = {
80
+ changes: RewordPlannedChange[];
81
+ oldTip: string;
82
+ newTip?: string;
83
+ refName: string;
84
+ dryRun: boolean;
85
+ };
86
+
87
+ export type HistoryExports = {
88
+ "reword-export": (options: {
89
+ cwd?: string;
90
+ base: string;
91
+ ref?: string;
92
+ path: string;
93
+ }) => { count: number; path: string };
94
+ "reword-rewrite": (options: {
95
+ cwd?: string;
96
+ base: string;
97
+ ref?: string;
98
+ path: string;
99
+ dryRun?: boolean;
100
+ }) => RewordRewriteReport;
101
+ "retime-range": (options: {
102
+ cwd?: string;
103
+ commit: string;
104
+ startDate?: string;
105
+ endDate?: string;
106
+ branch?: string;
107
+ tip?: string;
108
+ }) => { branch: string; newTip: string; rewritten: number };
109
+ "retime-root": (options: {
110
+ cwd?: string;
111
+ startDate?: string;
112
+ endDate?: string;
113
+ branch?: string;
114
+ tip?: string;
115
+ message?: string;
116
+ }) => { branch: string; newTip: string; rewritten: number };
117
+ "changelog-render": (options: {
118
+ cwd?: string;
119
+ version?: string;
120
+ fromRef?: string;
121
+ toRef?: string;
122
+ write?: boolean;
123
+ tags?: boolean;
124
+ repo?: string;
125
+ authorMap?: string;
126
+ releasesDir?: string;
127
+ }) => {
128
+ notes: string;
129
+ version: string;
130
+ fromRef?: string;
131
+ toRef: string;
132
+ commitCount: number;
133
+ writtenPath?: string;
134
+ rangeLabel: string;
135
+ };
136
+ "changelog-lookup": (options: {
137
+ cwd?: string;
138
+ email?: string;
139
+ login?: string;
140
+ map?: string;
141
+ githubToken?: string;
142
+ fetch?: boolean;
143
+ }) => GithubAuthor;
144
+ };
145
+
71
146
  export type PublisherExports = {
72
147
  "publish-workspace": (options: {
73
148
  cwd?: string;
@@ -85,6 +160,7 @@ export type PublisherExports = {
85
160
  dryRun?: boolean;
86
161
  refresh?: boolean;
87
162
  only?: string;
163
+ packages?: string[];
88
164
  npm?: string;
89
165
  otp?: string;
90
166
  totpSecret?: string;
@@ -95,6 +171,7 @@ export type PublisherExports = {
95
171
  export type NiftyNative = {
96
172
  gitmoji: GitmojiExports;
97
173
  git: GitExports;
174
+ history: HistoryExports;
98
175
  publisher: PublisherExports;
99
176
  };
100
177
 
@@ -146,11 +223,80 @@ type NativeBinding = {
146
223
  dryRun?: boolean | null;
147
224
  refresh?: boolean | null;
148
225
  only?: string | null;
226
+ packages?: string[] | null;
149
227
  npm?: string | null;
150
228
  otp?: string | null;
151
229
  totpSecret?: string | null;
152
230
  token?: string | null;
153
231
  }) => TrustReport;
232
+ gitToolsRewordExport: (options: {
233
+ cwd?: string | null;
234
+ base: string;
235
+ ref?: string | null;
236
+ path: string;
237
+ }) => { count: number; path: string };
238
+ gitToolsRewordRewrite: (options: {
239
+ cwd?: string | null;
240
+ base: string;
241
+ ref?: string | null;
242
+ path: string;
243
+ dryRun?: boolean | null;
244
+ }) => {
245
+ changes: Array<{
246
+ oldOid: string;
247
+ oldSubject: string;
248
+ newSubject: string;
249
+ parentsRelinked: boolean;
250
+ messageChanged: boolean;
251
+ }>;
252
+ oldTip: string;
253
+ newTip?: string | null;
254
+ refName: string;
255
+ dryRun: boolean;
256
+ };
257
+ gitToolsRetimeRange: (options: {
258
+ cwd?: string | null;
259
+ commit: string;
260
+ startDate?: string | null;
261
+ endDate?: string | null;
262
+ branch?: string | null;
263
+ tip?: string | null;
264
+ }) => { branch: string; newTip: string; rewritten: number };
265
+ gitToolsRetimeRoot: (options: {
266
+ cwd?: string | null;
267
+ startDate?: string | null;
268
+ endDate?: string | null;
269
+ branch?: string | null;
270
+ tip?: string | null;
271
+ message?: string | null;
272
+ }) => { branch: string; newTip: string; rewritten: number };
273
+ gitToolsChangelogRender: (options: {
274
+ cwd?: string | null;
275
+ version?: string | null;
276
+ fromRef?: string | null;
277
+ toRef?: string | null;
278
+ write?: boolean | null;
279
+ tags?: boolean | null;
280
+ repo?: string | null;
281
+ authorMap?: string | null;
282
+ releasesDir?: string | null;
283
+ }) => {
284
+ notes: string;
285
+ version: string;
286
+ fromRef?: string | null;
287
+ toRef: string;
288
+ commitCount: number;
289
+ writtenPath?: string | null;
290
+ rangeLabel: string;
291
+ };
292
+ gitToolsChangelogLookup: (options: {
293
+ cwd?: string | null;
294
+ email?: string | null;
295
+ login?: string | null;
296
+ map?: string | null;
297
+ githubToken?: string | null;
298
+ fetch?: boolean | null;
299
+ }) => GithubAuthor;
154
300
  };
155
301
 
156
302
  const PLATFORM_PACKAGES: Record<string, string> = {
@@ -213,6 +359,82 @@ function wrapBinding(binding: NativeBinding): NiftyNative {
213
359
  "detect-github-repo": (repoRoot) => binding.gitDetectGithubRepo(repoRoot) ?? undefined,
214
360
  "parse-github-remote": (url) => binding.gitParseGithubRemote(url) ?? undefined,
215
361
  },
362
+ history: {
363
+ "reword-export": (options) =>
364
+ binding.gitToolsRewordExport({
365
+ ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),
366
+ base: options.base,
367
+ ...(options.ref !== undefined ? { ref: options.ref } : {}),
368
+ path: options.path,
369
+ }),
370
+ "reword-rewrite": (options) => {
371
+ const report = binding.gitToolsRewordRewrite({
372
+ ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),
373
+ base: options.base,
374
+ ...(options.ref !== undefined ? { ref: options.ref } : {}),
375
+ path: options.path,
376
+ ...(options.dryRun !== undefined ? { dryRun: options.dryRun } : {}),
377
+ });
378
+ return {
379
+ changes: report.changes,
380
+ oldTip: report.oldTip,
381
+ newTip: report.newTip ?? undefined,
382
+ refName: report.refName,
383
+ dryRun: report.dryRun,
384
+ };
385
+ },
386
+ "retime-range": (options) =>
387
+ binding.gitToolsRetimeRange({
388
+ ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),
389
+ commit: options.commit,
390
+ ...(options.startDate !== undefined ? { startDate: options.startDate } : {}),
391
+ ...(options.endDate !== undefined ? { endDate: options.endDate } : {}),
392
+ ...(options.branch !== undefined ? { branch: options.branch } : {}),
393
+ ...(options.tip !== undefined ? { tip: options.tip } : {}),
394
+ }),
395
+ "retime-root": (options) =>
396
+ binding.gitToolsRetimeRoot({
397
+ ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),
398
+ ...(options.startDate !== undefined ? { startDate: options.startDate } : {}),
399
+ ...(options.endDate !== undefined ? { endDate: options.endDate } : {}),
400
+ ...(options.branch !== undefined ? { branch: options.branch } : {}),
401
+ ...(options.tip !== undefined ? { tip: options.tip } : {}),
402
+ ...(options.message !== undefined ? { message: options.message } : {}),
403
+ }),
404
+ "changelog-render": (options) => {
405
+ const report = binding.gitToolsChangelogRender({
406
+ ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),
407
+ ...(options.version !== undefined ? { version: options.version } : {}),
408
+ ...(options.fromRef !== undefined ? { fromRef: options.fromRef } : {}),
409
+ ...(options.toRef !== undefined ? { toRef: options.toRef } : {}),
410
+ ...(options.write !== undefined ? { write: options.write } : {}),
411
+ ...(options.tags !== undefined ? { tags: options.tags } : {}),
412
+ ...(options.repo !== undefined ? { repo: options.repo } : {}),
413
+ ...(options.authorMap !== undefined ? { authorMap: options.authorMap } : {}),
414
+ ...(options.releasesDir !== undefined ? { releasesDir: options.releasesDir } : {}),
415
+ });
416
+ return {
417
+ notes: report.notes,
418
+ version: report.version,
419
+ fromRef: report.fromRef ?? undefined,
420
+ toRef: report.toRef,
421
+ commitCount: report.commitCount,
422
+ writtenPath: report.writtenPath ?? undefined,
423
+ rangeLabel: report.rangeLabel,
424
+ };
425
+ },
426
+ "changelog-lookup": (options) => {
427
+ const author = binding.gitToolsChangelogLookup({
428
+ ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),
429
+ ...(options.email !== undefined ? { email: options.email } : {}),
430
+ ...(options.login !== undefined ? { login: options.login } : {}),
431
+ ...(options.map !== undefined ? { map: options.map } : {}),
432
+ ...(options.githubToken !== undefined ? { githubToken: options.githubToken } : {}),
433
+ ...(options.fetch !== undefined ? { fetch: options.fetch } : {}),
434
+ });
435
+ return mapAuthor(author) ?? {};
436
+ },
437
+ },
216
438
  publisher: {
217
439
  "publish-workspace": (options) =>
218
440
  binding.publisherPublishWorkspace({
@@ -232,6 +454,7 @@ function wrapBinding(binding: NativeBinding): NiftyNative {
232
454
  ...(options.dryRun !== undefined ? { dryRun: options.dryRun } : {}),
233
455
  ...(options.refresh !== undefined ? { refresh: options.refresh } : {}),
234
456
  ...(options.only !== undefined ? { only: options.only } : {}),
457
+ ...(options.packages !== undefined ? { packages: options.packages } : {}),
235
458
  ...(options.npm !== undefined ? { npm: options.npm } : {}),
236
459
  ...(options.otp !== undefined ? { otp: options.otp } : {}),
237
460
  ...(options.totpSecret !== undefined ? { totpSecret: options.totpSecret } : {}),
package/Readme.md DELETED
@@ -1,30 +0,0 @@
1
- # @doki-land/nifty
2
-
3
- **Gitmoji is the default Nifty convention.**
4
-
5
- | Layer | Role |
6
- | --- | --- |
7
- | `@doki-land/nifty-<platform>` | Node-API `.node`(gitmoji + gix) |
8
- | `nifty-publisher` | Rust:`petgraph` 拓扑排序 + `npm publish` |
9
- | `src/cli/` | CLI 实现(`update` / `lint` / `check` / `upload` / `bump` / `publish`) |
10
- | `cli/nifty.mjs` | npm `bin` shim(jiti 加载 `src/cli`) |
11
- | `src/` | TypeScript API |
12
-
13
- Rust 侧无 `bin` / `cli`。
14
-
15
- **本仓开发**(pnpm workspace,`projects/packages/*`):
16
-
17
- ```bash
18
- pnpm install # 链接 @doki-land/nifty → node_modules/.bin/nifty
19
- pnpm run build:napi # 构建 native addon
20
- pnpm exec nifty bump
21
- pnpm exec nifty publish --dry-run
22
- ```
23
-
24
- **发布后消费**:
25
-
26
- ```bash
27
- npm install @doki-land/nifty
28
- nifty bump
29
- nifty publish --dry-run
30
- ```