patchwork-os 0.2.0-alpha.0 → 0.2.0-alpha.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/README.md +41 -46
- package/dist/commands/dashboard.d.ts +47 -0
- package/dist/commands/dashboard.js +319 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/connectors/github.d.ts +44 -0
- package/dist/connectors/github.js +113 -0
- package/dist/connectors/github.js.map +1 -0
- package/dist/connectors/gmail.d.ts +40 -0
- package/dist/connectors/gmail.js +275 -0
- package/dist/connectors/gmail.js.map +1 -0
- package/dist/index.js +116 -22
- package/dist/index.js.map +1 -1
- package/dist/recipes/yamlRunner.d.ts +95 -0
- package/dist/recipes/yamlRunner.js +533 -0
- package/dist/recipes/yamlRunner.js.map +1 -0
- package/dist/server.js +180 -1
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
- package/templates/recipes/gmail-health-check.yaml +19 -0
- package/templates/recipes/inbox-triage.yaml +15 -0
- package/templates/recipes/morning-brief.yaml +55 -0
- package/templates/scheduled-tasks/morning-brief/SKILL.md +37 -0
package/README.md
CHANGED
|
@@ -2,71 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
**AI that works while you're away. Runs on your machine. Doesn't lock you in.**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
- **A developer's overnight.** Tests run on every push, flaky ones quarantined, a clean PR opened against the failing build. You wake up to a passing CI and a short note on what changed.
|
|
9
|
-
- **A small business's inbox.** New customer questions triaged, invoices matched to orders, three follow-ups drafted in your voice. Nothing sends without your nod.
|
|
5
|
+
```bash
|
|
6
|
+
npx patchwork-os@alpha patchwork-init
|
|
7
|
+
```
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
That one command sets up 5 local recipes, detects Ollama, and drops a terminal dashboard at your fingertips — under 90 seconds on a warm npm cache.
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
- **Your models, your keys** — Claude, GPT, Gemini, Grok, or local Ollama. Swap anytime. Nothing phones home.
|
|
15
|
-
- **Oversight you actually use** — a dashboard on your phone approves or rejects anything risky before it happens.
|
|
11
|
+
## What it does
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
Patchwork OS watches for things that matter, acts, and asks before anything risky goes out.
|
|
18
14
|
|
|
19
|
-
|
|
15
|
+
- **A developer's overnight.** Tests fail on a push → a one-paragraph triage note lands in your inbox. You wake up knowing where to look.
|
|
16
|
+
- **A small business's inbox.** New customer questions triaged, follow-ups drafted in your voice. Nothing sends without your nod.
|
|
17
|
+
- **A parent's morning.** Field-trip form flagged, reply drafted to the teacher — done before the first coffee.
|
|
20
18
|
|
|
21
|
-
##
|
|
19
|
+
## How it works
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- **Multi-model from day one** — Claude, OpenAI, Gemini, Grok, local LLMs (Ollama)
|
|
27
|
-
- **Drag-and-drop recipes** — YAML automation anyone can write
|
|
28
|
-
- **Oversight dashboard** — approve/reject high-risk actions from phone
|
|
29
|
-
- **Proven core** — 2,725+ tests, real-time IDE context, 170 built-in tools
|
|
30
|
-
- **100% MIT**
|
|
21
|
+
- **Recipes** — plain YAML files describe what to watch and what to do. Share them like dotfiles. No code required.
|
|
22
|
+
- **Your models, your keys** — Claude, GPT, Gemini, Grok, or local Ollama. Swap anytime. Nothing phones home.
|
|
23
|
+
- **Oversight first** — everything risky lands in `~/.patchwork/inbox/` for your approval before it goes anywhere.
|
|
31
24
|
|
|
32
|
-
##
|
|
25
|
+
## After init
|
|
33
26
|
|
|
34
27
|
```bash
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
patchwork-os recipe list # see installed recipes
|
|
29
|
+
patchwork-os recipe run daily-status # run one now
|
|
30
|
+
patchwork-os # open terminal dashboard
|
|
37
31
|
```
|
|
38
32
|
|
|
39
|
-
|
|
33
|
+
The oversight web UI runs at `http://localhost:3100` when the bridge is active.
|
|
40
34
|
|
|
41
|
-
##
|
|
35
|
+
## 5 starter recipes (no API key needed)
|
|
42
36
|
|
|
43
|
-
|
|
|
37
|
+
| Recipe | Trigger | What it does |
|
|
44
38
|
|---|---|---|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
| 5 | Optional hosted tier | year 2 |
|
|
51
|
-
|
|
52
|
-
Full plan: `../Patchwork_OS_Plan_and_Roadmap.docx`.
|
|
39
|
+
| `ambient-journal` | git commit | appends one line to `~/.patchwork/journal/` |
|
|
40
|
+
| `daily-status` | cron 08:00 | morning brief from yesterday's commits |
|
|
41
|
+
| `watch-failing-tests` | test run | drops triage note to inbox on failure |
|
|
42
|
+
| `lint-on-save` | file save | surfaces new TS/JS diagnostics to inbox |
|
|
43
|
+
| `stale-branches` | cron weekly | lists branches older than 30 days |
|
|
53
44
|
|
|
54
|
-
|
|
45
|
+
All 5 write to `~/.patchwork/inbox/` only. Nothing is sent anywhere without your approval.
|
|
55
46
|
|
|
56
|
-
|
|
57
|
-
bridge's MCP server, automation hooks, orchestrator, plugin system, and tool
|
|
58
|
-
library are the substrate. Patchwork adds:
|
|
59
|
-
|
|
60
|
-
1. `src/adapters/` — `ModelAdapter` interface + per-provider implementations
|
|
61
|
-
2. `src/recipes/` — YAML recipe parser → existing automation DSL *(planned)*
|
|
62
|
-
3. `dashboard/` — Next.js oversight UI *(planned)*
|
|
47
|
+
## Roadmap
|
|
63
48
|
|
|
64
|
-
|
|
49
|
+
| Phase | Status |
|
|
50
|
+
|---|---|
|
|
51
|
+
| Foundation — init, recipes, terminal dashboard | **shipped (W1)** |
|
|
52
|
+
| Connectors — Gmail, calendar, Slack | W2 |
|
|
53
|
+
| Mobile oversight — approve from phone | W3 |
|
|
54
|
+
| Community recipes + ecosystem | Q3 |
|
|
65
55
|
|
|
66
|
-
##
|
|
56
|
+
## From source
|
|
67
57
|
|
|
68
|
-
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/Oolab-labs/patchwork-os
|
|
60
|
+
cd patchwork-os
|
|
61
|
+
npm install && npm run build
|
|
62
|
+
node dist/index.js patchwork-init
|
|
63
|
+
```
|
|
69
64
|
|
|
70
65
|
## License
|
|
71
66
|
|
|
72
|
-
MIT © Oolab Labs.
|
|
67
|
+
MIT © Oolab Labs. Built on the [Claude IDE Bridge](./README.bridge.md).
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal dashboard — `patchwork-os` with no args.
|
|
3
|
+
*
|
|
4
|
+
* Polls ~/.patchwork/runs.jsonl (recent recipe activity) and inbox/ (pending
|
|
5
|
+
* items). Renders to stdout with ANSI color. Supports TTY and non-TTY output.
|
|
6
|
+
*
|
|
7
|
+
* Keybindings (TTY only):
|
|
8
|
+
* q / Ctrl-C quit
|
|
9
|
+
* r refresh now
|
|
10
|
+
* o <n> open inbox item n in $EDITOR
|
|
11
|
+
* a <n> approve inbox item (move to ~/.patchwork/approved/)
|
|
12
|
+
*/
|
|
13
|
+
export interface RunEntry {
|
|
14
|
+
seq: number;
|
|
15
|
+
recipeName?: string;
|
|
16
|
+
trigger?: string;
|
|
17
|
+
status: "done" | "error" | "running" | "pending" | string;
|
|
18
|
+
createdAt?: number;
|
|
19
|
+
doneAt?: number;
|
|
20
|
+
durationMs?: number;
|
|
21
|
+
outputTail?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface InboxItem {
|
|
24
|
+
index: number;
|
|
25
|
+
filename: string;
|
|
26
|
+
fullPath: string;
|
|
27
|
+
mtime: number;
|
|
28
|
+
preview: string;
|
|
29
|
+
}
|
|
30
|
+
export interface DashboardData {
|
|
31
|
+
version: string;
|
|
32
|
+
recipeCount: number;
|
|
33
|
+
recentRuns: RunEntry[];
|
|
34
|
+
inboxItems: InboxItem[];
|
|
35
|
+
}
|
|
36
|
+
export interface DashboardDeps {
|
|
37
|
+
patchworkDir?: string;
|
|
38
|
+
now?: () => Date;
|
|
39
|
+
stdout?: NodeJS.WriteStream;
|
|
40
|
+
/** Override for tests — skip TTY interaction. */
|
|
41
|
+
noTTY?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export declare function loadRecentRuns(patchworkDir: string, limit?: number): RunEntry[];
|
|
44
|
+
export declare function loadInboxItems(patchworkDir: string, limit?: number): InboxItem[];
|
|
45
|
+
export declare function countRecipes(patchworkDir: string): number;
|
|
46
|
+
export declare function renderDashboard(data: DashboardData, now: Date): string;
|
|
47
|
+
export declare function runDashboard(deps?: DashboardDeps): Promise<void>;
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal dashboard — `patchwork-os` with no args.
|
|
3
|
+
*
|
|
4
|
+
* Polls ~/.patchwork/runs.jsonl (recent recipe activity) and inbox/ (pending
|
|
5
|
+
* items). Renders to stdout with ANSI color. Supports TTY and non-TTY output.
|
|
6
|
+
*
|
|
7
|
+
* Keybindings (TTY only):
|
|
8
|
+
* q / Ctrl-C quit
|
|
9
|
+
* r refresh now
|
|
10
|
+
* o <n> open inbox item n in $EDITOR
|
|
11
|
+
* a <n> approve inbox item (move to ~/.patchwork/approved/)
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync, } from "node:fs";
|
|
14
|
+
import os from "node:os";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import readline from "node:readline";
|
|
17
|
+
// ── ANSI helpers ──────────────────────────────────────────────────────────────
|
|
18
|
+
const ESC = "\x1b[";
|
|
19
|
+
const RESET = "\x1b[0m";
|
|
20
|
+
const BOLD = "\x1b[1m";
|
|
21
|
+
const DIM = "\x1b[2m";
|
|
22
|
+
const GREEN = "\x1b[32m";
|
|
23
|
+
const YELLOW = "\x1b[33m";
|
|
24
|
+
const RED = "\x1b[31m";
|
|
25
|
+
const CYAN = "\x1b[36m";
|
|
26
|
+
const BLUE = "\x1b[34m";
|
|
27
|
+
function color(c, s) {
|
|
28
|
+
return `${c}${s}${RESET}`;
|
|
29
|
+
}
|
|
30
|
+
function clearScreen(out) {
|
|
31
|
+
if (out.isTTY) {
|
|
32
|
+
out.write(`${ESC}2J${ESC}H`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// ── Data loading ──────────────────────────────────────────────────────────────
|
|
36
|
+
export function loadRecentRuns(patchworkDir, limit = 10) {
|
|
37
|
+
const runsPath = path.join(patchworkDir, "runs.jsonl");
|
|
38
|
+
if (!existsSync(runsPath))
|
|
39
|
+
return [];
|
|
40
|
+
try {
|
|
41
|
+
const lines = readFileSync(runsPath, "utf-8")
|
|
42
|
+
.split("\n")
|
|
43
|
+
.filter(Boolean)
|
|
44
|
+
.slice(-limit * 2);
|
|
45
|
+
const entries = [];
|
|
46
|
+
for (const line of lines) {
|
|
47
|
+
try {
|
|
48
|
+
entries.push(JSON.parse(line));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// skip malformed
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return entries.slice(-limit).reverse();
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function loadInboxItems(patchworkDir, limit = 20) {
|
|
61
|
+
const inboxDir = path.join(patchworkDir, "inbox");
|
|
62
|
+
if (!existsSync(inboxDir))
|
|
63
|
+
return [];
|
|
64
|
+
try {
|
|
65
|
+
const files = readdirSync(inboxDir)
|
|
66
|
+
.filter((f) => !f.startsWith("."))
|
|
67
|
+
.map((f) => {
|
|
68
|
+
const fp = path.join(inboxDir, f);
|
|
69
|
+
try {
|
|
70
|
+
const st = statSync(fp);
|
|
71
|
+
return { f, mtime: st.mtimeMs };
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
.filter((x) => x !== null)
|
|
78
|
+
.sort((a, b) => b.mtime - a.mtime)
|
|
79
|
+
.slice(0, limit);
|
|
80
|
+
return files.map(({ f, mtime }, i) => {
|
|
81
|
+
const fp = path.join(inboxDir, f);
|
|
82
|
+
let preview = "";
|
|
83
|
+
try {
|
|
84
|
+
preview = readFileSync(fp, "utf-8")
|
|
85
|
+
.split("\n")
|
|
86
|
+
.slice(0, 3)
|
|
87
|
+
.join(" ")
|
|
88
|
+
.slice(0, 120);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
preview = "(unreadable)";
|
|
92
|
+
}
|
|
93
|
+
return { index: i + 1, filename: f, fullPath: fp, mtime, preview };
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export function countRecipes(patchworkDir) {
|
|
101
|
+
const recipesDir = path.join(patchworkDir, "recipes");
|
|
102
|
+
if (!existsSync(recipesDir))
|
|
103
|
+
return 0;
|
|
104
|
+
try {
|
|
105
|
+
return readdirSync(recipesDir).filter((f) => (f.endsWith(".yaml") || f.endsWith(".yml") || f.endsWith(".json")) &&
|
|
106
|
+
!f.endsWith(".permissions.json")).length;
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// ── Rendering ─────────────────────────────────────────────────────────────────
|
|
113
|
+
function formatAge(ms, now) {
|
|
114
|
+
const diff = Math.floor((now - ms) / 1000);
|
|
115
|
+
if (diff < 60)
|
|
116
|
+
return `${diff}s ago`;
|
|
117
|
+
if (diff < 3600)
|
|
118
|
+
return `${Math.floor(diff / 60)}m ago`;
|
|
119
|
+
if (diff < 86400)
|
|
120
|
+
return `${Math.floor(diff / 3600)}h ago`;
|
|
121
|
+
return `${Math.floor(diff / 86400)}d ago`;
|
|
122
|
+
}
|
|
123
|
+
function statusBadge(status) {
|
|
124
|
+
switch (status) {
|
|
125
|
+
case "done":
|
|
126
|
+
return color(GREEN, "✓ done");
|
|
127
|
+
case "error":
|
|
128
|
+
return color(RED, "✗ error");
|
|
129
|
+
case "running":
|
|
130
|
+
return color(YELLOW, "⟳ running");
|
|
131
|
+
default:
|
|
132
|
+
return color(DIM, status);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export function renderDashboard(data, now) {
|
|
136
|
+
const nowMs = now.getTime();
|
|
137
|
+
const lines = [];
|
|
138
|
+
// Header
|
|
139
|
+
lines.push(`${BOLD}${BLUE}Patchwork OS${RESET} ${DIM}v${data.version}${RESET} • ${color(CYAN, String(data.recipeCount))} recipes active`);
|
|
140
|
+
lines.push("");
|
|
141
|
+
// Recent activity
|
|
142
|
+
lines.push(color(BOLD, "RECENT (last 10 runs)"));
|
|
143
|
+
if (data.recentRuns.length === 0) {
|
|
144
|
+
lines.push(` ${DIM}No runs yet. Try: patchwork-os recipe run ambient-journal${RESET}`);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
for (const run of data.recentRuns) {
|
|
148
|
+
const ts = run.createdAt ? `[${formatAge(run.createdAt, nowMs)}]` : "";
|
|
149
|
+
const name = run.recipeName ?? run.trigger ?? "unknown";
|
|
150
|
+
const badge = statusBadge(run.status);
|
|
151
|
+
const dur = run.durationMs
|
|
152
|
+
? ` (${(run.durationMs / 1000).toFixed(1)}s)`
|
|
153
|
+
: "";
|
|
154
|
+
const tail = run.outputTail
|
|
155
|
+
? ` ${DIM}→ ${run.outputTail.split("\n")[0]?.slice(0, 80)}${RESET}`
|
|
156
|
+
: "";
|
|
157
|
+
lines.push(` ${DIM}${ts.padEnd(10)}${RESET} ${color(CYAN, name).padEnd(30)} ${badge}${dur}${tail}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
lines.push("");
|
|
161
|
+
// Inbox
|
|
162
|
+
lines.push(color(BOLD, `INBOX (${data.inboxItems.length} pending approval)`));
|
|
163
|
+
if (data.inboxItems.length === 0) {
|
|
164
|
+
lines.push(` ${DIM}Empty${RESET}`);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
for (const item of data.inboxItems) {
|
|
168
|
+
const age = formatAge(item.mtime, nowMs);
|
|
169
|
+
lines.push(` ${color(YELLOW, String(item.index).padStart(2))} ${item.filename.padEnd(40)} ${DIM}${age}${RESET}`);
|
|
170
|
+
if (item.preview) {
|
|
171
|
+
lines.push(` ${DIM}${item.preview}${RESET}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
lines.push("");
|
|
176
|
+
return lines.join("\n");
|
|
177
|
+
}
|
|
178
|
+
function renderHelp(isTTY) {
|
|
179
|
+
if (!isTTY)
|
|
180
|
+
return "";
|
|
181
|
+
return `${DIM} q quit r refresh o <n> open in $EDITOR a <n> approve${RESET}\n`;
|
|
182
|
+
}
|
|
183
|
+
// ── Approve / open helpers ────────────────────────────────────────────────────
|
|
184
|
+
function approveItem(item, patchworkDir) {
|
|
185
|
+
const approvedDir = path.join(patchworkDir, "approved");
|
|
186
|
+
mkdirSync(approvedDir, { recursive: true });
|
|
187
|
+
const dest = path.join(approvedDir, item.filename);
|
|
188
|
+
renameSync(item.fullPath, dest);
|
|
189
|
+
return ` ✓ moved to approved/${item.filename}`;
|
|
190
|
+
}
|
|
191
|
+
function openInEditor(item) {
|
|
192
|
+
const editor = process.env.EDITOR ?? process.env.VISUAL ?? "vi";
|
|
193
|
+
const { spawnSync } = require("node:child_process");
|
|
194
|
+
spawnSync(editor, [item.fullPath], { stdio: "inherit" });
|
|
195
|
+
}
|
|
196
|
+
// ── Main loop ─────────────────────────────────────────────────────────────────
|
|
197
|
+
export async function runDashboard(deps = {}) {
|
|
198
|
+
const patchworkDir = deps.patchworkDir ?? path.join(os.homedir(), ".patchwork");
|
|
199
|
+
const out = deps.stdout ?? process.stdout;
|
|
200
|
+
const isTTY = !deps.noTTY && out.isTTY === true;
|
|
201
|
+
const getNow = deps.now ?? (() => new Date());
|
|
202
|
+
// Read version from package.json
|
|
203
|
+
let version = "0.2.0";
|
|
204
|
+
try {
|
|
205
|
+
const pkg = JSON.parse(readFileSync(path.join(path.dirname(path.dirname(new URL(import.meta.url).pathname)), "package.json"), "utf-8"));
|
|
206
|
+
version = pkg.version;
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// fallback
|
|
210
|
+
}
|
|
211
|
+
function getData() {
|
|
212
|
+
return {
|
|
213
|
+
version,
|
|
214
|
+
recipeCount: countRecipes(patchworkDir),
|
|
215
|
+
recentRuns: loadRecentRuns(patchworkDir),
|
|
216
|
+
inboxItems: loadInboxItems(patchworkDir),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function refresh() {
|
|
220
|
+
if (isTTY)
|
|
221
|
+
clearScreen(out);
|
|
222
|
+
const data = getData();
|
|
223
|
+
out.write(renderDashboard(data, getNow()));
|
|
224
|
+
out.write(renderHelp(isTTY));
|
|
225
|
+
if (!isTTY) {
|
|
226
|
+
// Non-TTY: print once and exit
|
|
227
|
+
process.exit(0);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (!isTTY) {
|
|
231
|
+
refresh();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
// TTY interactive mode
|
|
235
|
+
refresh();
|
|
236
|
+
const pollInterval = setInterval(refresh, 5_000);
|
|
237
|
+
readline.emitKeypressEvents(process.stdin);
|
|
238
|
+
if (process.stdin.isTTY) {
|
|
239
|
+
process.stdin.setRawMode(true);
|
|
240
|
+
}
|
|
241
|
+
let inputBuffer = "";
|
|
242
|
+
function handleKey(str, key) {
|
|
243
|
+
if (key?.ctrl && key.name === "c") {
|
|
244
|
+
cleanup();
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const ch = str ?? "";
|
|
248
|
+
if (ch === "q") {
|
|
249
|
+
cleanup();
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (ch === "r") {
|
|
253
|
+
refresh();
|
|
254
|
+
inputBuffer = "";
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (ch === "\r" || ch === "\n") {
|
|
258
|
+
const parts = inputBuffer.trim().split(/\s+/);
|
|
259
|
+
const cmd = parts[0]?.toLowerCase();
|
|
260
|
+
const idx = Number(parts[1]);
|
|
261
|
+
inputBuffer = "";
|
|
262
|
+
if ((cmd === "o" || cmd === "a") && Number.isFinite(idx) && idx > 0) {
|
|
263
|
+
const data = getData();
|
|
264
|
+
const item = data.inboxItems.find((x) => x.index === idx);
|
|
265
|
+
if (!item) {
|
|
266
|
+
out.write(`\n Item ${idx} not found.\n`);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (cmd === "o") {
|
|
270
|
+
cleanup(false);
|
|
271
|
+
openInEditor(item);
|
|
272
|
+
// Re-enter dashboard after editor exits
|
|
273
|
+
if (process.stdin.isTTY)
|
|
274
|
+
process.stdin.setRawMode(true);
|
|
275
|
+
refresh();
|
|
276
|
+
const newInterval = setInterval(refresh, 5_000);
|
|
277
|
+
process.stdin.on("keypress", handleKey);
|
|
278
|
+
process.once("SIGINT", () => {
|
|
279
|
+
clearInterval(newInterval);
|
|
280
|
+
process.exit(0);
|
|
281
|
+
});
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (cmd === "a") {
|
|
285
|
+
const msg = approveItem(item, patchworkDir);
|
|
286
|
+
out.write(`\n${msg}\n`);
|
|
287
|
+
setTimeout(refresh, 200);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
// Accumulate input for multi-char commands like "o 2"
|
|
294
|
+
if (/[\w\s]/.test(ch)) {
|
|
295
|
+
inputBuffer += ch;
|
|
296
|
+
out.write(ch);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
process.stdin.on("keypress", handleKey);
|
|
300
|
+
process.once("SIGINT", cleanup);
|
|
301
|
+
function cleanup(doExit = true) {
|
|
302
|
+
clearInterval(pollInterval);
|
|
303
|
+
process.stdin.removeListener("keypress", handleKey);
|
|
304
|
+
if (process.stdin.isTTY) {
|
|
305
|
+
try {
|
|
306
|
+
process.stdin.setRawMode(false);
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
/* ignore */
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
out.write("\n");
|
|
313
|
+
if (doExit)
|
|
314
|
+
process.exit(0);
|
|
315
|
+
}
|
|
316
|
+
// Keep process alive
|
|
317
|
+
await new Promise(() => { });
|
|
318
|
+
}
|
|
319
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/commands/dashboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub connector — uses the `gh` CLI for all operations.
|
|
3
|
+
* No OAuth app required; piggybacks on `gh auth login`.
|
|
4
|
+
*
|
|
5
|
+
* Exported step helpers used by yamlRunner:
|
|
6
|
+
* listIssues(opts) — open issues assigned to / mentioning viewer
|
|
7
|
+
* listPRs(opts) — open PRs authored by / requested for review by viewer
|
|
8
|
+
* getStatus() — { connected: boolean, user?: string }
|
|
9
|
+
*/
|
|
10
|
+
export interface GitHubIssue {
|
|
11
|
+
number: number;
|
|
12
|
+
title: string;
|
|
13
|
+
repo: string;
|
|
14
|
+
url: string;
|
|
15
|
+
labels: string[];
|
|
16
|
+
updatedAt: string;
|
|
17
|
+
}
|
|
18
|
+
export interface GitHubPR {
|
|
19
|
+
number: number;
|
|
20
|
+
title: string;
|
|
21
|
+
repo: string;
|
|
22
|
+
url: string;
|
|
23
|
+
isDraft: boolean;
|
|
24
|
+
reviewDecision: string;
|
|
25
|
+
updatedAt: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ListIssuesOpts {
|
|
28
|
+
assignee?: string;
|
|
29
|
+
mention?: string;
|
|
30
|
+
limit?: number;
|
|
31
|
+
repo?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface ListPRsOpts {
|
|
34
|
+
author?: string;
|
|
35
|
+
reviewRequested?: string;
|
|
36
|
+
limit?: number;
|
|
37
|
+
repo?: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function getStatus(): {
|
|
40
|
+
connected: boolean;
|
|
41
|
+
user?: string;
|
|
42
|
+
};
|
|
43
|
+
export declare function listIssues(opts?: ListIssuesOpts): GitHubIssue[];
|
|
44
|
+
export declare function listPRs(opts?: ListPRsOpts): GitHubPR[];
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub connector — uses the `gh` CLI for all operations.
|
|
3
|
+
* No OAuth app required; piggybacks on `gh auth login`.
|
|
4
|
+
*
|
|
5
|
+
* Exported step helpers used by yamlRunner:
|
|
6
|
+
* listIssues(opts) — open issues assigned to / mentioning viewer
|
|
7
|
+
* listPRs(opts) — open PRs authored by / requested for review by viewer
|
|
8
|
+
* getStatus() — { connected: boolean, user?: string }
|
|
9
|
+
*/
|
|
10
|
+
import { spawnSync } from "node:child_process";
|
|
11
|
+
function gh(args) {
|
|
12
|
+
const result = spawnSync("gh", args, {
|
|
13
|
+
encoding: "utf-8",
|
|
14
|
+
timeout: 15_000,
|
|
15
|
+
env: { ...process.env, GITHUB_TOKEN: undefined },
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
ok: !result.error && result.status === 0,
|
|
19
|
+
stdout: result.stdout ?? "",
|
|
20
|
+
stderr: result.stderr ?? "",
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function getStatus() {
|
|
24
|
+
const r = gh(["auth", "status", "--json", "loggedInAccounts"]);
|
|
25
|
+
if (!r.ok)
|
|
26
|
+
return { connected: false };
|
|
27
|
+
try {
|
|
28
|
+
const data = JSON.parse(r.stdout);
|
|
29
|
+
const user = data.loggedInAccounts?.[0]?.user;
|
|
30
|
+
return { connected: true, user };
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// gh auth status without --json on older versions
|
|
34
|
+
const match = /Logged in to .+ account (\S+)/.exec(r.stdout + r.stderr);
|
|
35
|
+
return { connected: true, user: match?.[1] };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function listIssues(opts = {}) {
|
|
39
|
+
const args = ["issue", "list", "--json", "number,title,url,labels,updatedAt"];
|
|
40
|
+
if (opts.repo) {
|
|
41
|
+
args.push("--repo", opts.repo);
|
|
42
|
+
}
|
|
43
|
+
if (opts.assignee)
|
|
44
|
+
args.push("--assignee", opts.assignee);
|
|
45
|
+
if (opts.mention)
|
|
46
|
+
args.push("--mention", opts.mention);
|
|
47
|
+
args.push("--limit", String(Math.min(opts.limit ?? 20, 50)));
|
|
48
|
+
const r = gh(args);
|
|
49
|
+
if (!r.ok)
|
|
50
|
+
return [];
|
|
51
|
+
try {
|
|
52
|
+
const raw = JSON.parse(r.stdout);
|
|
53
|
+
const repo = opts.repo ?? inferRepo();
|
|
54
|
+
return raw.map((i) => ({
|
|
55
|
+
number: i.number,
|
|
56
|
+
title: i.title,
|
|
57
|
+
repo,
|
|
58
|
+
url: i.url,
|
|
59
|
+
labels: i.labels.map((l) => l.name),
|
|
60
|
+
updatedAt: i.updatedAt,
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function listPRs(opts = {}) {
|
|
68
|
+
const args = [
|
|
69
|
+
"pr",
|
|
70
|
+
"list",
|
|
71
|
+
"--json",
|
|
72
|
+
"number,title,url,isDraft,reviewDecision,updatedAt",
|
|
73
|
+
];
|
|
74
|
+
if (opts.repo) {
|
|
75
|
+
args.push("--repo", opts.repo);
|
|
76
|
+
}
|
|
77
|
+
if (opts.author)
|
|
78
|
+
args.push("--author", opts.author);
|
|
79
|
+
if (opts.reviewRequested)
|
|
80
|
+
args.push("--review-requested", opts.reviewRequested);
|
|
81
|
+
args.push("--limit", String(Math.min(opts.limit ?? 20, 50)));
|
|
82
|
+
const r = gh(args);
|
|
83
|
+
if (!r.ok)
|
|
84
|
+
return [];
|
|
85
|
+
try {
|
|
86
|
+
const raw = JSON.parse(r.stdout);
|
|
87
|
+
const repo = opts.repo ?? inferRepo();
|
|
88
|
+
return raw.map((p) => ({
|
|
89
|
+
number: p.number,
|
|
90
|
+
title: p.title,
|
|
91
|
+
repo,
|
|
92
|
+
url: p.url,
|
|
93
|
+
isDraft: p.isDraft,
|
|
94
|
+
reviewDecision: p.reviewDecision ?? "",
|
|
95
|
+
updatedAt: p.updatedAt,
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function inferRepo() {
|
|
103
|
+
const r = gh(["repo", "view", "--json", "nameWithOwner"]);
|
|
104
|
+
if (!r.ok)
|
|
105
|
+
return "";
|
|
106
|
+
try {
|
|
107
|
+
return JSON.parse(r.stdout).nameWithOwner;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return "";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/connectors/github.ts"],"names":[],"mappings":"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"}
|