@pmelab/gtd 64.1.2 → 64.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +28 -16
- package/dist/chunks/{steering-CQzL-lX1.mjs → steering-DEh_MS40.mjs} +57 -0
- package/dist/chunks/{testkit-D539mnDI.mjs → testkit-BUX-47TD.mjs} +61 -18
- package/dist/gtd.bundle.mjs +144 -51
- package/dist/gtd.core.mjs +110 -109
- package/dist/steering.mjs +1 -1
- package/dist/testkit/gherkin.mjs +1 -1
- package/dist/testkit.mjs +1 -1
- package/dist/web/main.js +81 -14
- package/dist/workflow-kit.mjs +1 -1
- package/package.json +1 -1
- package/src/cli/Cli.test.ts +1 -0
- package/src/cli/Cli.ts +17 -2
- package/src/cli/Program.ts +6 -0
- package/src/cli/ToolCommands.ts +1 -0
- package/src/edge/Edge.test.ts +22 -0
- package/src/edge/Edge.ts +22 -0
- package/src/edge/index.ts +1 -0
- package/src/platform/Git.ts +33 -10
- package/src/steering/SteeringFormat.ts +4 -1
- package/src/steering/freeform.test.ts +51 -1
- package/src/steering/freeform.ts +38 -0
- package/src/twins/FakeGitOperations.ts +2 -0
- package/src/twins/GitTiers.ts +26 -1
- package/src/twins/InMemRepo.ts +5 -0
package/README.md
CHANGED
|
@@ -433,22 +433,25 @@ commit. Its guide is
|
|
|
433
433
|
Prefer a phone or another device over your editor? `gtd ui` opens the file whose
|
|
434
434
|
turn it is as a small web app, over Tailscale — including a step that names no
|
|
435
435
|
format, or one nothing recognizes, which still opens as plain markdown structure
|
|
436
|
-
instead of refusing to start: read, plus a note on any block
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
answer
|
|
450
|
-
|
|
451
|
-
|
|
436
|
+
instead of refusing to start: read, plus a note on any block and tickable
|
|
437
|
+
task-list boxes (each list is pick-one: ticking a box unticks its siblings, and
|
|
438
|
+
a ticked box can't be cleared from the phone). It also binds on an idle worktree
|
|
439
|
+
— nothing pending yet — opening `.gtd/TODO.md` free-form with a bare textfield
|
|
440
|
+
so you can sketch from your phone; the sketch stays un-triaged on disk until you
|
|
441
|
+
run `gtd` again, from anywhere, to pick it up. A description renders inline
|
|
442
|
+
markdown — bold, code, strikethrough, links, and images — instead of literal
|
|
443
|
+
asterisks and backticks. A note you add from the phone starts a thread: a
|
|
444
|
+
footnote holding a `H:`/`A:` conversation. Threads show as a conversation under
|
|
445
|
+
their block, question, chunk, or hunk — or, in a review chunk with no file
|
|
446
|
+
pointers, under each line of its lists, so a summary's entries take a note
|
|
447
|
+
apiece — and one the agent answered last carries a "waiting on you" badge. Tap
|
|
448
|
+
it to reply — your reply is added as a new `H:` entry; while the agent has yet
|
|
449
|
+
to answer, reopening it edits your last entry instead. Tap an already-answered
|
|
450
|
+
question to leave a note on it; the agent may overturn the answer. A `findings`
|
|
451
|
+
file lists its findings, each with a fix checkbox and, once ticked, an optional
|
|
452
|
+
line of guidance; Done stays disabled while the file holds anything its gate
|
|
453
|
+
would refuse. Done saves and leaves the server running; it exits once the
|
|
454
|
+
worktree moves on to another step. See
|
|
452
455
|
[Configuration](https://github.com/pmelab/gtd/blob/main/docs/configuration.md)
|
|
453
456
|
for its `ui:` settings.
|
|
454
457
|
|
|
@@ -472,6 +475,15 @@ unknown key. `gtd.config.ts` is the only repository config: gtd 23 removed the
|
|
|
472
475
|
home directory — fails every command until you delete it. See
|
|
473
476
|
[Migrating from `.gtdrc`](https://github.com/pmelab/gtd/blob/main/docs/configuration.md#migrating-from-gtdrc).
|
|
474
477
|
|
|
478
|
+
## Large untracked trees
|
|
479
|
+
|
|
480
|
+
`gtd next`, `gtd land`, `gtd judge answer` and `gtd start` refuse when the
|
|
481
|
+
worktree holds more than 1,000 untracked, un-ignored files (a landing would
|
|
482
|
+
commit them all). The error names the count and the largest untracked
|
|
483
|
+
directories; add them to `.gitignore` (or `.git/info/exclude`) or delete them,
|
|
484
|
+
then run again. Fixed limit, no config key. Every other command — read-only ones
|
|
485
|
+
like `gtd check --open-threads`, `gtd judge`, `gtd validate` — never refuses.
|
|
486
|
+
|
|
475
487
|
## Checking a range for stray files
|
|
476
488
|
|
|
477
489
|
```sh
|
|
@@ -16486,6 +16486,58 @@ const appendEdit = (content, text) => {
|
|
|
16486
16486
|
const newText = trimmed.length > 0 ? `${trimmed}${eol}${eol}${normalizedText}${eol}` : `${normalizedText}${eol}`;
|
|
16487
16487
|
return wholeDocumentEdit(content, newText);
|
|
16488
16488
|
};
|
|
16489
|
+
/** Every task-list item with its sibling task items (direct children of one list only). */
|
|
16490
|
+
const taskGroups = (node, out) => {
|
|
16491
|
+
const n = node;
|
|
16492
|
+
if (n.type === "list") out.push(n.children.filter((i) => i.checked === true || i.checked === false));
|
|
16493
|
+
for (const c of n.children ?? []) taskGroups(c, out);
|
|
16494
|
+
};
|
|
16495
|
+
/** The box sits on the first child's line, which is not the marker line when a bare `-` precedes it. */
|
|
16496
|
+
const boxEdit = (lines, item, newText) => {
|
|
16497
|
+
const line = toLspPosition((item.children[0]?.position ?? item.position).start).line;
|
|
16498
|
+
const m = /\[( |x|X)\]/.exec(lines[line] ?? "");
|
|
16499
|
+
if (!m) return void 0;
|
|
16500
|
+
const c = m.index + 1;
|
|
16501
|
+
return {
|
|
16502
|
+
range: {
|
|
16503
|
+
start: {
|
|
16504
|
+
line,
|
|
16505
|
+
character: c
|
|
16506
|
+
},
|
|
16507
|
+
end: {
|
|
16508
|
+
line,
|
|
16509
|
+
character: c + 1
|
|
16510
|
+
}
|
|
16511
|
+
},
|
|
16512
|
+
newText
|
|
16513
|
+
};
|
|
16514
|
+
};
|
|
16515
|
+
/** Pick-one tick: sets the box on `line` and unticks its ticked siblings, in one edit set. Ticking an already-ticked box is an empty edit set. */
|
|
16516
|
+
const tickEdits = (content, line) => {
|
|
16517
|
+
const lines = content.split("\n");
|
|
16518
|
+
const groups = [];
|
|
16519
|
+
taskGroups(parseMarkdown(content), groups);
|
|
16520
|
+
const startLine = (i) => toLspPosition(i.position.start).line;
|
|
16521
|
+
const group = groups.find((g) => g.some((i) => startLine(i) === line));
|
|
16522
|
+
if (!group) return {
|
|
16523
|
+
ok: false,
|
|
16524
|
+
reason: "anchor-not-found"
|
|
16525
|
+
};
|
|
16526
|
+
const target = group.find((i) => startLine(i) === line);
|
|
16527
|
+
if (target.checked === true) return {
|
|
16528
|
+
ok: true,
|
|
16529
|
+
edits: []
|
|
16530
|
+
};
|
|
16531
|
+
const edits = group.filter((i) => i === target || i.checked === true).map((i) => boxEdit(lines, i, i === target ? "x" : " "));
|
|
16532
|
+
if (edits.some((e) => e === void 0)) return {
|
|
16533
|
+
ok: false,
|
|
16534
|
+
reason: "anchor-not-found"
|
|
16535
|
+
};
|
|
16536
|
+
return {
|
|
16537
|
+
ok: true,
|
|
16538
|
+
edits
|
|
16539
|
+
};
|
|
16540
|
+
};
|
|
16489
16541
|
/**
|
|
16490
16542
|
* Free-form's `apply`: only a `paragraph` anchor resolves (the only kind
|
|
16491
16543
|
* `view` ever reports), and it only ever APPENDS, at or past the document's
|
|
@@ -16500,6 +16552,11 @@ const freeFormApply = (content, anchor, opts) => {
|
|
|
16500
16552
|
ok: false,
|
|
16501
16553
|
reason: "anchor-not-found"
|
|
16502
16554
|
};
|
|
16555
|
+
if (opts.checked === true) return tickEdits(content, anchor.line);
|
|
16556
|
+
if (opts.checked === false) return {
|
|
16557
|
+
ok: false,
|
|
16558
|
+
reason: "pick-never-clears"
|
|
16559
|
+
};
|
|
16503
16560
|
const text = opts.text ?? "";
|
|
16504
16561
|
const tree = parseMarkdown(content);
|
|
16505
16562
|
const lastLineIndex = content.split(/\r?\n/).length - 1;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { C as moveScript, D as revertScript, E as restoreScript, H as installContext, K as markedOptions, O as showScript, S as checkScript, T as removeScript, Y as protocolMismatch, i as configure, k as writeScript$1, n as configProblems, o as isFactoryWorkflow, p as numeric, s as answered, t as flows_exports, x as applyScript } from "./flows-dnIE_qbe.mjs";
|
|
2
2
|
import { M as renderFormat, O as ACCESS_REFUSAL, a as renderScriptJson, d as renderLandPlain, f as DEMAND_BRIEFING, g as statusOf, h as renderBeatJson, i as judgeJson, k as PIN_PATH, l as noopText, m as beatDocument, n as resolveSession, o as scriptFields, p as renderBeatPlain, r as selectPath, s as landFields, t as globMatches, u as renderLandJson, v as beatKindOf, y as demandOf } from "./wire-CaPJ9Tme.mjs";
|
|
3
|
-
import { F as headingSectionBodies, I as formatFinding, a as sections, c as openThreads, d as formatFromSpec, i as sectionBodies, l as steeringFormatFor, o as threads, r as openQuestions, s as BUILT_IN_MODE_NAMES, t as parseCodeThreads, u as unansweredQuestions } from "./steering-
|
|
3
|
+
import { F as headingSectionBodies, I as formatFinding, a as sections, c as openThreads, d as formatFromSpec, i as sectionBodies, l as steeringFormatFor, o as threads, r as openQuestions, s as BUILT_IN_MODE_NAMES, t as parseCodeThreads, u as unansweredQuestions } from "./steering-DEh_MS40.mjs";
|
|
4
4
|
import { createRequire, isBuiltin } from "node:module";
|
|
5
5
|
import * as Crypto from "node:crypto";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
@@ -20448,14 +20448,20 @@ const stripCommitSeam = (tail) => {
|
|
|
20448
20448
|
const afterNul = tail.startsWith("\0") ? tail.slice(1) : tail;
|
|
20449
20449
|
return afterNul.startsWith("\n") ? afterNul.slice(1) : afterNul;
|
|
20450
20450
|
};
|
|
20451
|
+
const ARGV_CHUNK = 500;
|
|
20452
|
+
const chunked = (items) => {
|
|
20453
|
+
const out = [];
|
|
20454
|
+
for (let i = 0; i < items.length; i += ARGV_CHUNK) out.push(items.slice(i, i + ARGV_CHUNK));
|
|
20455
|
+
return out;
|
|
20456
|
+
};
|
|
20451
20457
|
/**
|
|
20452
20458
|
* `path → blob object id` at `ref`; a path absent from the map doesn't exist
|
|
20453
20459
|
* there. An unresolvable `ref` (an empty repo) yields an empty map, so every
|
|
20454
20460
|
* candidate reads as "not at `ref`".
|
|
20455
20461
|
*/
|
|
20456
|
-
const blobsAtRef = (exec, ref, paths) => exec("git", "ls-tree", "-r", "-z", ref, "--", ...
|
|
20462
|
+
const blobsAtRef = (exec, ref, paths) => forEach$1(chunked(paths), (chunk) => exec("git", "ls-tree", "-r", "-z", ref, "--", ...chunk).pipe(catch_(() => succeed$1(""))), { concurrency: 1 }).pipe(map((outs) => {
|
|
20457
20463
|
const blobs = /* @__PURE__ */ new Map();
|
|
20458
|
-
for (const entry of splitNul
|
|
20464
|
+
for (const entry of outs.flatMap(splitNul)) {
|
|
20459
20465
|
const tab = entry.indexOf(" ");
|
|
20460
20466
|
if (tab === -1) continue;
|
|
20461
20467
|
const [, type, oid] = entry.slice(0, tab).split(" ");
|
|
@@ -20476,7 +20482,7 @@ const blobsAtRef = (exec, ref, paths) => exec("git", "ls-tree", "-r", "-z", ref,
|
|
|
20476
20482
|
* A symlink is the residual inexactness: hash-object hashes the target's
|
|
20477
20483
|
* content rather than the link text, and reads as `M`, never `D`.
|
|
20478
20484
|
*/
|
|
20479
|
-
const hashObjects = (exec, paths) => exec("git", "hash-object", "--", ...
|
|
20485
|
+
const hashObjects = (exec, paths) => forEach$1(chunked(paths), (chunk) => exec("git", "hash-object", "--", ...chunk).pipe(map((out) => out.trim().split("\n").map((oid, i) => [chunk[i] ?? "", oid.trim()]))), { concurrency: 1 }).pipe(map((entries) => new Map(entries.flat())), catch_(() => succeed$1(/* @__PURE__ */ new Map())));
|
|
20480
20486
|
/**
|
|
20481
20487
|
* Classify every untracked path against `ref`'s tree, by CONTENT: not at
|
|
20482
20488
|
* `ref` → `A`; different bytes → `M`; identical bytes → no entry. The latter
|
|
@@ -20590,6 +20596,7 @@ const makeGitImpl = (spawner, root) => {
|
|
|
20590
20596
|
}
|
|
20591
20597
|
return all;
|
|
20592
20598
|
}),
|
|
20599
|
+
untrackedPaths: () => exec("git", "ls-files", "--others", "--exclude-standard", "-z").pipe(map(splitNul)),
|
|
20593
20600
|
stagedPaths: () => exec("git", "diff", "--cached", "--name-status", "--no-renames", "-z", "HEAD").pipe(catch_(() => succeed$1("")), map((out) => parseNameStatus(splitNul(out)))),
|
|
20594
20601
|
resolveRef: (ref) => exec("git", "rev-parse", "--verify", "--end-of-options", ref).pipe(map((s) => s.trim()), flatMap((hash) => resolvedRefOrCorrupted(ref, hash))),
|
|
20595
20602
|
readRefOption: (ref) => exec("git", "rev-parse", "--verify", "--quiet", ref).pipe(map((s) => some(s.trim())), catch_(() => succeed$1(none()))),
|
|
@@ -26425,6 +26432,19 @@ const setupFor = (config, run, workspace, host, startOverrides = {}) => gen(func
|
|
|
26425
26432
|
}
|
|
26426
26433
|
};
|
|
26427
26434
|
});
|
|
26435
|
+
const UNTRACKED_LIMIT = 1e3;
|
|
26436
|
+
const refuseHugeUntracked = gen(function* () {
|
|
26437
|
+
const paths = yield* (yield* GitService).untrackedPaths();
|
|
26438
|
+
if (paths.length <= UNTRACKED_LIMIT) return;
|
|
26439
|
+
const dirs = /* @__PURE__ */ new Map();
|
|
26440
|
+
for (const p of paths) {
|
|
26441
|
+
const i = p.lastIndexOf("/");
|
|
26442
|
+
const d = i === -1 ? "." : p.slice(0, i);
|
|
26443
|
+
dirs.set(d, (dirs.get(d) ?? 0) + 1);
|
|
26444
|
+
}
|
|
26445
|
+
const top = [...dirs].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
26446
|
+
return yield* fail$4(/* @__PURE__ */ new Error(`gtd: ${paths.length} untracked files (limit ${UNTRACKED_LIMIT}); largest untracked directories: ${top.map(([d, n]) => `${d} (${n})`).join(", ")}. Add them to .gitignore or delete them.`));
|
|
26447
|
+
});
|
|
26428
26448
|
const pendingChanges = (git, withIndex) => gen(function* () {
|
|
26429
26449
|
const worktree = yield* git.changedPaths();
|
|
26430
26450
|
if (!withIndex) return worktree;
|
|
@@ -27667,6 +27687,7 @@ const landingScript = (required) => combinedScript(required, "");
|
|
|
27667
27687
|
const EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
27668
27688
|
/** Decides `gtd land`'s one transition without performing it. Refusals fail the Effect; a no-op returns `subject: null` and empty scripts. */
|
|
27669
27689
|
const planLanding = (opts = {}, current) => gen(function* () {
|
|
27690
|
+
yield* refuseHugeUntracked;
|
|
27670
27691
|
const rest = current ?? (yield* currentRest);
|
|
27671
27692
|
const snapshot = yield* snapshotFromRest(rest, opts.judge);
|
|
27672
27693
|
const outcome = planStep(snapshot, opts);
|
|
@@ -27848,6 +27869,7 @@ const startWorkflow = (workflow, varOverrides, json, out, commandLabel) => gen(f
|
|
|
27848
27869
|
const startable = config.workflowNames.length > 0 ? `startable: ${config.workflowNames.join(", ")}` : "this config exports no workflow besides its default, which an ordinary start runs";
|
|
27849
27870
|
return yield* fail$4(new GtdUsageError(`${commandLabel}: unknown workflow "${workflow}" — ${startable}`));
|
|
27850
27871
|
}
|
|
27872
|
+
yield* refuseHugeUntracked;
|
|
27851
27873
|
const rest = yield* restAt(void 0, varOverrides);
|
|
27852
27874
|
const started = yield* startRefusal(rest, resolved, varOverrides);
|
|
27853
27875
|
const plan = yield* planStart({
|
|
@@ -28104,6 +28126,7 @@ const restBeatKind = (rest) => beatKindOf({
|
|
|
28104
28126
|
* document's own `kind` field, never the exit code.
|
|
28105
28127
|
*/
|
|
28106
28128
|
const runNextCommand = (json, out) => gen(function* () {
|
|
28129
|
+
yield* refuseHugeUntracked;
|
|
28107
28130
|
const rest = yield* currentRest;
|
|
28108
28131
|
const rendered = yield* renderRest(rest);
|
|
28109
28132
|
const fields = yield* gatherBeatDocument(rest, rendered);
|
|
@@ -28271,6 +28294,7 @@ const runUiCliCommand = (command, out) => gen(function* () {
|
|
|
28271
28294
|
...command.host !== void 0 ? { host: command.host } : {},
|
|
28272
28295
|
...command.port !== void 0 ? { port: command.port } : {},
|
|
28273
28296
|
selfSigned: command.selfSigned,
|
|
28297
|
+
...command.http === true ? { http: true } : {},
|
|
28274
28298
|
dev: command.dev
|
|
28275
28299
|
},
|
|
28276
28300
|
config: config.ui,
|
|
@@ -28502,7 +28526,7 @@ const FLAGS = [
|
|
|
28502
28526
|
},
|
|
28503
28527
|
scopeError: "gtd: --port is only valid for `gtd ui`",
|
|
28504
28528
|
valueHint: "<n>",
|
|
28505
|
-
help: "The tailscale serve port (default: the first free of 8443, 10000, 443), or with --host the port to bind (default: any free one)"
|
|
28529
|
+
help: "The tailscale serve port (default: the first free of 8443, 10000, 443), or with --host or --http the port to bind (default: any free one)"
|
|
28506
28530
|
},
|
|
28507
28531
|
{
|
|
28508
28532
|
name: "--host",
|
|
@@ -28524,6 +28548,16 @@ const FLAGS = [
|
|
|
28524
28548
|
valueHint: "",
|
|
28525
28549
|
help: "Bind directly with a throwaway self-signed certificate instead of the configured ui.cert/ui.key"
|
|
28526
28550
|
},
|
|
28551
|
+
{
|
|
28552
|
+
name: "--http",
|
|
28553
|
+
arity: 0,
|
|
28554
|
+
repeatable: false,
|
|
28555
|
+
scope: (kind) => kind === "ui",
|
|
28556
|
+
decode: () => succeed$5(true),
|
|
28557
|
+
scopeError: "gtd: --http is only valid for `gtd ui`",
|
|
28558
|
+
valueHint: "",
|
|
28559
|
+
help: "Serve plain HTTP for a local TLS-terminating proxy; binds 127.0.0.1 unless a loopback --host is given"
|
|
28560
|
+
},
|
|
28527
28561
|
{
|
|
28528
28562
|
name: "--dev",
|
|
28529
28563
|
arity: 0,
|
|
@@ -28834,7 +28868,7 @@ Prints a sorted JSON array ([] when clean) and a summary on stderr; --verbose ad
|
|
|
28834
28868
|
arity: "none",
|
|
28835
28869
|
group: "Inspect",
|
|
28836
28870
|
summary: "Serve the web and phone client",
|
|
28837
|
-
details: `Serve gtd's web and phone client for this worktree. By default it publishes through \`tailscale serve\`, reachable from anywhere on the tailnet, on the first of ports 8443, 10000 and 443 that works; when none does it serves HTTPS locally instead of refusing.`
|
|
28871
|
+
details: `Serve gtd's web and phone client for this worktree. By default it publishes through \`tailscale serve\`, reachable from anywhere on the tailnet, on the first of ports 8443, 10000 and 443 that works; when none does it serves HTTPS locally instead of refusing. Done saves the steering file and keeps serving; the server exits when the worktree moves on to another step, or on a signal.`
|
|
28838
28872
|
},
|
|
28839
28873
|
{
|
|
28840
28874
|
token: "guide",
|
|
@@ -29239,18 +29273,22 @@ const parseArgv = (argv) => {
|
|
|
29239
29273
|
verbose
|
|
29240
29274
|
};
|
|
29241
29275
|
}
|
|
29242
|
-
if (kind === "ui")
|
|
29243
|
-
|
|
29244
|
-
|
|
29245
|
-
kind: "
|
|
29246
|
-
|
|
29247
|
-
|
|
29248
|
-
|
|
29249
|
-
|
|
29250
|
-
|
|
29251
|
-
|
|
29252
|
-
|
|
29253
|
-
|
|
29276
|
+
if (kind === "ui") {
|
|
29277
|
+
if (bag["--http"] === true && bag["--self-signed"] === true) return usagePlan("gtd: --http and --self-signed cannot be combined", jsonSeen);
|
|
29278
|
+
return {
|
|
29279
|
+
kind: "command",
|
|
29280
|
+
command: {
|
|
29281
|
+
kind: "ui",
|
|
29282
|
+
...bag["--host"] !== void 0 ? { host: bag["--host"] } : {},
|
|
29283
|
+
...bag["--port"] !== void 0 ? { port: bag["--port"] } : {},
|
|
29284
|
+
selfSigned: bag["--self-signed"] ?? false,
|
|
29285
|
+
...bag["--http"] === true ? { http: true } : {},
|
|
29286
|
+
dev: bag["--dev"] ?? false
|
|
29287
|
+
},
|
|
29288
|
+
json,
|
|
29289
|
+
verbose
|
|
29290
|
+
};
|
|
29291
|
+
}
|
|
29254
29292
|
if (kind === "check") return {
|
|
29255
29293
|
kind: "command",
|
|
29256
29294
|
command: {
|
|
@@ -29641,6 +29679,10 @@ var InMemRepo = class InMemRepo {
|
|
|
29641
29679
|
changedPathsWorktree(base) {
|
|
29642
29680
|
return diffTrees(this.treeAt(base), new Map(this.worktree));
|
|
29643
29681
|
}
|
|
29682
|
+
/** Worktree paths the index does not carry. */
|
|
29683
|
+
untrackedPaths() {
|
|
29684
|
+
return [...this.worktree.keys()].filter((k) => !this.index.has(k));
|
|
29685
|
+
}
|
|
29644
29686
|
/** The index vs HEAD — the port's `stagedPaths`. */
|
|
29645
29687
|
stagedPaths() {
|
|
29646
29688
|
return diffTrees(this.treeAt(void 0), this.index);
|
|
@@ -29971,6 +30013,7 @@ const makeGitReaderOps = (repo, root) => ({
|
|
|
29971
30013
|
commitHistory: (base, head) => succeed$1(repo.commitHistory(base, head)),
|
|
29972
30014
|
subjectHistory: (pageSize, skip, head) => succeed$1(repo.subjectHistory(pageSize, skip, head)),
|
|
29973
30015
|
changedPaths: (base) => succeed$1(repo.changedPathsWorktree(base)),
|
|
30016
|
+
untrackedPaths: () => succeed$1(repo.untrackedPaths()),
|
|
29974
30017
|
stagedPaths: () => succeed$1(repo.stagedPaths()),
|
|
29975
30018
|
diffPaths: (base, tip) => tryCatch(() => repo.diffPaths(base, tip)),
|
|
29976
30019
|
authorIdent: () => succeed$1(some({
|