@webappwiz/arbor 0.0.30 → 0.0.32
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/README.md +2 -2
- package/add.d.ts +23 -0
- package/age.d.ts +2 -0
- package/arbor.d.ts +11 -0
- package/attachments.d.ts +36 -0
- package/claim.d.ts +11 -0
- package/config.d.ts +55 -0
- package/config.js +7 -0
- package/dev/assets.d.ts +11 -0
- package/dev.d.ts +48 -0
- package/escalate.d.ts +28 -0
- package/exit.d.ts +42 -0
- package/git.d.ts +82 -0
- package/index.d.ts +2 -0
- package/index.js +4763 -0
- package/journal.d.ts +29 -0
- package/list.d.ts +18 -0
- package/load-config.d.ts +15 -0
- package/log.d.ts +14 -0
- package/merge.d.ts +24 -0
- package/package.json +15 -32
- package/path.d.ts +13 -0
- package/plan.d.ts +83 -0
- package/remove.d.ts +19 -0
- package/repository.d.ts +25 -0
- package/retry.d.ts +17 -0
- package/shell.d.ts +17 -0
- package/show.d.ts +53 -0
- package/snapshot.d.ts +36 -0
- package/table.d.ts +5 -0
- package/todo.d.ts +202 -0
- package/todos.d.ts +75 -0
- package/wait.d.ts +22 -0
- package/worktree-service.d.ts +51 -0
- package/worktree.d.ts +95 -0
- package/AGENTS.md +0 -7
- package/add.test.ts +0 -125
- package/add.ts +0 -192
- package/age.ts +0 -11
- package/arbor.test.ts +0 -145
- package/arbor.ts +0 -429
- package/assets.d.ts +0 -9
- package/attachments.ts +0 -87
- package/build.ts +0 -98
- package/claim.test.ts +0 -89
- package/claim.ts +0 -73
- package/components.json +0 -21
- package/config.ts +0 -58
- package/dev/api.ts +0 -120
- package/dev/app.test.tsx +0 -645
- package/dev/app.tsx +0 -80
- package/dev/assets.ts +0 -16
- package/dev/build/main.txt +0 -68
- package/dev/build/shell.txt +0 -21
- package/dev/build/styles.txt +0 -2263
- package/dev/components/ui/badge.tsx +0 -51
- package/dev/components/ui/button.tsx +0 -57
- package/dev/components/ui/dialog.tsx +0 -154
- package/dev/components/ui/empty.tsx +0 -100
- package/dev/components/ui/input-group.tsx +0 -155
- package/dev/components/ui/input.tsx +0 -19
- package/dev/components/ui/progress.tsx +0 -80
- package/dev/components/ui/textarea.tsx +0 -17
- package/dev/components/ui/toast.tsx +0 -227
- package/dev/feed.ts +0 -69
- package/dev/files.tsx +0 -191
- package/dev/index.html +0 -21
- package/dev/lib/utils.ts +0 -7
- package/dev/main.tsx +0 -22
- package/dev/markdown.test.tsx +0 -133
- package/dev/markdown.tsx +0 -124
- package/dev/mentions.tsx +0 -319
- package/dev/shadcn.css +0 -649
- package/dev/styles.css +0 -107
- package/dev/tags.tsx +0 -44
- package/dev/tasks.tsx +0 -151
- package/dev/todos.tsx +0 -759
- package/dev.test.ts +0 -439
- package/dev.ts +0 -386
- package/e2e.test.ts +0 -256
- package/escalate.test.ts +0 -76
- package/escalate.ts +0 -112
- package/exit.test.ts +0 -71
- package/exit.ts +0 -74
- package/git.ts +0 -294
- package/index.ts +0 -9
- package/journal.ts +0 -89
- package/list.test.ts +0 -82
- package/list.ts +0 -137
- package/load-config.test.ts +0 -121
- package/load-config.ts +0 -62
- package/log.test.ts +0 -65
- package/log.ts +0 -40
- package/merge.test.ts +0 -332
- package/merge.ts +0 -283
- package/path.test.ts +0 -35
- package/path.ts +0 -38
- package/plan.test.ts +0 -318
- package/plan.ts +0 -302
- package/progress.test.ts +0 -54
- package/progress.ts +0 -31
- package/remove.test.ts +0 -68
- package/remove.ts +0 -88
- package/repository.ts +0 -83
- package/retry.test.ts +0 -43
- package/retry.ts +0 -48
- package/shell.ts +0 -44
- package/show.test.ts +0 -91
- package/show.ts +0 -151
- package/snapshot.test.ts +0 -33
- package/snapshot.ts +0 -84
- package/table.ts +0 -20
- package/testing.ts +0 -229
- package/todo.test.ts +0 -490
- package/todo.ts +0 -834
- package/wait.test.ts +0 -61
- package/wait.ts +0 -77
- package/worktree-service.test.ts +0 -158
- package/worktree-service.ts +0 -193
- package/worktree.ts +0 -239
package/dev/styles.css
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
@import "tailwindcss";
|
|
2
|
-
@import "tw-animate-css";
|
|
3
|
-
@import "./shadcn.css";
|
|
4
|
-
|
|
5
|
-
/* Tailwind only emits the utilities it can actually see, and its automatic
|
|
6
|
-
detection does not find them from here. Every file holding a class the page
|
|
7
|
-
renders has to be listed: one that nobody lists comes out of the compiler as
|
|
8
|
-
nothing at all. */
|
|
9
|
-
@source "./app.tsx";
|
|
10
|
-
@source "./todos.tsx";
|
|
11
|
-
@source "./tasks.tsx";
|
|
12
|
-
@source "./markdown.tsx";
|
|
13
|
-
@source "./files.tsx";
|
|
14
|
-
@source "./mentions.tsx";
|
|
15
|
-
@source "./tags.tsx";
|
|
16
|
-
@source "./components/ui";
|
|
17
|
-
|
|
18
|
-
@custom-variant dark (&:is(.dark *));
|
|
19
|
-
|
|
20
|
-
/* shadcn's neutral theme. The page follows whatever the device it is opened
|
|
21
|
-
on is set to, so `dark` is toggled by main.tsx off prefers-color-scheme. */
|
|
22
|
-
:root {
|
|
23
|
-
color-scheme: light;
|
|
24
|
-
--radius: 0.625rem;
|
|
25
|
-
--background: oklch(1 0 0);
|
|
26
|
-
--foreground: oklch(0.145 0 0);
|
|
27
|
-
--card: oklch(1 0 0);
|
|
28
|
-
--card-foreground: oklch(0.145 0 0);
|
|
29
|
-
--popover: oklch(1 0 0);
|
|
30
|
-
--popover-foreground: oklch(0.145 0 0);
|
|
31
|
-
--primary: oklch(0.205 0 0);
|
|
32
|
-
--primary-foreground: oklch(0.985 0 0);
|
|
33
|
-
--secondary: oklch(0.97 0 0);
|
|
34
|
-
--secondary-foreground: oklch(0.205 0 0);
|
|
35
|
-
--muted: oklch(0.97 0 0);
|
|
36
|
-
--muted-foreground: oklch(0.556 0 0);
|
|
37
|
-
--accent: oklch(0.97 0 0);
|
|
38
|
-
--accent-foreground: oklch(0.205 0 0);
|
|
39
|
-
--destructive: oklch(0.577 0.245 27.325);
|
|
40
|
-
--success: oklch(0.627 0.17 149.2);
|
|
41
|
-
--warning: oklch(0.666 0.157 58.3);
|
|
42
|
-
--border: oklch(0.922 0 0);
|
|
43
|
-
--input: oklch(0.922 0 0);
|
|
44
|
-
--ring: oklch(0.708 0 0);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.dark {
|
|
48
|
-
color-scheme: dark;
|
|
49
|
-
--background: oklch(0.145 0 0);
|
|
50
|
-
--foreground: oklch(0.985 0 0);
|
|
51
|
-
--card: oklch(0.205 0 0);
|
|
52
|
-
--card-foreground: oklch(0.985 0 0);
|
|
53
|
-
--popover: oklch(0.205 0 0);
|
|
54
|
-
--popover-foreground: oklch(0.985 0 0);
|
|
55
|
-
--primary: oklch(0.922 0 0);
|
|
56
|
-
--primary-foreground: oklch(0.205 0 0);
|
|
57
|
-
--secondary: oklch(0.269 0 0);
|
|
58
|
-
--secondary-foreground: oklch(0.985 0 0);
|
|
59
|
-
--muted: oklch(0.269 0 0);
|
|
60
|
-
--muted-foreground: oklch(0.708 0 0);
|
|
61
|
-
--accent: oklch(0.269 0 0);
|
|
62
|
-
--accent-foreground: oklch(0.985 0 0);
|
|
63
|
-
--destructive: oklch(0.704 0.191 22.216);
|
|
64
|
-
--success: oklch(0.723 0.192 149.6);
|
|
65
|
-
--warning: oklch(0.769 0.165 70.1);
|
|
66
|
-
--border: oklch(1 0 0 / 10%);
|
|
67
|
-
--input: oklch(1 0 0 / 15%);
|
|
68
|
-
--ring: oklch(0.556 0 0);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
@theme inline {
|
|
72
|
-
--color-background: var(--background);
|
|
73
|
-
--color-foreground: var(--foreground);
|
|
74
|
-
--color-card: var(--card);
|
|
75
|
-
--color-card-foreground: var(--card-foreground);
|
|
76
|
-
--color-popover: var(--popover);
|
|
77
|
-
--color-popover-foreground: var(--popover-foreground);
|
|
78
|
-
--color-primary: var(--primary);
|
|
79
|
-
--color-primary-foreground: var(--primary-foreground);
|
|
80
|
-
--color-secondary: var(--secondary);
|
|
81
|
-
--color-secondary-foreground: var(--secondary-foreground);
|
|
82
|
-
--color-muted: var(--muted);
|
|
83
|
-
--color-muted-foreground: var(--muted-foreground);
|
|
84
|
-
--color-accent: var(--accent);
|
|
85
|
-
--color-accent-foreground: var(--accent-foreground);
|
|
86
|
-
--color-destructive: var(--destructive);
|
|
87
|
-
--color-success: var(--success);
|
|
88
|
-
--color-warning: var(--warning);
|
|
89
|
-
--color-border: var(--border);
|
|
90
|
-
--color-input: var(--input);
|
|
91
|
-
--color-ring: var(--ring);
|
|
92
|
-
--radius-sm: calc(var(--radius) - 4px);
|
|
93
|
-
--radius-md: calc(var(--radius) - 2px);
|
|
94
|
-
--radius-lg: var(--radius);
|
|
95
|
-
--radius-xl: calc(var(--radius) + 4px);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
@layer base {
|
|
99
|
-
* {
|
|
100
|
-
@apply border-border outline-ring/50;
|
|
101
|
-
}
|
|
102
|
-
/* A long URL or path breaks rather than pushing the page wider; lines
|
|
103
|
-
meant to stay on one line truncate instead. */
|
|
104
|
-
body {
|
|
105
|
-
@apply bg-background text-foreground antialiased wrap-anywhere;
|
|
106
|
-
}
|
|
107
|
-
}
|
package/dev/tags.tsx
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { TagIcon } from "lucide-react";
|
|
2
|
-
import type { JSX } from "react";
|
|
3
|
-
import { cn } from "#dev/lib/utils.ts";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* A row of tags over the list, the way a mail client filters by label: All,
|
|
7
|
-
* then every tag a todo has. Tapping one shows only its todos.
|
|
8
|
-
*/
|
|
9
|
-
export function TagFilter({
|
|
10
|
-
tags,
|
|
11
|
-
selected,
|
|
12
|
-
onSelect,
|
|
13
|
-
}: {
|
|
14
|
-
tags: string[];
|
|
15
|
-
selected: string | null;
|
|
16
|
-
onSelect: (tag: string | null) => void;
|
|
17
|
-
}): JSX.Element {
|
|
18
|
-
const chip = (label: string, value: string | null) => (
|
|
19
|
-
<button
|
|
20
|
-
key={label}
|
|
21
|
-
type="button"
|
|
22
|
-
aria-pressed={selected === value}
|
|
23
|
-
onClick={() => onSelect(value)}
|
|
24
|
-
className={cn(
|
|
25
|
-
"inline-flex cursor-pointer items-center gap-1 rounded-full border px-2.5 py-0.5 text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
26
|
-
selected === value
|
|
27
|
-
? "border-primary bg-primary text-primary-foreground"
|
|
28
|
-
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
29
|
-
)}
|
|
30
|
-
>
|
|
31
|
-
{value !== null && <TagIcon aria-hidden className="size-3" />}
|
|
32
|
-
{label}
|
|
33
|
-
</button>
|
|
34
|
-
);
|
|
35
|
-
return (
|
|
36
|
-
<fieldset
|
|
37
|
-
aria-label="filter by tag"
|
|
38
|
-
className="m-0 flex flex-wrap gap-1.5 border-0 p-0"
|
|
39
|
-
>
|
|
40
|
-
{chip("All", null)}
|
|
41
|
-
{tags.map((tag) => chip(tag, tag))}
|
|
42
|
-
</fieldset>
|
|
43
|
-
);
|
|
44
|
-
}
|
package/dev/tasks.tsx
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { type JSX, type ReactNode, useState } from "react";
|
|
2
|
-
import { Badge } from "#dev/components/ui/badge.tsx";
|
|
3
|
-
import {
|
|
4
|
-
Dialog,
|
|
5
|
-
DialogContent,
|
|
6
|
-
DialogDescription,
|
|
7
|
-
DialogHeader,
|
|
8
|
-
DialogTitle,
|
|
9
|
-
} from "#dev/components/ui/dialog.tsx";
|
|
10
|
-
import { Progress as Bar } from "#dev/components/ui/progress.tsx";
|
|
11
|
-
import { type Progress as Counted, progress } from "../progress";
|
|
12
|
-
import type { Details } from "../show";
|
|
13
|
-
import { Markdown } from "./markdown";
|
|
14
|
-
|
|
15
|
-
/** A tree in one of these needs fixing rather than driving. */
|
|
16
|
-
const BROKEN = new Set(["orphaned", "stray", "unrecorded", "unknown"]);
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Every task in a line: its name, a bar for how far along its plan is, and a status only
|
|
20
|
-
* when the status is news. The rest (branch, paths, the whole plan) waits
|
|
21
|
-
* behind a tap.
|
|
22
|
-
*/
|
|
23
|
-
export function Tasks({ tasks }: { tasks: Details[] }): JSX.Element {
|
|
24
|
-
const [opened, setOpened] = useState<Details | null>(null);
|
|
25
|
-
|
|
26
|
-
// One line, not a big empty state: the todos below it are the page then.
|
|
27
|
-
if (tasks.length === 0) {
|
|
28
|
-
return (
|
|
29
|
-
<p className="text-muted-foreground text-sm">
|
|
30
|
-
No tasks: <code>arbor add <task></code> starts one.
|
|
31
|
-
</p>
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<>
|
|
37
|
-
<ul className="flex flex-col">
|
|
38
|
-
{tasks.map((task) => (
|
|
39
|
-
<li key={task.task}>
|
|
40
|
-
<button
|
|
41
|
-
type="button"
|
|
42
|
-
onClick={() => setOpened(task)}
|
|
43
|
-
className="-mx-2 flex w-[calc(100%+1rem)] items-center gap-3 rounded-lg px-2 py-2 text-left hover:bg-muted"
|
|
44
|
-
>
|
|
45
|
-
<span className="min-w-0 flex-1 truncate text-sm">
|
|
46
|
-
{task.task}
|
|
47
|
-
</span>
|
|
48
|
-
<Status status={task.status} />
|
|
49
|
-
<PlanProgress plan={task.plan} />
|
|
50
|
-
</button>
|
|
51
|
-
</li>
|
|
52
|
-
))}
|
|
53
|
-
</ul>
|
|
54
|
-
<Dialog
|
|
55
|
-
open={opened !== null}
|
|
56
|
-
onOpenChange={(open) => {
|
|
57
|
-
if (!open) {
|
|
58
|
-
setOpened(null);
|
|
59
|
-
}
|
|
60
|
-
}}
|
|
61
|
-
>
|
|
62
|
-
{opened && <Task task={opened} />}
|
|
63
|
-
</Dialog>
|
|
64
|
-
</>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** Working and merging are the normal case, so they say nothing. */
|
|
69
|
-
function Status({ status }: { status: string }): JSX.Element | null {
|
|
70
|
-
if (status === "escalated") {
|
|
71
|
-
return <Badge variant="secondary">escalated</Badge>;
|
|
72
|
-
}
|
|
73
|
-
if (BROKEN.has(status)) {
|
|
74
|
-
return <Badge variant="destructive">{status}</Badge>;
|
|
75
|
-
}
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function PlanProgress({ plan }: { plan: string | null }): JSX.Element | null {
|
|
80
|
-
const counted = plan === null ? null : progress(plan);
|
|
81
|
-
return counted && <Progress {...counted} />;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/** A bar and its count, the end of a task's or a tag's row. */
|
|
85
|
-
export function Progress({ done, total }: Counted): JSX.Element {
|
|
86
|
-
return (
|
|
87
|
-
<span className="flex w-28 shrink-0 items-center gap-2">
|
|
88
|
-
<Bar value={done} max={total} aria-label="progress" className="flex-1" />
|
|
89
|
-
<span className="w-8 text-right text-muted-foreground text-xs tabular-nums">
|
|
90
|
-
{done}/{total}
|
|
91
|
-
</span>
|
|
92
|
-
</span>
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/** One task, all of it, in a dialog over the task list or a todo that names it. */
|
|
97
|
-
export function Task({ task }: { task: Details }): JSX.Element {
|
|
98
|
-
const fields: [string, ReactNode][] = [
|
|
99
|
-
["status", task.status],
|
|
100
|
-
["branch", task.branch],
|
|
101
|
-
["base", task.base],
|
|
102
|
-
["worktree", task.worktree],
|
|
103
|
-
["lease", task.lease],
|
|
104
|
-
["commits", String(task.ahead ?? "?")],
|
|
105
|
-
|
|
106
|
-
[
|
|
107
|
-
"diff",
|
|
108
|
-
task.added === null ? (
|
|
109
|
-
"?"
|
|
110
|
-
) : (
|
|
111
|
-
<span key="diff" className="tabular-nums">
|
|
112
|
-
<span className="text-success">+{task.added}</span>{" "}
|
|
113
|
-
<span className="text-destructive">-{task.removed ?? 0}</span>
|
|
114
|
-
</span>
|
|
115
|
-
),
|
|
116
|
-
],
|
|
117
|
-
["age", task.age ?? "?"],
|
|
118
|
-
];
|
|
119
|
-
return (
|
|
120
|
-
<DialogContent className="max-h-[85dvh] grid-cols-[minmax(0,1fr)] overflow-y-auto sm:max-w-xl">
|
|
121
|
-
<DialogHeader>
|
|
122
|
-
<DialogTitle>{task.task}</DialogTitle>
|
|
123
|
-
<DialogDescription>{task.escalation ?? task.status}</DialogDescription>
|
|
124
|
-
</DialogHeader>
|
|
125
|
-
<div className="flex min-w-0 flex-col gap-6 text-sm">
|
|
126
|
-
<dl className="grid grid-cols-[max-content_minmax(0,1fr)] gap-x-4 gap-y-1">
|
|
127
|
-
{fields.map(([name, value]) => (
|
|
128
|
-
<div key={name} className="contents">
|
|
129
|
-
<dt className="text-muted-foreground">{name}</dt>
|
|
130
|
-
<dd className="truncate">{value}</dd>
|
|
131
|
-
</div>
|
|
132
|
-
))}
|
|
133
|
-
</dl>
|
|
134
|
-
{task.plan === null ? (
|
|
135
|
-
<p className="text-muted-foreground">
|
|
136
|
-
No ARBOR.md: whoever picks this up starts from the diff.
|
|
137
|
-
</p>
|
|
138
|
-
) : (
|
|
139
|
-
<Markdown text={task.plan.replace(/^\s*#\s[^\n]*/, "")} />
|
|
140
|
-
)}
|
|
141
|
-
{task.planProblems.length > 0 && (
|
|
142
|
-
<ul className="flex flex-col gap-1 text-muted-foreground text-xs">
|
|
143
|
-
{task.planProblems.map((problem) => (
|
|
144
|
-
<li key={problem}>{problem}</li>
|
|
145
|
-
))}
|
|
146
|
-
</ul>
|
|
147
|
-
)}
|
|
148
|
-
</div>
|
|
149
|
-
</DialogContent>
|
|
150
|
-
);
|
|
151
|
-
}
|