@craftsamo/git-tools 0.2.1 → 0.2.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.
- package/.antigravity-plugin/plugin.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +18 -14
- package/dist/cli.js +33 -49
- package/dist/mcp.js +42 -60
- package/dist/opencode.js +41 -57
- package/package.json +1 -1
- package/plugin.yaml +3 -3
- package/skills/git-push/SKILL.md +2 -2
- package/skills/git-worktree/SKILL.md +2 -2
- package/src/hermes/git_tools_hermes/project.py +1 -1
package/README.md
CHANGED
|
@@ -303,22 +303,26 @@ Where a write is asked about, and where it is not:
|
|
|
303
303
|
Every entry point takes the same settings. A flag wins over its environment
|
|
304
304
|
variable, and an option or setting wins over the variable too.
|
|
305
305
|
|
|
306
|
-
| Setting | Flag | Variable | Meaning
|
|
307
|
-
| ---------------------- | ------------------------ | -------------------------------- |
|
|
308
|
-
| `toolsets` | `--toolsets` | `GIT_TOOLS_TOOLSETS` | the toolsets that are on, or `all`; default those `src/project.ts` names
|
|
309
|
-
| `read_only` | `--read-only` | `GIT_TOOLS_READ_ONLY` | registers no tool that writes; wins over every other setting
|
|
310
|
-
| `tools` | `--tools` | `GIT_TOOLS_TOOLS` | single tools to add by ID, whatever their toolset
|
|
311
|
-
| `exclude_tools` | `--exclude-tools` | `GIT_TOOLS_EXCLUDE_TOOLS` | single tools to remove by ID; wins over `tools` and `toolsets`
|
|
312
|
-
| `confirm` | `--confirm` | `GIT_TOOLS_CONFIRM` | MCP server only: `harness` (default) or `elicitation`, as the conventions say
|
|
313
|
-
| `language` | `--language` | `GIT_TOOLS_LANGUAGE` | native plugins only: the approval prompt's language, such as `ja`
|
|
314
|
-
| `emoji` | — | — | Hermes only: the emoji shown beside each toolset, by toolset name (`""` for none)
|
|
315
|
-
| `published_text_rules` | `--published-text-rules` | `GIT_TOOLS_PUBLISHED_TEXT_RULES` | the
|
|
316
|
-
| `worktree_root` | `--worktree-root` | `GIT_TOOLS_WORKTREE_ROOT` | the
|
|
306
|
+
| Setting | Flag | Variable | Meaning |
|
|
307
|
+
| ---------------------- | ------------------------ | -------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
308
|
+
| `toolsets` | `--toolsets` | `GIT_TOOLS_TOOLSETS` | the toolsets that are on, or `all`; default those `src/project.ts` names |
|
|
309
|
+
| `read_only` | `--read-only` | `GIT_TOOLS_READ_ONLY` | registers no tool that writes; wins over every other setting |
|
|
310
|
+
| `tools` | `--tools` | `GIT_TOOLS_TOOLS` | single tools to add by ID, whatever their toolset |
|
|
311
|
+
| `exclude_tools` | `--exclude-tools` | `GIT_TOOLS_EXCLUDE_TOOLS` | single tools to remove by ID; wins over `tools` and `toolsets` |
|
|
312
|
+
| `confirm` | `--confirm` | `GIT_TOOLS_CONFIRM` | MCP server only: `harness` (default) or `elicitation`, as the conventions say |
|
|
313
|
+
| `language` | `--language` | `GIT_TOOLS_LANGUAGE` | native plugins only: the approval prompt's language, such as `ja` |
|
|
314
|
+
| `emoji` | — | — | Hermes only: the emoji shown beside each toolset, by toolset name (`""` for none) |
|
|
315
|
+
| `published_text_rules` | `--published-text-rules` | `GIT_TOOLS_PUBLISHED_TEXT_RULES` | the path of a JSON file of published-text rules (see the push toolset); unset, nothing is checked |
|
|
316
|
+
| `worktree_root` | `--worktree-root` | `GIT_TOOLS_WORKTREE_ROOT` | the path where task worktrees go; unset, `~/worktrees` |
|
|
317
317
|
|
|
318
318
|
Lists are comma-separated in a flag or a variable. A package's own settings,
|
|
319
319
|
listed in `options` in `src/project.ts`, take a row each here and are read the
|
|
320
|
-
same way
|
|
321
|
-
|
|
320
|
+
same way. A `path` is trimmed; `~` and `~/…` (also with the platform separator)
|
|
321
|
+
stand for the home directory (`HOME` when it is absolute, else the account's).
|
|
322
|
+
It must then be absolute and reaches the tool normalized, without a filesystem
|
|
323
|
+
check. Blank paths count as unset. Refused values are `invalid_argument`, naming
|
|
324
|
+
the flag, variable or option and what it must be. Hermes passes paths to the
|
|
325
|
+
command line, which checks them. The layout is
|
|
322
326
|
`<root>/<repository>/<branch>`, with each `/` of the branch written `-`; the
|
|
323
327
|
repository is the last part of `origin`'s URL without `.git`, else the folder
|
|
324
328
|
name of the main checkout. Where each harness reads them:
|
|
@@ -339,7 +343,7 @@ name of the main checkout. Where each harness reads them:
|
|
|
339
343
|
settings:
|
|
340
344
|
read_only: false
|
|
341
345
|
exclude_tools: []
|
|
342
|
-
published_text_rules:
|
|
346
|
+
published_text_rules: /home/me/.config/git-tools/published-text.json
|
|
343
347
|
worktree_root: ~/worktrees
|
|
344
348
|
```
|
|
345
349
|
|
package/dist/cli.js
CHANGED
|
@@ -27,7 +27,7 @@ var PROJECT = {
|
|
|
27
27
|
/** The toolsets on when a setting names none. */
|
|
28
28
|
defaultToolsets: ["repo", "commit", "rebase"],
|
|
29
29
|
/** The package's own settings, which the tools themselves read: each snake_case name and its type, with bounds when it needs them. */
|
|
30
|
-
options: { published_text_rules: "
|
|
30
|
+
options: { published_text_rules: "path", worktree_root: "path" },
|
|
31
31
|
/** The environment variables the tools read besides the settings, which Codex forwards to the server after them. */
|
|
32
32
|
toolVariables: [
|
|
33
33
|
"LANGUAGE",
|
|
@@ -5135,7 +5135,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
5135
5135
|
var NONE = 0;
|
|
5136
5136
|
var ASSUMED = 1;
|
|
5137
5137
|
var PROVEN = 2;
|
|
5138
|
-
function isRecursive(inst, stack,
|
|
5138
|
+
function isRecursive(inst, stack, resolve3) {
|
|
5139
5139
|
const cached2 = recursive.get(inst);
|
|
5140
5140
|
if (cached2 !== void 0)
|
|
5141
5141
|
return cached2 ? PROVEN : NONE;
|
|
@@ -5145,7 +5145,7 @@ function isRecursive(inst, stack, resolve5) {
|
|
|
5145
5145
|
let result = NONE;
|
|
5146
5146
|
const check2 = (child) => {
|
|
5147
5147
|
if (result !== PROVEN && child?._zod) {
|
|
5148
|
-
const answer = isRecursive(child, stack,
|
|
5148
|
+
const answer = isRecursive(child, stack, resolve3);
|
|
5149
5149
|
if (answer > result)
|
|
5150
5150
|
result = answer;
|
|
5151
5151
|
}
|
|
@@ -5156,7 +5156,7 @@ function isRecursive(inst, stack, resolve5) {
|
|
|
5156
5156
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
5157
5157
|
if (spread && !desc.enumerable)
|
|
5158
5158
|
continue;
|
|
5159
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
5159
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve3) : NONE;
|
|
5160
5160
|
if (child > answer)
|
|
5161
5161
|
answer = child;
|
|
5162
5162
|
}
|
|
@@ -5220,7 +5220,7 @@ function isRecursive(inst, stack, resolve5) {
|
|
|
5220
5220
|
break;
|
|
5221
5221
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
5222
5222
|
case "lazy": {
|
|
5223
|
-
const inner = def._cachedInner ?? (
|
|
5223
|
+
const inner = def._cachedInner ?? (resolve3 ? inst._zod.innerType : void 0);
|
|
5224
5224
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
5225
5225
|
break;
|
|
5226
5226
|
}
|
|
@@ -19829,7 +19829,7 @@ function abortError(signal) {
|
|
|
19829
19829
|
}
|
|
19830
19830
|
function exec(argv, options) {
|
|
19831
19831
|
const { signal } = options;
|
|
19832
|
-
return new Promise((
|
|
19832
|
+
return new Promise((resolve3, reject) => {
|
|
19833
19833
|
if (signal?.aborted) {
|
|
19834
19834
|
reject(abortError(signal));
|
|
19835
19835
|
return;
|
|
@@ -19888,7 +19888,7 @@ function exec(argv, options) {
|
|
|
19888
19888
|
}
|
|
19889
19889
|
const finish = () => settle2(() => {
|
|
19890
19890
|
const { code, killedBy } = exitedWith ?? { code: null, killedBy: null };
|
|
19891
|
-
|
|
19891
|
+
resolve3({
|
|
19892
19892
|
code: code ?? -1,
|
|
19893
19893
|
stdout,
|
|
19894
19894
|
stderr,
|
|
@@ -22788,7 +22788,7 @@ async function compareBranch(root, remote, selected, expect, signal) {
|
|
|
22788
22788
|
|
|
22789
22789
|
// src/core/push/published-text.ts
|
|
22790
22790
|
import { readFile as readFile2, stat as stat6 } from "node:fs/promises";
|
|
22791
|
-
import { isAbsolute as isAbsolute4
|
|
22791
|
+
import { isAbsolute as isAbsolute4 } from "node:path";
|
|
22792
22792
|
|
|
22793
22793
|
// src/core/describe.ts
|
|
22794
22794
|
var MAX_FACTS = 8;
|
|
@@ -22925,19 +22925,6 @@ async function wholeCallDescription(spec, args, ctx) {
|
|
|
22925
22925
|
return { ...headline2 && { headline: headline2 }, facts, ...text && { text }, ...kept2 };
|
|
22926
22926
|
}
|
|
22927
22927
|
|
|
22928
|
-
// src/core/home.ts
|
|
22929
|
-
import { homedir } from "node:os";
|
|
22930
|
-
import { join as join5 } from "node:path";
|
|
22931
|
-
var HOME_MARK = "~";
|
|
22932
|
-
var HOME_PREFIX = "~/";
|
|
22933
|
-
function homeDirectory() {
|
|
22934
|
-
return process.env.HOME?.trim() || homedir();
|
|
22935
|
-
}
|
|
22936
|
-
function expandHome(value) {
|
|
22937
|
-
if (value === HOME_MARK) return homeDirectory();
|
|
22938
|
-
return value.startsWith(HOME_PREFIX) ? join5(homeDirectory(), value.slice(HOME_PREFIX.length)) : value;
|
|
22939
|
-
}
|
|
22940
|
-
|
|
22941
22928
|
// src/core/push/published-text.ts
|
|
22942
22929
|
var PUBLISHED_TEXT_RULES_OPTION = "published_text_rules";
|
|
22943
22930
|
var MAX_FILE_BYTES = 64 * 1024;
|
|
@@ -23010,11 +22997,8 @@ async function loadPublishedTextRules(options, signal) {
|
|
|
23010
22997
|
const option = options?.[PUBLISHED_TEXT_RULES_OPTION];
|
|
23011
22998
|
const path = typeof option === "string" ? option.trim() : void 0;
|
|
23012
22999
|
if (!path) return [];
|
|
23013
|
-
|
|
23014
|
-
|
|
23015
|
-
throw invalidRules(path, `the value must be an absolute path, or start with ${HOME_PREFIX}`);
|
|
23016
|
-
const normalized = resolve2(expanded);
|
|
23017
|
-
return compileRules(normalized, parseRulesJson(normalized, await readRulesFile(normalized, signal)));
|
|
23000
|
+
if (!isAbsolute4(path)) throw invalidRules(path, "the value must be an absolute path");
|
|
23001
|
+
return compileRules(path, parseRulesJson(path, await readRulesFile(path, signal)));
|
|
23018
23002
|
}
|
|
23019
23003
|
var publishedTextFindingSchema = external_exports.object({
|
|
23020
23004
|
rule: external_exports.string().describe("The name of the rule that matched."),
|
|
@@ -23968,11 +23952,11 @@ var rebaseRead = defineTool({
|
|
|
23968
23952
|
// src/core/rebase/resume.ts
|
|
23969
23953
|
import { createHash as createHash3 } from "node:crypto";
|
|
23970
23954
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
23971
|
-
import { join as
|
|
23955
|
+
import { join as join7 } from "node:path";
|
|
23972
23956
|
|
|
23973
23957
|
// src/core/conflicts.ts
|
|
23974
23958
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
23975
|
-
import { basename as basename2, join as
|
|
23959
|
+
import { basename as basename2, join as join5 } from "node:path";
|
|
23976
23960
|
var REGION_MAX = 20;
|
|
23977
23961
|
var SIDE_LINES_MAX = 40;
|
|
23978
23962
|
var LOCKFILES = {
|
|
@@ -24084,7 +24068,7 @@ async function readConflictFile(root, path, xy, operation) {
|
|
|
24084
24068
|
}
|
|
24085
24069
|
let text;
|
|
24086
24070
|
try {
|
|
24087
|
-
text = await readFile3(
|
|
24071
|
+
text = await readFile3(join5(root, path), "utf8");
|
|
24088
24072
|
} catch {
|
|
24089
24073
|
return { ...file2, region_count: 0, regions: [] };
|
|
24090
24074
|
}
|
|
@@ -24167,13 +24151,13 @@ var rebaseOutcomeSchema = external_exports.object({
|
|
|
24167
24151
|
|
|
24168
24152
|
// src/core/rebase/rebase-state.ts
|
|
24169
24153
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
24170
|
-
import { join as
|
|
24154
|
+
import { join as join6 } from "node:path";
|
|
24171
24155
|
var HEADS_PREFIX = "refs/heads/";
|
|
24172
24156
|
var STATE_DIRS = ["rebase-merge", "rebase-apply"];
|
|
24173
24157
|
var UPDATE_REFS_LINES = 3;
|
|
24174
24158
|
async function readStateFile(dir, name) {
|
|
24175
24159
|
try {
|
|
24176
|
-
return (await readFile4(
|
|
24160
|
+
return (await readFile4(join6(dir, name), "utf8")).trim();
|
|
24177
24161
|
} catch {
|
|
24178
24162
|
return void 0;
|
|
24179
24163
|
}
|
|
@@ -24348,7 +24332,7 @@ async function conflictedFiles(root, signal) {
|
|
|
24348
24332
|
for (const path of await unmergedPaths(root, signal)) {
|
|
24349
24333
|
let content;
|
|
24350
24334
|
try {
|
|
24351
|
-
content = await readFile5(
|
|
24335
|
+
content = await readFile5(join7(root, path));
|
|
24352
24336
|
} catch {
|
|
24353
24337
|
content = null;
|
|
24354
24338
|
}
|
|
@@ -25347,7 +25331,8 @@ var repoRead = defineTool({
|
|
|
25347
25331
|
import { lstat } from "node:fs/promises";
|
|
25348
25332
|
|
|
25349
25333
|
// src/core/worktree/layout.ts
|
|
25350
|
-
import {
|
|
25334
|
+
import { homedir } from "node:os";
|
|
25335
|
+
import { basename as basename3, dirname as dirname3, isAbsolute as isAbsolute5, join as join8 } from "node:path";
|
|
25351
25336
|
var WORKTREE_ROOT_OPTION = "worktree_root";
|
|
25352
25337
|
var DEFAULT_ROOT_FOLDER = "worktrees";
|
|
25353
25338
|
var GIT_DIRECTORY = ".git";
|
|
@@ -25358,15 +25343,14 @@ var NOT_A_NAME = [".", ".."];
|
|
|
25358
25343
|
function worktreeRoot(ctx) {
|
|
25359
25344
|
const option = ctx.options?.[WORKTREE_ROOT_OPTION];
|
|
25360
25345
|
const value = typeof option === "string" ? option.trim() : void 0;
|
|
25361
|
-
if (!value) return
|
|
25362
|
-
|
|
25363
|
-
if (!isAbsolute5(expanded)) {
|
|
25346
|
+
if (!value) return join8(process.env.HOME?.trim() || homedir(), DEFAULT_ROOT_FOLDER);
|
|
25347
|
+
if (!isAbsolute5(value)) {
|
|
25364
25348
|
throw new ToolError(
|
|
25365
25349
|
"invalid_argument",
|
|
25366
|
-
`The ${WORKTREE_ROOT_OPTION} setting (${value}): the value must be an absolute path
|
|
25350
|
+
`The ${WORKTREE_ROOT_OPTION} setting (${value}): the value must be an absolute path.`
|
|
25367
25351
|
);
|
|
25368
25352
|
}
|
|
25369
|
-
return
|
|
25353
|
+
return value;
|
|
25370
25354
|
}
|
|
25371
25355
|
async function mainCheckout(root, signal) {
|
|
25372
25356
|
const common = (await git(["rev-parse", "--path-format=absolute", "--git-common-dir"], { cwd: root, signal })).trim();
|
|
@@ -25382,7 +25366,7 @@ async function repositoryName(root, signal) {
|
|
|
25382
25366
|
return fromUrl || basename3(await mainCheckout(root, signal)).replace(GIT_SUFFIX, "");
|
|
25383
25367
|
}
|
|
25384
25368
|
function worktreePath(root, repository, branch) {
|
|
25385
|
-
return
|
|
25369
|
+
return join8(root, repository, branch.replaceAll("/", "-"));
|
|
25386
25370
|
}
|
|
25387
25371
|
|
|
25388
25372
|
// src/core/worktree/add-plan.ts
|
|
@@ -25645,7 +25629,7 @@ var worktreeAdd = defineTool({
|
|
|
25645
25629
|
});
|
|
25646
25630
|
|
|
25647
25631
|
// src/core/worktree/list.ts
|
|
25648
|
-
import { dirname as dirname5, join as
|
|
25632
|
+
import { dirname as dirname5, join as join9 } from "node:path";
|
|
25649
25633
|
var worktreeSchema = external_exports.object({
|
|
25650
25634
|
directory: external_exports.string().describe("The worktree's directory: its real path when it exists, else as git prints it."),
|
|
25651
25635
|
branch: external_exports.string().nullable().describe("The checked-out branch's name; null when HEAD is detached or bare."),
|
|
@@ -25680,7 +25664,7 @@ async function readWorktreeList(callerRoot, root, signal) {
|
|
|
25680
25664
|
const repository = await repositoryName(callerRoot, signal);
|
|
25681
25665
|
const [caller, layoutFolder, entries] = await Promise.all([
|
|
25682
25666
|
realpathOrSelf(callerRoot),
|
|
25683
|
-
realpathOfExisting(
|
|
25667
|
+
realpathOfExisting(join9(root, repository)),
|
|
25684
25668
|
listWorktrees(callerRoot, signal)
|
|
25685
25669
|
]);
|
|
25686
25670
|
return {
|
|
@@ -25742,7 +25726,7 @@ async function removeDescription(plan, signal) {
|
|
|
25742
25726
|
}
|
|
25743
25727
|
|
|
25744
25728
|
// src/core/worktree/remove-plan.ts
|
|
25745
|
-
import { resolve as
|
|
25729
|
+
import { resolve as resolve2 } from "node:path";
|
|
25746
25730
|
|
|
25747
25731
|
// src/core/worktree/remove-checks.ts
|
|
25748
25732
|
var MAX_LISTED_FILES = 50;
|
|
@@ -25816,7 +25800,7 @@ async function targetOf2(request) {
|
|
|
25816
25800
|
if (request.directory.trim() === "") {
|
|
25817
25801
|
throw invalid3("directory is blank; pass the directory of the worktree to remove.");
|
|
25818
25802
|
}
|
|
25819
|
-
return realpathOfExisting(
|
|
25803
|
+
return realpathOfExisting(resolve2(request.callerRoot, request.directory));
|
|
25820
25804
|
}
|
|
25821
25805
|
async function findWorktree(request, target) {
|
|
25822
25806
|
for (const entry of await listWorktrees(request.callerRoot, request.signal)) {
|
|
@@ -25859,7 +25843,7 @@ async function planRemove(request) {
|
|
|
25859
25843
|
|
|
25860
25844
|
// src/core/worktree/remove-run.ts
|
|
25861
25845
|
import { rmdir } from "node:fs/promises";
|
|
25862
|
-
import { dirname as dirname6, join as
|
|
25846
|
+
import { dirname as dirname6, join as join10 } from "node:path";
|
|
25863
25847
|
|
|
25864
25848
|
// src/core/worktree/landed.ts
|
|
25865
25849
|
var LANDED_READ_TIMEOUT_MS = PROTECTION_READ_TIMEOUT_MS;
|
|
@@ -25941,7 +25925,7 @@ async function removeWorktreeRecord(request, plan) {
|
|
|
25941
25925
|
}
|
|
25942
25926
|
async function removeEmptyLayoutFolder(request, plan) {
|
|
25943
25927
|
const { callerRoot, worktreeRoot: worktreeRoot2, signal } = request;
|
|
25944
|
-
const folder = await realpathOfExisting(
|
|
25928
|
+
const folder = await realpathOfExisting(join10(worktreeRoot2, await repositoryName(callerRoot, signal)));
|
|
25945
25929
|
const parent = dirname6(plan.directory);
|
|
25946
25930
|
if (await realpathOfExisting(parent) !== folder) return;
|
|
25947
25931
|
try {
|
|
@@ -26404,9 +26388,9 @@ async function timedCallDescription(spec, args, ctx, timeoutMs = DESCRIBE_TIMEOU
|
|
|
26404
26388
|
let timer;
|
|
26405
26389
|
let onAbort;
|
|
26406
26390
|
try {
|
|
26407
|
-
const timedOut = new Promise((
|
|
26391
|
+
const timedOut = new Promise((resolve3) => {
|
|
26408
26392
|
timer = setTimeout(() => {
|
|
26409
|
-
|
|
26393
|
+
resolve3(void 0);
|
|
26410
26394
|
controller.abort();
|
|
26411
26395
|
}, timeoutMs);
|
|
26412
26396
|
});
|
|
@@ -26461,7 +26445,7 @@ var PROJECT_PROFILE = {
|
|
|
26461
26445
|
|
|
26462
26446
|
// src/entry/settings.ts
|
|
26463
26447
|
import { homedir as homedir2 } from "node:os";
|
|
26464
|
-
import { isAbsolute as isAbsolute6, join as
|
|
26448
|
+
import { isAbsolute as isAbsolute6, join as join11, resolve as resolvePath, sep as sep3 } from "node:path";
|
|
26465
26449
|
var CONFIRM_MODES = ["harness", "elicitation"];
|
|
26466
26450
|
var ALL_TOOLSETS = "all";
|
|
26467
26451
|
var TRUE_VALUES = ["1", "true"];
|
|
@@ -26555,7 +26539,7 @@ function parseNumber(value, source) {
|
|
|
26555
26539
|
}
|
|
26556
26540
|
function absolutePath(text, source, env) {
|
|
26557
26541
|
const home = env.HOME !== void 0 && isAbsolute6(env.HOME) ? env.HOME : homedir2();
|
|
26558
|
-
const expanded = text === "~" || text.startsWith("~/") || text.startsWith(`~${sep3}`) ?
|
|
26542
|
+
const expanded = text === "~" || text.startsWith("~/") || text.startsWith(`~${sep3}`) ? join11(home, text.slice(1)) : text;
|
|
26559
26543
|
if (!isAbsolute6(expanded)) throw new ToolError("invalid_argument", `${source} must be an absolute path.`);
|
|
26560
26544
|
return resolvePath(expanded);
|
|
26561
26545
|
}
|
package/dist/mcp.js
CHANGED
|
@@ -2984,7 +2984,7 @@ var require_compile = __commonJS({
|
|
|
2984
2984
|
const schOrFunc = root.refs[ref];
|
|
2985
2985
|
if (schOrFunc)
|
|
2986
2986
|
return schOrFunc;
|
|
2987
|
-
let _sch =
|
|
2987
|
+
let _sch = resolve3.call(this, root, ref);
|
|
2988
2988
|
if (_sch === void 0) {
|
|
2989
2989
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
2990
2990
|
const { schemaId } = this.opts;
|
|
@@ -3011,7 +3011,7 @@ var require_compile = __commonJS({
|
|
|
3011
3011
|
function sameSchemaEnv(s1, s2) {
|
|
3012
3012
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3013
3013
|
}
|
|
3014
|
-
function
|
|
3014
|
+
function resolve3(root, ref) {
|
|
3015
3015
|
let sch;
|
|
3016
3016
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3017
3017
|
ref = sch;
|
|
@@ -3875,7 +3875,7 @@ var require_fast_uri = __commonJS({
|
|
|
3875
3875
|
}
|
|
3876
3876
|
return uri;
|
|
3877
3877
|
}
|
|
3878
|
-
function
|
|
3878
|
+
function resolve3(baseURI, relativeURI, options) {
|
|
3879
3879
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3880
3880
|
const {
|
|
3881
3881
|
parsed: baseParsed,
|
|
@@ -4266,7 +4266,7 @@ var require_fast_uri = __commonJS({
|
|
|
4266
4266
|
var fastUri = {
|
|
4267
4267
|
SCHEMES,
|
|
4268
4268
|
normalize,
|
|
4269
|
-
resolve:
|
|
4269
|
+
resolve: resolve3,
|
|
4270
4270
|
resolveComponent,
|
|
4271
4271
|
equal,
|
|
4272
4272
|
serialize,
|
|
@@ -12325,7 +12325,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
12325
12325
|
var NONE = 0;
|
|
12326
12326
|
var ASSUMED = 1;
|
|
12327
12327
|
var PROVEN = 2;
|
|
12328
|
-
function isRecursive(inst, stack,
|
|
12328
|
+
function isRecursive(inst, stack, resolve3) {
|
|
12329
12329
|
const cached2 = recursive.get(inst);
|
|
12330
12330
|
if (cached2 !== void 0)
|
|
12331
12331
|
return cached2 ? PROVEN : NONE;
|
|
@@ -12335,7 +12335,7 @@ function isRecursive(inst, stack, resolve5) {
|
|
|
12335
12335
|
let result = NONE;
|
|
12336
12336
|
const check2 = (child) => {
|
|
12337
12337
|
if (result !== PROVEN && child?._zod) {
|
|
12338
|
-
const answer = isRecursive(child, stack,
|
|
12338
|
+
const answer = isRecursive(child, stack, resolve3);
|
|
12339
12339
|
if (answer > result)
|
|
12340
12340
|
result = answer;
|
|
12341
12341
|
}
|
|
@@ -12346,7 +12346,7 @@ function isRecursive(inst, stack, resolve5) {
|
|
|
12346
12346
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
12347
12347
|
if (spread && !desc.enumerable)
|
|
12348
12348
|
continue;
|
|
12349
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
12349
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve3) : NONE;
|
|
12350
12350
|
if (child > answer)
|
|
12351
12351
|
answer = child;
|
|
12352
12352
|
}
|
|
@@ -12410,7 +12410,7 @@ function isRecursive(inst, stack, resolve5) {
|
|
|
12410
12410
|
break;
|
|
12411
12411
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
12412
12412
|
case "lazy": {
|
|
12413
|
-
const inner = def._cachedInner ?? (
|
|
12413
|
+
const inner = def._cachedInner ?? (resolve3 ? inst._zod.innerType : void 0);
|
|
12414
12414
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
12415
12415
|
break;
|
|
12416
12416
|
}
|
|
@@ -28587,12 +28587,12 @@ var StdioServerTransport = class {
|
|
|
28587
28587
|
this.onclose?.();
|
|
28588
28588
|
}
|
|
28589
28589
|
send(message) {
|
|
28590
|
-
return new Promise((
|
|
28590
|
+
return new Promise((resolve3) => {
|
|
28591
28591
|
const json2 = serializeMessage(message);
|
|
28592
28592
|
if (this._stdout.write(json2)) {
|
|
28593
|
-
|
|
28593
|
+
resolve3();
|
|
28594
28594
|
} else {
|
|
28595
|
-
this._stdout.once("drain",
|
|
28595
|
+
this._stdout.once("drain", resolve3);
|
|
28596
28596
|
}
|
|
28597
28597
|
});
|
|
28598
28598
|
}
|
|
@@ -28639,7 +28639,7 @@ function abortError(signal) {
|
|
|
28639
28639
|
}
|
|
28640
28640
|
function exec(argv, options) {
|
|
28641
28641
|
const { signal } = options;
|
|
28642
|
-
return new Promise((
|
|
28642
|
+
return new Promise((resolve3, reject) => {
|
|
28643
28643
|
if (signal?.aborted) {
|
|
28644
28644
|
reject(abortError(signal));
|
|
28645
28645
|
return;
|
|
@@ -28698,7 +28698,7 @@ function exec(argv, options) {
|
|
|
28698
28698
|
}
|
|
28699
28699
|
const finish = () => settle2(() => {
|
|
28700
28700
|
const { code, killedBy } = exitedWith ?? { code: null, killedBy: null };
|
|
28701
|
-
|
|
28701
|
+
resolve3({
|
|
28702
28702
|
code: code ?? -1,
|
|
28703
28703
|
stdout,
|
|
28704
28704
|
stderr,
|
|
@@ -29113,7 +29113,7 @@ var PROJECT = {
|
|
|
29113
29113
|
/** The toolsets on when a setting names none. */
|
|
29114
29114
|
defaultToolsets: ["repo", "commit", "rebase"],
|
|
29115
29115
|
/** The package's own settings, which the tools themselves read: each snake_case name and its type, with bounds when it needs them. */
|
|
29116
|
-
options: { published_text_rules: "
|
|
29116
|
+
options: { published_text_rules: "path", worktree_root: "path" },
|
|
29117
29117
|
/** The environment variables the tools read besides the settings, which Codex forwards to the server after them. */
|
|
29118
29118
|
toolVariables: [
|
|
29119
29119
|
"LANGUAGE",
|
|
@@ -31857,22 +31857,7 @@ async function compareBranch(root, remote, selected, expect, signal) {
|
|
|
31857
31857
|
|
|
31858
31858
|
// src/core/push/published-text.ts
|
|
31859
31859
|
import { readFile as readFile2, stat as stat6 } from "node:fs/promises";
|
|
31860
|
-
import { isAbsolute as isAbsolute5
|
|
31861
|
-
|
|
31862
|
-
// src/core/home.ts
|
|
31863
|
-
import { homedir as homedir2 } from "node:os";
|
|
31864
|
-
import { join as join6 } from "node:path";
|
|
31865
|
-
var HOME_MARK = "~";
|
|
31866
|
-
var HOME_PREFIX = "~/";
|
|
31867
|
-
function homeDirectory() {
|
|
31868
|
-
return process.env.HOME?.trim() || homedir2();
|
|
31869
|
-
}
|
|
31870
|
-
function expandHome(value) {
|
|
31871
|
-
if (value === HOME_MARK) return homeDirectory();
|
|
31872
|
-
return value.startsWith(HOME_PREFIX) ? join6(homeDirectory(), value.slice(HOME_PREFIX.length)) : value;
|
|
31873
|
-
}
|
|
31874
|
-
|
|
31875
|
-
// src/core/push/published-text.ts
|
|
31860
|
+
import { isAbsolute as isAbsolute5 } from "node:path";
|
|
31876
31861
|
var PUBLISHED_TEXT_RULES_OPTION = "published_text_rules";
|
|
31877
31862
|
var MAX_FILE_BYTES = 64 * 1024;
|
|
31878
31863
|
var MAX_RULES = 100;
|
|
@@ -31944,11 +31929,8 @@ async function loadPublishedTextRules(options, signal) {
|
|
|
31944
31929
|
const option = options?.[PUBLISHED_TEXT_RULES_OPTION];
|
|
31945
31930
|
const path = typeof option === "string" ? option.trim() : void 0;
|
|
31946
31931
|
if (!path) return [];
|
|
31947
|
-
|
|
31948
|
-
|
|
31949
|
-
throw invalidRules(path, `the value must be an absolute path, or start with ${HOME_PREFIX}`);
|
|
31950
|
-
const normalized = resolve2(expanded);
|
|
31951
|
-
return compileRules(normalized, parseRulesJson(normalized, await readRulesFile(normalized, signal)));
|
|
31932
|
+
if (!isAbsolute5(path)) throw invalidRules(path, "the value must be an absolute path");
|
|
31933
|
+
return compileRules(path, parseRulesJson(path, await readRulesFile(path, signal)));
|
|
31952
31934
|
}
|
|
31953
31935
|
var publishedTextFindingSchema = external_exports.object({
|
|
31954
31936
|
rule: external_exports.string().describe("The name of the rule that matched."),
|
|
@@ -32902,11 +32884,11 @@ var rebaseRead = defineTool({
|
|
|
32902
32884
|
// src/core/rebase/resume.ts
|
|
32903
32885
|
import { createHash as createHash3 } from "node:crypto";
|
|
32904
32886
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
32905
|
-
import { join as
|
|
32887
|
+
import { join as join8 } from "node:path";
|
|
32906
32888
|
|
|
32907
32889
|
// src/core/conflicts.ts
|
|
32908
32890
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
32909
|
-
import { basename as basename2, join as
|
|
32891
|
+
import { basename as basename2, join as join6 } from "node:path";
|
|
32910
32892
|
var REGION_MAX = 20;
|
|
32911
32893
|
var SIDE_LINES_MAX = 40;
|
|
32912
32894
|
var LOCKFILES = {
|
|
@@ -33018,7 +33000,7 @@ async function readConflictFile(root, path, xy, operation) {
|
|
|
33018
33000
|
}
|
|
33019
33001
|
let text;
|
|
33020
33002
|
try {
|
|
33021
|
-
text = await readFile3(
|
|
33003
|
+
text = await readFile3(join6(root, path), "utf8");
|
|
33022
33004
|
} catch {
|
|
33023
33005
|
return { ...file2, region_count: 0, regions: [] };
|
|
33024
33006
|
}
|
|
@@ -33101,13 +33083,13 @@ var rebaseOutcomeSchema = external_exports.object({
|
|
|
33101
33083
|
|
|
33102
33084
|
// src/core/rebase/rebase-state.ts
|
|
33103
33085
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
33104
|
-
import { join as
|
|
33086
|
+
import { join as join7 } from "node:path";
|
|
33105
33087
|
var HEADS_PREFIX = "refs/heads/";
|
|
33106
33088
|
var STATE_DIRS = ["rebase-merge", "rebase-apply"];
|
|
33107
33089
|
var UPDATE_REFS_LINES = 3;
|
|
33108
33090
|
async function readStateFile(dir, name) {
|
|
33109
33091
|
try {
|
|
33110
|
-
return (await readFile4(
|
|
33092
|
+
return (await readFile4(join7(dir, name), "utf8")).trim();
|
|
33111
33093
|
} catch {
|
|
33112
33094
|
return void 0;
|
|
33113
33095
|
}
|
|
@@ -33282,7 +33264,7 @@ async function conflictedFiles(root, signal) {
|
|
|
33282
33264
|
for (const path of await unmergedPaths(root, signal)) {
|
|
33283
33265
|
let content;
|
|
33284
33266
|
try {
|
|
33285
|
-
content = await readFile5(
|
|
33267
|
+
content = await readFile5(join8(root, path));
|
|
33286
33268
|
} catch {
|
|
33287
33269
|
content = null;
|
|
33288
33270
|
}
|
|
@@ -34281,7 +34263,8 @@ var repoRead = defineTool({
|
|
|
34281
34263
|
import { lstat } from "node:fs/promises";
|
|
34282
34264
|
|
|
34283
34265
|
// src/core/worktree/layout.ts
|
|
34284
|
-
import {
|
|
34266
|
+
import { homedir as homedir2 } from "node:os";
|
|
34267
|
+
import { basename as basename3, dirname as dirname3, isAbsolute as isAbsolute6, join as join9 } from "node:path";
|
|
34285
34268
|
var WORKTREE_ROOT_OPTION = "worktree_root";
|
|
34286
34269
|
var DEFAULT_ROOT_FOLDER = "worktrees";
|
|
34287
34270
|
var GIT_DIRECTORY = ".git";
|
|
@@ -34292,15 +34275,14 @@ var NOT_A_NAME = [".", ".."];
|
|
|
34292
34275
|
function worktreeRoot(ctx) {
|
|
34293
34276
|
const option = ctx.options?.[WORKTREE_ROOT_OPTION];
|
|
34294
34277
|
const value = typeof option === "string" ? option.trim() : void 0;
|
|
34295
|
-
if (!value) return
|
|
34296
|
-
|
|
34297
|
-
if (!isAbsolute6(expanded)) {
|
|
34278
|
+
if (!value) return join9(process.env.HOME?.trim() || homedir2(), DEFAULT_ROOT_FOLDER);
|
|
34279
|
+
if (!isAbsolute6(value)) {
|
|
34298
34280
|
throw new ToolError(
|
|
34299
34281
|
"invalid_argument",
|
|
34300
|
-
`The ${WORKTREE_ROOT_OPTION} setting (${value}): the value must be an absolute path
|
|
34282
|
+
`The ${WORKTREE_ROOT_OPTION} setting (${value}): the value must be an absolute path.`
|
|
34301
34283
|
);
|
|
34302
34284
|
}
|
|
34303
|
-
return
|
|
34285
|
+
return value;
|
|
34304
34286
|
}
|
|
34305
34287
|
async function mainCheckout(root, signal) {
|
|
34306
34288
|
const common = (await git(["rev-parse", "--path-format=absolute", "--git-common-dir"], { cwd: root, signal })).trim();
|
|
@@ -34316,7 +34298,7 @@ async function repositoryName(root, signal) {
|
|
|
34316
34298
|
return fromUrl || basename3(await mainCheckout(root, signal)).replace(GIT_SUFFIX, "");
|
|
34317
34299
|
}
|
|
34318
34300
|
function worktreePath(root, repository, branch) {
|
|
34319
|
-
return
|
|
34301
|
+
return join9(root, repository, branch.replaceAll("/", "-"));
|
|
34320
34302
|
}
|
|
34321
34303
|
|
|
34322
34304
|
// src/core/worktree/add-plan.ts
|
|
@@ -34579,7 +34561,7 @@ var worktreeAdd = defineTool({
|
|
|
34579
34561
|
});
|
|
34580
34562
|
|
|
34581
34563
|
// src/core/worktree/list.ts
|
|
34582
|
-
import { dirname as dirname5, join as
|
|
34564
|
+
import { dirname as dirname5, join as join10 } from "node:path";
|
|
34583
34565
|
var worktreeSchema = external_exports.object({
|
|
34584
34566
|
directory: external_exports.string().describe("The worktree's directory: its real path when it exists, else as git prints it."),
|
|
34585
34567
|
branch: external_exports.string().nullable().describe("The checked-out branch's name; null when HEAD is detached or bare."),
|
|
@@ -34614,7 +34596,7 @@ async function readWorktreeList(callerRoot, root, signal) {
|
|
|
34614
34596
|
const repository = await repositoryName(callerRoot, signal);
|
|
34615
34597
|
const [caller, layoutFolder, entries] = await Promise.all([
|
|
34616
34598
|
realpathOrSelf(callerRoot),
|
|
34617
|
-
realpathOfExisting(
|
|
34599
|
+
realpathOfExisting(join10(root, repository)),
|
|
34618
34600
|
listWorktrees(callerRoot, signal)
|
|
34619
34601
|
]);
|
|
34620
34602
|
return {
|
|
@@ -34676,7 +34658,7 @@ async function removeDescription(plan, signal) {
|
|
|
34676
34658
|
}
|
|
34677
34659
|
|
|
34678
34660
|
// src/core/worktree/remove-plan.ts
|
|
34679
|
-
import { resolve as
|
|
34661
|
+
import { resolve as resolve2 } from "node:path";
|
|
34680
34662
|
|
|
34681
34663
|
// src/core/worktree/remove-checks.ts
|
|
34682
34664
|
var MAX_LISTED_FILES = 50;
|
|
@@ -34750,7 +34732,7 @@ async function targetOf2(request) {
|
|
|
34750
34732
|
if (request.directory.trim() === "") {
|
|
34751
34733
|
throw invalid3("directory is blank; pass the directory of the worktree to remove.");
|
|
34752
34734
|
}
|
|
34753
|
-
return realpathOfExisting(
|
|
34735
|
+
return realpathOfExisting(resolve2(request.callerRoot, request.directory));
|
|
34754
34736
|
}
|
|
34755
34737
|
async function findWorktree(request, target) {
|
|
34756
34738
|
for (const entry of await listWorktrees(request.callerRoot, request.signal)) {
|
|
@@ -34793,7 +34775,7 @@ async function planRemove(request) {
|
|
|
34793
34775
|
|
|
34794
34776
|
// src/core/worktree/remove-run.ts
|
|
34795
34777
|
import { rmdir } from "node:fs/promises";
|
|
34796
|
-
import { dirname as dirname6, join as
|
|
34778
|
+
import { dirname as dirname6, join as join11 } from "node:path";
|
|
34797
34779
|
|
|
34798
34780
|
// src/core/worktree/landed.ts
|
|
34799
34781
|
var LANDED_READ_TIMEOUT_MS = PROTECTION_READ_TIMEOUT_MS;
|
|
@@ -34875,7 +34857,7 @@ async function removeWorktreeRecord(request, plan) {
|
|
|
34875
34857
|
}
|
|
34876
34858
|
async function removeEmptyLayoutFolder(request, plan) {
|
|
34877
34859
|
const { callerRoot, worktreeRoot: worktreeRoot2, signal } = request;
|
|
34878
|
-
const folder = await realpathOfExisting(
|
|
34860
|
+
const folder = await realpathOfExisting(join11(worktreeRoot2, await repositoryName(callerRoot, signal)));
|
|
34879
34861
|
const parent = dirname6(plan.directory);
|
|
34880
34862
|
if (await realpathOfExisting(parent) !== folder) return;
|
|
34881
34863
|
try {
|
|
@@ -35630,7 +35612,7 @@ var Protocol = class {
|
|
|
35630
35612
|
return;
|
|
35631
35613
|
}
|
|
35632
35614
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
35633
|
-
await new Promise((
|
|
35615
|
+
await new Promise((resolve3) => setTimeout(resolve3, pollInterval));
|
|
35634
35616
|
options?.signal?.throwIfAborted();
|
|
35635
35617
|
}
|
|
35636
35618
|
} catch (error62) {
|
|
@@ -35647,7 +35629,7 @@ var Protocol = class {
|
|
|
35647
35629
|
*/
|
|
35648
35630
|
request(request, resultSchema, options) {
|
|
35649
35631
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
35650
|
-
return new Promise((
|
|
35632
|
+
return new Promise((resolve3, reject) => {
|
|
35651
35633
|
const earlyReject = (error62) => {
|
|
35652
35634
|
reject(error62);
|
|
35653
35635
|
};
|
|
@@ -35725,7 +35707,7 @@ var Protocol = class {
|
|
|
35725
35707
|
if (!parseResult.success) {
|
|
35726
35708
|
reject(parseResult.error);
|
|
35727
35709
|
} else {
|
|
35728
|
-
|
|
35710
|
+
resolve3(parseResult.data);
|
|
35729
35711
|
}
|
|
35730
35712
|
} catch (error62) {
|
|
35731
35713
|
reject(error62);
|
|
@@ -35987,12 +35969,12 @@ var Protocol = class {
|
|
|
35987
35969
|
}
|
|
35988
35970
|
} catch {
|
|
35989
35971
|
}
|
|
35990
|
-
return new Promise((
|
|
35972
|
+
return new Promise((resolve3, reject) => {
|
|
35991
35973
|
if (signal.aborted) {
|
|
35992
35974
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
35993
35975
|
return;
|
|
35994
35976
|
}
|
|
35995
|
-
const timeoutId = setTimeout(
|
|
35977
|
+
const timeoutId = setTimeout(resolve3, interval);
|
|
35996
35978
|
signal.addEventListener("abort", () => {
|
|
35997
35979
|
clearTimeout(timeoutId);
|
|
35998
35980
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -36948,7 +36930,7 @@ async function main() {
|
|
|
36948
36930
|
const settings = parseSettings(process.argv.slice(2), process.env);
|
|
36949
36931
|
server = createServer(ALL_TOOLS, settings, {
|
|
36950
36932
|
ownDir: packageRoot(import.meta.url),
|
|
36951
|
-
version: true ? "0.2.
|
|
36933
|
+
version: true ? "0.2.2" : void 0
|
|
36952
36934
|
});
|
|
36953
36935
|
} catch (error62) {
|
|
36954
36936
|
if (!isToolError(error62)) throw error62;
|
package/dist/opencode.js
CHANGED
|
@@ -26,7 +26,7 @@ var PROJECT = {
|
|
|
26
26
|
/** The toolsets on when a setting names none. */
|
|
27
27
|
defaultToolsets: ["repo", "commit", "rebase"],
|
|
28
28
|
/** The package's own settings, which the tools themselves read: each snake_case name and its type, with bounds when it needs them. */
|
|
29
|
-
options: { published_text_rules: "
|
|
29
|
+
options: { published_text_rules: "path", worktree_root: "path" },
|
|
30
30
|
/** The environment variables the tools read besides the settings, which Codex forwards to the server after them. */
|
|
31
31
|
toolVariables: [
|
|
32
32
|
"LANGUAGE",
|
|
@@ -5134,7 +5134,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
5134
5134
|
var NONE = 0;
|
|
5135
5135
|
var ASSUMED = 1;
|
|
5136
5136
|
var PROVEN = 2;
|
|
5137
|
-
function isRecursive(inst, stack,
|
|
5137
|
+
function isRecursive(inst, stack, resolve4) {
|
|
5138
5138
|
const cached2 = recursive.get(inst);
|
|
5139
5139
|
if (cached2 !== void 0)
|
|
5140
5140
|
return cached2 ? PROVEN : NONE;
|
|
@@ -5144,7 +5144,7 @@ function isRecursive(inst, stack, resolve6) {
|
|
|
5144
5144
|
let result = NONE;
|
|
5145
5145
|
const check2 = (child) => {
|
|
5146
5146
|
if (result !== PROVEN && child?._zod) {
|
|
5147
|
-
const answer = isRecursive(child, stack,
|
|
5147
|
+
const answer = isRecursive(child, stack, resolve4);
|
|
5148
5148
|
if (answer > result)
|
|
5149
5149
|
result = answer;
|
|
5150
5150
|
}
|
|
@@ -5155,7 +5155,7 @@ function isRecursive(inst, stack, resolve6) {
|
|
|
5155
5155
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
5156
5156
|
if (spread && !desc.enumerable)
|
|
5157
5157
|
continue;
|
|
5158
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
5158
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve4) : NONE;
|
|
5159
5159
|
if (child > answer)
|
|
5160
5160
|
answer = child;
|
|
5161
5161
|
}
|
|
@@ -5219,7 +5219,7 @@ function isRecursive(inst, stack, resolve6) {
|
|
|
5219
5219
|
break;
|
|
5220
5220
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
5221
5221
|
case "lazy": {
|
|
5222
|
-
const inner = def._cachedInner ?? (
|
|
5222
|
+
const inner = def._cachedInner ?? (resolve4 ? inst._zod.innerType : void 0);
|
|
5223
5223
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
5224
5224
|
break;
|
|
5225
5225
|
}
|
|
@@ -19828,7 +19828,7 @@ function abortError(signal) {
|
|
|
19828
19828
|
}
|
|
19829
19829
|
function exec(argv, options) {
|
|
19830
19830
|
const { signal } = options;
|
|
19831
|
-
return new Promise((
|
|
19831
|
+
return new Promise((resolve4, reject) => {
|
|
19832
19832
|
if (signal?.aborted) {
|
|
19833
19833
|
reject(abortError(signal));
|
|
19834
19834
|
return;
|
|
@@ -19887,7 +19887,7 @@ function exec(argv, options) {
|
|
|
19887
19887
|
}
|
|
19888
19888
|
const finish = () => settle2(() => {
|
|
19889
19889
|
const { code, killedBy } = exitedWith ?? { code: null, killedBy: null };
|
|
19890
|
-
|
|
19890
|
+
resolve4({
|
|
19891
19891
|
code: code ?? -1,
|
|
19892
19892
|
stdout,
|
|
19893
19893
|
stderr,
|
|
@@ -22774,7 +22774,7 @@ async function compareBranch(root, remote, selected, expect, signal) {
|
|
|
22774
22774
|
|
|
22775
22775
|
// src/core/push/published-text.ts
|
|
22776
22776
|
import { readFile as readFile2, stat as stat6 } from "node:fs/promises";
|
|
22777
|
-
import { isAbsolute as isAbsolute4
|
|
22777
|
+
import { isAbsolute as isAbsolute4 } from "node:path";
|
|
22778
22778
|
|
|
22779
22779
|
// src/core/describe.ts
|
|
22780
22780
|
var MAX_FACTS = 8;
|
|
@@ -22911,19 +22911,6 @@ async function wholeCallDescription(spec, args, ctx) {
|
|
|
22911
22911
|
return { ...headline2 && { headline: headline2 }, facts, ...text && { text }, ...kept2 };
|
|
22912
22912
|
}
|
|
22913
22913
|
|
|
22914
|
-
// src/core/home.ts
|
|
22915
|
-
import { homedir } from "node:os";
|
|
22916
|
-
import { join as join5 } from "node:path";
|
|
22917
|
-
var HOME_MARK = "~";
|
|
22918
|
-
var HOME_PREFIX = "~/";
|
|
22919
|
-
function homeDirectory() {
|
|
22920
|
-
return process.env.HOME?.trim() || homedir();
|
|
22921
|
-
}
|
|
22922
|
-
function expandHome(value) {
|
|
22923
|
-
if (value === HOME_MARK) return homeDirectory();
|
|
22924
|
-
return value.startsWith(HOME_PREFIX) ? join5(homeDirectory(), value.slice(HOME_PREFIX.length)) : value;
|
|
22925
|
-
}
|
|
22926
|
-
|
|
22927
22914
|
// src/core/push/published-text.ts
|
|
22928
22915
|
var PUBLISHED_TEXT_RULES_OPTION = "published_text_rules";
|
|
22929
22916
|
var MAX_FILE_BYTES = 64 * 1024;
|
|
@@ -22996,11 +22983,8 @@ async function loadPublishedTextRules(options, signal) {
|
|
|
22996
22983
|
const option = options?.[PUBLISHED_TEXT_RULES_OPTION];
|
|
22997
22984
|
const path = typeof option === "string" ? option.trim() : void 0;
|
|
22998
22985
|
if (!path) return [];
|
|
22999
|
-
|
|
23000
|
-
|
|
23001
|
-
throw invalidRules(path, `the value must be an absolute path, or start with ${HOME_PREFIX}`);
|
|
23002
|
-
const normalized = resolve2(expanded);
|
|
23003
|
-
return compileRules(normalized, parseRulesJson(normalized, await readRulesFile(normalized, signal)));
|
|
22986
|
+
if (!isAbsolute4(path)) throw invalidRules(path, "the value must be an absolute path");
|
|
22987
|
+
return compileRules(path, parseRulesJson(path, await readRulesFile(path, signal)));
|
|
23004
22988
|
}
|
|
23005
22989
|
var publishedTextFindingSchema = external_exports.object({
|
|
23006
22990
|
rule: external_exports.string().describe("The name of the rule that matched."),
|
|
@@ -23954,11 +23938,11 @@ var rebaseRead = defineTool({
|
|
|
23954
23938
|
// src/core/rebase/resume.ts
|
|
23955
23939
|
import { createHash as createHash3 } from "node:crypto";
|
|
23956
23940
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
23957
|
-
import { join as
|
|
23941
|
+
import { join as join7 } from "node:path";
|
|
23958
23942
|
|
|
23959
23943
|
// src/core/conflicts.ts
|
|
23960
23944
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
23961
|
-
import { basename as basename2, join as
|
|
23945
|
+
import { basename as basename2, join as join5 } from "node:path";
|
|
23962
23946
|
var REGION_MAX = 20;
|
|
23963
23947
|
var SIDE_LINES_MAX = 40;
|
|
23964
23948
|
var LOCKFILES = {
|
|
@@ -24070,7 +24054,7 @@ async function readConflictFile(root, path, xy, operation) {
|
|
|
24070
24054
|
}
|
|
24071
24055
|
let text;
|
|
24072
24056
|
try {
|
|
24073
|
-
text = await readFile3(
|
|
24057
|
+
text = await readFile3(join5(root, path), "utf8");
|
|
24074
24058
|
} catch {
|
|
24075
24059
|
return { ...file2, region_count: 0, regions: [] };
|
|
24076
24060
|
}
|
|
@@ -24153,13 +24137,13 @@ var rebaseOutcomeSchema = external_exports.object({
|
|
|
24153
24137
|
|
|
24154
24138
|
// src/core/rebase/rebase-state.ts
|
|
24155
24139
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
24156
|
-
import { join as
|
|
24140
|
+
import { join as join6 } from "node:path";
|
|
24157
24141
|
var HEADS_PREFIX = "refs/heads/";
|
|
24158
24142
|
var STATE_DIRS = ["rebase-merge", "rebase-apply"];
|
|
24159
24143
|
var UPDATE_REFS_LINES = 3;
|
|
24160
24144
|
async function readStateFile(dir, name) {
|
|
24161
24145
|
try {
|
|
24162
|
-
return (await readFile4(
|
|
24146
|
+
return (await readFile4(join6(dir, name), "utf8")).trim();
|
|
24163
24147
|
} catch {
|
|
24164
24148
|
return void 0;
|
|
24165
24149
|
}
|
|
@@ -24334,7 +24318,7 @@ async function conflictedFiles(root, signal) {
|
|
|
24334
24318
|
for (const path of await unmergedPaths(root, signal)) {
|
|
24335
24319
|
let content;
|
|
24336
24320
|
try {
|
|
24337
|
-
content = await readFile5(
|
|
24321
|
+
content = await readFile5(join7(root, path));
|
|
24338
24322
|
} catch {
|
|
24339
24323
|
content = null;
|
|
24340
24324
|
}
|
|
@@ -25333,7 +25317,8 @@ var repoRead = defineTool({
|
|
|
25333
25317
|
import { lstat } from "node:fs/promises";
|
|
25334
25318
|
|
|
25335
25319
|
// src/core/worktree/layout.ts
|
|
25336
|
-
import {
|
|
25320
|
+
import { homedir } from "node:os";
|
|
25321
|
+
import { basename as basename3, dirname as dirname3, isAbsolute as isAbsolute5, join as join8 } from "node:path";
|
|
25337
25322
|
var WORKTREE_ROOT_OPTION = "worktree_root";
|
|
25338
25323
|
var DEFAULT_ROOT_FOLDER = "worktrees";
|
|
25339
25324
|
var GIT_DIRECTORY = ".git";
|
|
@@ -25344,15 +25329,14 @@ var NOT_A_NAME = [".", ".."];
|
|
|
25344
25329
|
function worktreeRoot(ctx) {
|
|
25345
25330
|
const option = ctx.options?.[WORKTREE_ROOT_OPTION];
|
|
25346
25331
|
const value = typeof option === "string" ? option.trim() : void 0;
|
|
25347
|
-
if (!value) return
|
|
25348
|
-
|
|
25349
|
-
if (!isAbsolute5(expanded)) {
|
|
25332
|
+
if (!value) return join8(process.env.HOME?.trim() || homedir(), DEFAULT_ROOT_FOLDER);
|
|
25333
|
+
if (!isAbsolute5(value)) {
|
|
25350
25334
|
throw new ToolError(
|
|
25351
25335
|
"invalid_argument",
|
|
25352
|
-
`The ${WORKTREE_ROOT_OPTION} setting (${value}): the value must be an absolute path
|
|
25336
|
+
`The ${WORKTREE_ROOT_OPTION} setting (${value}): the value must be an absolute path.`
|
|
25353
25337
|
);
|
|
25354
25338
|
}
|
|
25355
|
-
return
|
|
25339
|
+
return value;
|
|
25356
25340
|
}
|
|
25357
25341
|
async function mainCheckout(root, signal) {
|
|
25358
25342
|
const common = (await git(["rev-parse", "--path-format=absolute", "--git-common-dir"], { cwd: root, signal })).trim();
|
|
@@ -25368,7 +25352,7 @@ async function repositoryName(root, signal) {
|
|
|
25368
25352
|
return fromUrl || basename3(await mainCheckout(root, signal)).replace(GIT_SUFFIX, "");
|
|
25369
25353
|
}
|
|
25370
25354
|
function worktreePath(root, repository, branch) {
|
|
25371
|
-
return
|
|
25355
|
+
return join8(root, repository, branch.replaceAll("/", "-"));
|
|
25372
25356
|
}
|
|
25373
25357
|
|
|
25374
25358
|
// src/core/worktree/add-plan.ts
|
|
@@ -25631,7 +25615,7 @@ var worktreeAdd = defineTool({
|
|
|
25631
25615
|
});
|
|
25632
25616
|
|
|
25633
25617
|
// src/core/worktree/list.ts
|
|
25634
|
-
import { dirname as dirname5, join as
|
|
25618
|
+
import { dirname as dirname5, join as join9 } from "node:path";
|
|
25635
25619
|
var worktreeSchema = external_exports.object({
|
|
25636
25620
|
directory: external_exports.string().describe("The worktree's directory: its real path when it exists, else as git prints it."),
|
|
25637
25621
|
branch: external_exports.string().nullable().describe("The checked-out branch's name; null when HEAD is detached or bare."),
|
|
@@ -25666,7 +25650,7 @@ async function readWorktreeList(callerRoot, root, signal) {
|
|
|
25666
25650
|
const repository = await repositoryName(callerRoot, signal);
|
|
25667
25651
|
const [caller, layoutFolder, entries] = await Promise.all([
|
|
25668
25652
|
realpathOrSelf(callerRoot),
|
|
25669
|
-
realpathOfExisting(
|
|
25653
|
+
realpathOfExisting(join9(root, repository)),
|
|
25670
25654
|
listWorktrees(callerRoot, signal)
|
|
25671
25655
|
]);
|
|
25672
25656
|
return {
|
|
@@ -25728,7 +25712,7 @@ async function removeDescription(plan, signal) {
|
|
|
25728
25712
|
}
|
|
25729
25713
|
|
|
25730
25714
|
// src/core/worktree/remove-plan.ts
|
|
25731
|
-
import { resolve as
|
|
25715
|
+
import { resolve as resolve2 } from "node:path";
|
|
25732
25716
|
|
|
25733
25717
|
// src/core/worktree/remove-checks.ts
|
|
25734
25718
|
var MAX_LISTED_FILES = 50;
|
|
@@ -25802,7 +25786,7 @@ async function targetOf2(request) {
|
|
|
25802
25786
|
if (request.directory.trim() === "") {
|
|
25803
25787
|
throw invalid3("directory is blank; pass the directory of the worktree to remove.");
|
|
25804
25788
|
}
|
|
25805
|
-
return realpathOfExisting(
|
|
25789
|
+
return realpathOfExisting(resolve2(request.callerRoot, request.directory));
|
|
25806
25790
|
}
|
|
25807
25791
|
async function findWorktree(request, target) {
|
|
25808
25792
|
for (const entry of await listWorktrees(request.callerRoot, request.signal)) {
|
|
@@ -25845,7 +25829,7 @@ async function planRemove(request) {
|
|
|
25845
25829
|
|
|
25846
25830
|
// src/core/worktree/remove-run.ts
|
|
25847
25831
|
import { rmdir } from "node:fs/promises";
|
|
25848
|
-
import { dirname as dirname6, join as
|
|
25832
|
+
import { dirname as dirname6, join as join10 } from "node:path";
|
|
25849
25833
|
|
|
25850
25834
|
// src/core/worktree/landed.ts
|
|
25851
25835
|
var LANDED_READ_TIMEOUT_MS = PROTECTION_READ_TIMEOUT_MS;
|
|
@@ -25927,7 +25911,7 @@ async function removeWorktreeRecord(request, plan) {
|
|
|
25927
25911
|
}
|
|
25928
25912
|
async function removeEmptyLayoutFolder(request, plan) {
|
|
25929
25913
|
const { callerRoot, worktreeRoot: worktreeRoot2, signal } = request;
|
|
25930
|
-
const folder = await realpathOfExisting(
|
|
25914
|
+
const folder = await realpathOfExisting(join10(worktreeRoot2, await repositoryName(callerRoot, signal)));
|
|
25931
25915
|
const parent = dirname6(plan.directory);
|
|
25932
25916
|
if (await realpathOfExisting(parent) !== folder) return;
|
|
25933
25917
|
try {
|
|
@@ -26392,9 +26376,9 @@ async function timedCallDescription(spec, args, ctx, timeoutMs = DESCRIBE_TIMEOU
|
|
|
26392
26376
|
let timer;
|
|
26393
26377
|
let onAbort;
|
|
26394
26378
|
try {
|
|
26395
|
-
const timedOut = new Promise((
|
|
26379
|
+
const timedOut = new Promise((resolve4) => {
|
|
26396
26380
|
timer = setTimeout(() => {
|
|
26397
|
-
|
|
26381
|
+
resolve4(void 0);
|
|
26398
26382
|
controller.abort();
|
|
26399
26383
|
}, timeoutMs);
|
|
26400
26384
|
});
|
|
@@ -26475,7 +26459,7 @@ var PROJECT_PROFILE = {
|
|
|
26475
26459
|
|
|
26476
26460
|
// src/entry/settings.ts
|
|
26477
26461
|
import { homedir as homedir2 } from "node:os";
|
|
26478
|
-
import { isAbsolute as isAbsolute6, join as
|
|
26462
|
+
import { isAbsolute as isAbsolute6, join as join11, resolve as resolvePath, sep as sep3 } from "node:path";
|
|
26479
26463
|
var ALL_TOOLSETS = "all";
|
|
26480
26464
|
var TRUE_VALUES = ["1", "true"];
|
|
26481
26465
|
var FALSE_VALUES = ["0", "false"];
|
|
@@ -26534,7 +26518,7 @@ function parseNumber(value, source) {
|
|
|
26534
26518
|
}
|
|
26535
26519
|
function absolutePath(text, source, env) {
|
|
26536
26520
|
const home = env.HOME !== void 0 && isAbsolute6(env.HOME) ? env.HOME : homedir2();
|
|
26537
|
-
const expanded = text === "~" || text.startsWith("~/") || text.startsWith(`~${sep3}`) ?
|
|
26521
|
+
const expanded = text === "~" || text.startsWith("~/") || text.startsWith(`~${sep3}`) ? join11(home, text.slice(1)) : text;
|
|
26538
26522
|
if (!isAbsolute6(expanded)) throw new ToolError("invalid_argument", `${source} must be an absolute path.`);
|
|
26539
26523
|
return resolvePath(expanded);
|
|
26540
26524
|
}
|
|
@@ -26681,7 +26665,7 @@ function settingsFromOptions(options, env, profile = PROJECT_PROFILE) {
|
|
|
26681
26665
|
if (unknown2 !== void 0) {
|
|
26682
26666
|
throw new ToolError("invalid_argument", `Unknown option "${unknown2}"; use one of ${names.join(", ")}.`);
|
|
26683
26667
|
}
|
|
26684
|
-
const
|
|
26668
|
+
const resolve4 = (name, fromOption, fromText) => {
|
|
26685
26669
|
if (given[name] !== void 0) return fromOption(given[name]);
|
|
26686
26670
|
const text = envText(name, env, profile);
|
|
26687
26671
|
return text !== void 0 ? fromText(text) : void 0;
|
|
@@ -26698,17 +26682,17 @@ function settingsFromOptions(options, env, profile = PROJECT_PROFILE) {
|
|
|
26698
26682
|
if (parsed !== void 0) parsedOptions[name] = parsed;
|
|
26699
26683
|
}
|
|
26700
26684
|
const settings = { options: parsedOptions };
|
|
26701
|
-
const toolsets =
|
|
26685
|
+
const toolsets = resolve4(
|
|
26702
26686
|
"toolsets",
|
|
26703
26687
|
(value) => toolsetsOption(value, profile.toolsets),
|
|
26704
26688
|
({ text, source }) => checkToolsets(splitList(text), source, profile.toolsets)
|
|
26705
26689
|
);
|
|
26706
26690
|
if (toolsets !== void 0) settings.toolsets = toolsets;
|
|
26707
|
-
const readOnly =
|
|
26691
|
+
const readOnly = resolve4("read_only", booleanOption, ({ text, source }) => parseBoolean(text, source));
|
|
26708
26692
|
if (readOnly !== void 0) settings.read_only = readOnly;
|
|
26709
|
-
const tools =
|
|
26693
|
+
const tools = resolve4("tools", listOption("tools"), ({ text }) => splitList(text));
|
|
26710
26694
|
if (tools !== void 0) settings.tools = tools;
|
|
26711
|
-
const excluded =
|
|
26695
|
+
const excluded = resolve4("exclude_tools", listOption("exclude_tools"), ({ text }) => splitList(text));
|
|
26712
26696
|
if (excluded !== void 0) settings.exclude_tools = excluded;
|
|
26713
26697
|
const language = given[LANGUAGE_OPTION] !== void 0 ? languageOption(given[LANGUAGE_OPTION]) : promptLanguage(void 0, env, void 0, profile);
|
|
26714
26698
|
if (language !== void 0) settings.language = language;
|
|
@@ -26803,7 +26787,7 @@ function createV1Server(specs, deps = {}) {
|
|
|
26803
26787
|
|
|
26804
26788
|
// src/opencode/skills.ts
|
|
26805
26789
|
import { readFile as readFile6, readdir } from "node:fs/promises";
|
|
26806
|
-
import { join as
|
|
26790
|
+
import { join as join12, resolve as resolve3 } from "node:path";
|
|
26807
26791
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
26808
26792
|
var SKILL_FILE = "SKILL.md";
|
|
26809
26793
|
var FRONTMATTER = /^---[ \t]*\r?\n([\s\S]*?\r?\n)?---[ \t]*(?:\r?\n|$)/;
|
|
@@ -26894,7 +26878,7 @@ async function readSkillFile(path) {
|
|
|
26894
26878
|
}
|
|
26895
26879
|
}
|
|
26896
26880
|
async function readSkills(dir) {
|
|
26897
|
-
const root =
|
|
26881
|
+
const root = resolve3(typeof dir === "string" ? dir : fileURLToPath2(dir));
|
|
26898
26882
|
let entries;
|
|
26899
26883
|
try {
|
|
26900
26884
|
entries = (await readdir(root, { withFileTypes: true })).filter((entry) => !entry.isFile()).map((entry) => entry.name);
|
|
@@ -26904,7 +26888,7 @@ async function readSkills(dir) {
|
|
|
26904
26888
|
}
|
|
26905
26889
|
const skills = /* @__PURE__ */ new Map();
|
|
26906
26890
|
for (const directory of entries.sort()) {
|
|
26907
|
-
const path =
|
|
26891
|
+
const path = join12(root, directory, SKILL_FILE);
|
|
26908
26892
|
const text = await readSkillFile(path);
|
|
26909
26893
|
if (text === void 0) continue;
|
|
26910
26894
|
const found = parseSkill(directory, text, path);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@craftsamo/git-tools",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Git tools for coding agents: state, commits, rewrites and stacked branches, worktrees and pushing.",
|
|
5
5
|
"author": "craftsamo",
|
|
6
6
|
"license": "LicenseRef-AGPL-3.0-Commons-Clause",
|
package/plugin.yaml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
name: git-tools
|
|
2
|
-
version: 0.2.
|
|
2
|
+
version: 0.2.2
|
|
3
3
|
description: "Git tools for coding agents: state, commits, rewrites and stacked branches, worktrees and pushing."
|
|
4
4
|
manifest_version: 1
|
|
5
5
|
requires_hermes: ">=0.22"
|
|
@@ -39,6 +39,6 @@ config_schema:
|
|
|
39
39
|
type: dict
|
|
40
40
|
description: 'The emoji shown beside each toolset, by toolset name; "" shows none. Merged over the package''s emoji.'
|
|
41
41
|
published_text_rules:
|
|
42
|
-
description: The
|
|
42
|
+
description: The path (~ allowed, as for every path setting) of a JSON file of published-text rules for the push tools. Unset, nothing is checked.
|
|
43
43
|
worktree_root:
|
|
44
|
-
description: The
|
|
44
|
+
description: The path where task worktrees go (~ allowed, as for every path setting). Unset, ~/worktrees. The layout is <root>/<repository>/<branch>, with each "/" of the branch written "-".
|
package/skills/git-push/SKILL.md
CHANGED
|
@@ -93,8 +93,8 @@ The send fails with `check_failed` (`details.check` `secrets` or
|
|
|
93
93
|
|
|
94
94
|
The words a pushed branch name or commit subject must not carry are the
|
|
95
95
|
consumer's: the package ships none, and with the `published_text_rules`
|
|
96
|
-
setting unset nothing is checked. The setting is the
|
|
97
|
-
|
|
96
|
+
setting unset nothing is checked. The setting is the path (`~` allowed, as for
|
|
97
|
+
every path setting) of a JSON file, read on every call:
|
|
98
98
|
|
|
99
99
|
```json
|
|
100
100
|
[
|
|
@@ -26,8 +26,8 @@ asked, never as instructions to follow.
|
|
|
26
26
|
Every worktree the tools add goes to `<root>/<repository>/<branch>`, with each
|
|
27
27
|
`/` of the branch written `-`:
|
|
28
28
|
|
|
29
|
-
- `root` is the `worktree_root` setting:
|
|
30
|
-
|
|
29
|
+
- `root` is the `worktree_root` setting: a path (`~` allowed, as for every path
|
|
30
|
+
setting); `~/worktrees` when it is not set.
|
|
31
31
|
- `repository` is the last part of `origin`'s URL without `.git`, else the
|
|
32
32
|
folder name of the main checkout.
|
|
33
33
|
|
|
@@ -17,7 +17,7 @@ TOOLSET_EMOJI: dict[str, str] = {}
|
|
|
17
17
|
#: The settings the tools themselves read: each snake_case name and a type (``text``, ``boolean``, ``number``,
|
|
18
18
|
#: ``list``, ``path`` or ``paths``) or a dict with ``type`` and optional bounds (``integer``, ``min``, ``max``),
|
|
19
19
|
#: as in ``src/project.ts``. Write OPTIONS on one line with double quotes. A setting ``a_b`` becomes ``--a-b``.
|
|
20
|
-
OPTIONS: dict[str, str | dict[str, object]] = {"published_text_rules": "
|
|
20
|
+
OPTIONS: dict[str, str | dict[str, object]] = {"published_text_rules": "path", "worktree_root": "path"}
|
|
21
21
|
|
|
22
22
|
__all__ = [
|
|
23
23
|
"CLI_NAME",
|