@loompad/cli 0.1.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/ARCHITECTURE.md +211 -0
- package/CHANGELOG.md +470 -0
- package/LICENSE +21 -0
- package/README.md +630 -0
- package/dist/adapters/base.d.ts +71 -0
- package/dist/adapters/base.js +187 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/bridges/antigravity.d.ts +53 -0
- package/dist/adapters/bridges/antigravity.js +106 -0
- package/dist/adapters/bridges/antigravity.js.map +1 -0
- package/dist/adapters/bridges/cdp.d.ts +82 -0
- package/dist/adapters/bridges/cdp.js +222 -0
- package/dist/adapters/bridges/cdp.js.map +1 -0
- package/dist/adapters/bridges/gui-chat.d.ts +113 -0
- package/dist/adapters/bridges/gui-chat.js +498 -0
- package/dist/adapters/bridges/gui-chat.js.map +1 -0
- package/dist/adapters/bridges/kiro.d.ts +19 -0
- package/dist/adapters/bridges/kiro.js +22 -0
- package/dist/adapters/bridges/kiro.js.map +1 -0
- package/dist/adapters/bridges/profiles.d.ts +82 -0
- package/dist/adapters/bridges/profiles.js +125 -0
- package/dist/adapters/bridges/profiles.js.map +1 -0
- package/dist/adapters/claude-code.d.ts +26 -0
- package/dist/adapters/claude-code.js +209 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/codex.d.ts +51 -0
- package/dist/adapters/codex.js +291 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/echo.d.ts +20 -0
- package/dist/adapters/echo.js +79 -0
- package/dist/adapters/echo.js.map +1 -0
- package/dist/adapters/grok.d.ts +61 -0
- package/dist/adapters/grok.js +217 -0
- package/dist/adapters/grok.js.map +1 -0
- package/dist/adapters/index.d.ts +9 -0
- package/dist/adapters/index.js +33 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/opencode.d.ts +64 -0
- package/dist/adapters/opencode.js +426 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/cli/common.d.ts +11 -0
- package/dist/cli/common.js +40 -0
- package/dist/cli/common.js.map +1 -0
- package/dist/cli/doctor.d.ts +12 -0
- package/dist/cli/doctor.js +181 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.js +641 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/tui-model.d.ts +73 -0
- package/dist/cli/tui-model.js +312 -0
- package/dist/cli/tui-model.js.map +1 -0
- package/dist/cli/tui.d.ts +15 -0
- package/dist/cli/tui.js +451 -0
- package/dist/cli/tui.js.map +1 -0
- package/dist/cli/ui.d.ts +10 -0
- package/dist/cli/ui.js +135 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/core/ades.d.ts +79 -0
- package/dist/core/ades.js +130 -0
- package/dist/core/ades.js.map +1 -0
- package/dist/core/baton.d.ts +37 -0
- package/dist/core/baton.js +92 -0
- package/dist/core/baton.js.map +1 -0
- package/dist/core/brain-extract.d.ts +111 -0
- package/dist/core/brain-extract.js +248 -0
- package/dist/core/brain-extract.js.map +1 -0
- package/dist/core/brain-index.d.ts +128 -0
- package/dist/core/brain-index.js +338 -0
- package/dist/core/brain-index.js.map +1 -0
- package/dist/core/brain.d.ts +214 -0
- package/dist/core/brain.js +425 -0
- package/dist/core/brain.js.map +1 -0
- package/dist/core/claude-cli.d.ts +12 -0
- package/dist/core/claude-cli.js +47 -0
- package/dist/core/claude-cli.js.map +1 -0
- package/dist/core/distill.d.ts +19 -0
- package/dist/core/distill.js +88 -0
- package/dist/core/distill.js.map +1 -0
- package/dist/core/eventlog.d.ts +43 -0
- package/dist/core/eventlog.js +211 -0
- package/dist/core/eventlog.js.map +1 -0
- package/dist/core/git.d.ts +203 -0
- package/dist/core/git.js +460 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/logbook.d.ts +59 -0
- package/dist/core/logbook.js +118 -0
- package/dist/core/logbook.js.map +1 -0
- package/dist/core/memory.d.ts +34 -0
- package/dist/core/memory.js +124 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/notify.d.ts +11 -0
- package/dist/core/notify.js +30 -0
- package/dist/core/notify.js.map +1 -0
- package/dist/core/projection.d.ts +20 -0
- package/dist/core/projection.js +96 -0
- package/dist/core/projection.js.map +1 -0
- package/dist/core/registry.d.ts +76 -0
- package/dist/core/registry.js +147 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/router.d.ts +42 -0
- package/dist/core/router.js +99 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/routes.d.ts +93 -0
- package/dist/core/routes.js +399 -0
- package/dist/core/routes.js.map +1 -0
- package/dist/core/search.d.ts +63 -0
- package/dist/core/search.js +0 -0
- package/dist/core/search.js.map +1 -0
- package/dist/core/setup.d.ts +70 -0
- package/dist/core/setup.js +250 -0
- package/dist/core/setup.js.map +1 -0
- package/dist/core/suggestions.d.ts +15 -0
- package/dist/core/suggestions.js +38 -0
- package/dist/core/suggestions.js.map +1 -0
- package/dist/core/worktree.d.ts +32 -0
- package/dist/core/worktree.js +83 -0
- package/dist/core/worktree.js.map +1 -0
- package/dist/daemon/app-page.d.ts +32 -0
- package/dist/daemon/app-page.js +6363 -0
- package/dist/daemon/app-page.js.map +1 -0
- package/dist/daemon/auth.d.ts +51 -0
- package/dist/daemon/auth.js +135 -0
- package/dist/daemon/auth.js.map +1 -0
- package/dist/daemon/board.d.ts +117 -0
- package/dist/daemon/board.js +202 -0
- package/dist/daemon/board.js.map +1 -0
- package/dist/daemon/brand-icons.d.ts +29 -0
- package/dist/daemon/brand-icons.js +44 -0
- package/dist/daemon/brand-icons.js.map +1 -0
- package/dist/daemon/client.d.ts +127 -0
- package/dist/daemon/client.js +237 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/geist-font.d.ts +10 -0
- package/dist/daemon/geist-font.js +783 -0
- package/dist/daemon/geist-font.js.map +1 -0
- package/dist/daemon/guards.d.ts +18 -0
- package/dist/daemon/guards.js +40 -0
- package/dist/daemon/guards.js.map +1 -0
- package/dist/daemon/linear.d.ts +59 -0
- package/dist/daemon/linear.js +117 -0
- package/dist/daemon/linear.js.map +1 -0
- package/dist/daemon/push.d.ts +22 -0
- package/dist/daemon/push.js +58 -0
- package/dist/daemon/push.js.map +1 -0
- package/dist/daemon/runtime.d.ts +299 -0
- package/dist/daemon/runtime.js +1016 -0
- package/dist/daemon/runtime.js.map +1 -0
- package/dist/daemon/server.d.ts +125 -0
- package/dist/daemon/server.js +1728 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/tasks.d.ts +153 -0
- package/dist/daemon/tasks.js +264 -0
- package/dist/daemon/tasks.js.map +1 -0
- package/dist/daemon/terminals.d.ts +82 -0
- package/dist/daemon/terminals.js +372 -0
- package/dist/daemon/terminals.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/sdk.d.ts +17 -0
- package/dist/sdk.js +17 -0
- package/dist/sdk.js.map +1 -0
- package/dist/types.d.ts +236 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/docs/SETUP.md +265 -0
- package/docs/adapters.md +132 -0
- package/docs/design-system.md +245 -0
- package/docs/img/board-linear.png +0 -0
- package/docs/img/board-projects.png +0 -0
- package/docs/img/brain.png +0 -0
- package/docs/img/settings.png +0 -0
- package/docs/img/workspace.png +0 -0
- package/docs/integration-notes.md +76 -0
- package/docs/proposals/brain.md +262 -0
- package/package.json +84 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append-only per-project event log — Loom's source of truth.
|
|
3
|
+
*
|
|
4
|
+
* Primary store: node:sqlite (built into Node >= 22.5, zero native deps).
|
|
5
|
+
* Fallback store: JSONL (if node:sqlite is unavailable, or LOOM_STORE=jsonl).
|
|
6
|
+
*/
|
|
7
|
+
import type { EventKind, LoomEvent, NewEvent } from "../types.js";
|
|
8
|
+
export interface ListOpts {
|
|
9
|
+
since?: number;
|
|
10
|
+
limit?: number;
|
|
11
|
+
kinds?: EventKind[];
|
|
12
|
+
/**
|
|
13
|
+
* Only this conversation. Asking for the main chat also returns events
|
|
14
|
+
* written before chats existed — they have no id and belong to it.
|
|
15
|
+
* Omit to read the whole project, which is what the brain wants.
|
|
16
|
+
*/
|
|
17
|
+
chat?: string;
|
|
18
|
+
}
|
|
19
|
+
/** The store behind a project's log. Exported so search can take a narrow
|
|
20
|
+
* slice of it (list) rather than the whole EventLog — a searcher has no
|
|
21
|
+
* business being able to append. */
|
|
22
|
+
export interface EventStore {
|
|
23
|
+
append(e: Required<Omit<NewEvent, "agentId" | "chat">> & {
|
|
24
|
+
agentId?: string;
|
|
25
|
+
chat?: string;
|
|
26
|
+
}): LoomEvent;
|
|
27
|
+
list(opts?: ListOpts): LoomEvent[];
|
|
28
|
+
lastId(): number;
|
|
29
|
+
close(): void;
|
|
30
|
+
}
|
|
31
|
+
export declare class EventLog {
|
|
32
|
+
private store;
|
|
33
|
+
private emitter;
|
|
34
|
+
private constructor();
|
|
35
|
+
/** Open (or create) the log inside a project's .loom directory. */
|
|
36
|
+
static open(loomDir: string): Promise<EventLog>;
|
|
37
|
+
append(e: NewEvent): LoomEvent;
|
|
38
|
+
list(opts?: ListOpts): LoomEvent[];
|
|
39
|
+
lastId(): number;
|
|
40
|
+
/** Live subscription to appended events; returns unsubscribe. */
|
|
41
|
+
onEvent(cb: (e: LoomEvent) => void): () => void;
|
|
42
|
+
close(): void;
|
|
43
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append-only per-project event log — Loom's source of truth.
|
|
3
|
+
*
|
|
4
|
+
* Primary store: node:sqlite (built into Node >= 22.5, zero native deps).
|
|
5
|
+
* Fallback store: JSONL (if node:sqlite is unavailable, or LOOM_STORE=jsonl).
|
|
6
|
+
*/
|
|
7
|
+
import { EventEmitter } from "node:events";
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { MAIN_CHAT } from "../types.js";
|
|
11
|
+
class SqliteStore {
|
|
12
|
+
db;
|
|
13
|
+
constructor(sqlite, file) {
|
|
14
|
+
this.db = new sqlite.DatabaseSync(file);
|
|
15
|
+
this.db.exec(`
|
|
16
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
17
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
18
|
+
ts INTEGER NOT NULL,
|
|
19
|
+
kind TEXT NOT NULL,
|
|
20
|
+
agent_id TEXT,
|
|
21
|
+
chat TEXT,
|
|
22
|
+
payload TEXT NOT NULL
|
|
23
|
+
);
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_events_kind ON events(kind, id);
|
|
25
|
+
`);
|
|
26
|
+
// Migrate BEFORE indexing chat. A log written before chats existed already
|
|
27
|
+
// has an `events` table, so CREATE TABLE IF NOT EXISTS is a no-op and the
|
|
28
|
+
// column is still missing — indexing it here would throw "no such column"
|
|
29
|
+
// and take the whole log down with it. Add the column, then index.
|
|
30
|
+
// The log is append-only and those events are history: a NULL chat reads
|
|
31
|
+
// as the main conversation rather than being rewritten.
|
|
32
|
+
const cols = this.db.prepare("PRAGMA table_info(events)").all();
|
|
33
|
+
if (!cols.some((c) => c.name === "chat")) {
|
|
34
|
+
this.db.exec("ALTER TABLE events ADD COLUMN chat TEXT");
|
|
35
|
+
}
|
|
36
|
+
this.db.exec("CREATE INDEX IF NOT EXISTS idx_events_chat ON events(chat, id)");
|
|
37
|
+
}
|
|
38
|
+
append(e) {
|
|
39
|
+
const stmt = this.db.prepare("INSERT INTO events (ts, kind, agent_id, chat, payload) VALUES (?, ?, ?, ?, ?)");
|
|
40
|
+
const res = stmt.run(e.ts, e.kind, e.agentId ?? null, e.chat ?? null, JSON.stringify(e.payload));
|
|
41
|
+
return {
|
|
42
|
+
id: Number(res.lastInsertRowid),
|
|
43
|
+
ts: e.ts,
|
|
44
|
+
kind: e.kind,
|
|
45
|
+
...(e.agentId ? { agentId: e.agentId } : {}),
|
|
46
|
+
...(e.chat ? { chat: e.chat } : {}),
|
|
47
|
+
payload: e.payload,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
list(opts = {}) {
|
|
51
|
+
const clauses = [];
|
|
52
|
+
const params = [];
|
|
53
|
+
if (opts.since !== undefined) {
|
|
54
|
+
clauses.push("id > ?");
|
|
55
|
+
params.push(opts.since);
|
|
56
|
+
}
|
|
57
|
+
if (opts.kinds?.length) {
|
|
58
|
+
clauses.push(`kind IN (${opts.kinds.map(() => "?").join(",")})`);
|
|
59
|
+
params.push(...opts.kinds);
|
|
60
|
+
}
|
|
61
|
+
if (opts.chat !== undefined) {
|
|
62
|
+
if (opts.chat === MAIN_CHAT) {
|
|
63
|
+
// pre-chat history has no id and belongs to the main conversation
|
|
64
|
+
clauses.push("(chat = ? OR chat IS NULL)");
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
clauses.push("chat = ?");
|
|
68
|
+
}
|
|
69
|
+
params.push(opts.chat);
|
|
70
|
+
}
|
|
71
|
+
const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
72
|
+
// When limiting, we want the *most recent* N in ascending order.
|
|
73
|
+
const sql = opts.limit
|
|
74
|
+
? `SELECT * FROM (SELECT * FROM events ${where} ORDER BY id DESC LIMIT ?) ORDER BY id ASC`
|
|
75
|
+
: `SELECT * FROM events ${where} ORDER BY id ASC`;
|
|
76
|
+
if (opts.limit)
|
|
77
|
+
params.push(opts.limit);
|
|
78
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
79
|
+
return rows.map((r) => ({
|
|
80
|
+
id: Number(r.id),
|
|
81
|
+
ts: r.ts,
|
|
82
|
+
kind: r.kind,
|
|
83
|
+
...(r.agent_id ? { agentId: r.agent_id } : {}),
|
|
84
|
+
...(r.chat ? { chat: r.chat } : {}),
|
|
85
|
+
payload: JSON.parse(r.payload),
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
lastId() {
|
|
89
|
+
const row = this.db.prepare("SELECT MAX(id) AS m FROM events").get();
|
|
90
|
+
return row?.m ? Number(row.m) : 0;
|
|
91
|
+
}
|
|
92
|
+
close() {
|
|
93
|
+
this.db.close();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// JSONL fallback store
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
class JsonlStore {
|
|
100
|
+
file;
|
|
101
|
+
nextId;
|
|
102
|
+
cache;
|
|
103
|
+
constructor(file) {
|
|
104
|
+
this.file = file;
|
|
105
|
+
this.cache = [];
|
|
106
|
+
if (fs.existsSync(file)) {
|
|
107
|
+
for (const line of fs.readFileSync(file, "utf8").split("\n")) {
|
|
108
|
+
if (!line.trim())
|
|
109
|
+
continue;
|
|
110
|
+
try {
|
|
111
|
+
this.cache.push(JSON.parse(line));
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Skip torn trailing writes; the log stays usable.
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
this.nextId = (this.cache[this.cache.length - 1]?.id ?? 0) + 1;
|
|
119
|
+
}
|
|
120
|
+
append(e) {
|
|
121
|
+
const ev = {
|
|
122
|
+
id: this.nextId++,
|
|
123
|
+
ts: e.ts,
|
|
124
|
+
kind: e.kind,
|
|
125
|
+
...(e.agentId ? { agentId: e.agentId } : {}),
|
|
126
|
+
...(e.chat ? { chat: e.chat } : {}),
|
|
127
|
+
payload: e.payload,
|
|
128
|
+
};
|
|
129
|
+
fs.appendFileSync(this.file, JSON.stringify(ev) + "\n");
|
|
130
|
+
this.cache.push(ev);
|
|
131
|
+
return ev;
|
|
132
|
+
}
|
|
133
|
+
list(opts = {}) {
|
|
134
|
+
let out = this.cache;
|
|
135
|
+
if (opts.since !== undefined)
|
|
136
|
+
out = out.filter((e) => e.id > opts.since);
|
|
137
|
+
if (opts.kinds?.length)
|
|
138
|
+
out = out.filter((e) => opts.kinds.includes(e.kind));
|
|
139
|
+
// must match SqliteStore exactly: an event with no chat is main's
|
|
140
|
+
if (opts.chat !== undefined) {
|
|
141
|
+
out = out.filter((e) => opts.chat === MAIN_CHAT ? (e.chat ?? MAIN_CHAT) === MAIN_CHAT : e.chat === opts.chat);
|
|
142
|
+
}
|
|
143
|
+
if (opts.limit && out.length > opts.limit)
|
|
144
|
+
out = out.slice(-opts.limit);
|
|
145
|
+
return [...out];
|
|
146
|
+
}
|
|
147
|
+
lastId() {
|
|
148
|
+
return this.cache[this.cache.length - 1]?.id ?? 0;
|
|
149
|
+
}
|
|
150
|
+
close() { }
|
|
151
|
+
}
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// EventLog facade
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
export class EventLog {
|
|
156
|
+
store;
|
|
157
|
+
emitter = new EventEmitter();
|
|
158
|
+
constructor(store) {
|
|
159
|
+
this.store = store;
|
|
160
|
+
this.emitter.setMaxListeners(100);
|
|
161
|
+
}
|
|
162
|
+
/** Open (or create) the log inside a project's .loom directory. */
|
|
163
|
+
static async open(loomDir) {
|
|
164
|
+
fs.mkdirSync(loomDir, { recursive: true });
|
|
165
|
+
if (process.env.LOOM_STORE !== "jsonl") {
|
|
166
|
+
let sqlite;
|
|
167
|
+
try {
|
|
168
|
+
sqlite = await import("node:sqlite");
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// No node:sqlite in this runtime — the JSONL store is the whole point
|
|
172
|
+
// of the fallback. This is the ONLY thing it catches.
|
|
173
|
+
return new EventLog(new JsonlStore(path.join(loomDir, "log.jsonl")));
|
|
174
|
+
}
|
|
175
|
+
// Deliberately outside the catch. If node:sqlite exists but the log won't
|
|
176
|
+
// open — corrupt file, failed migration, bad permissions — falling back
|
|
177
|
+
// would silently start an EMPTY jsonl log beside a database full of your
|
|
178
|
+
// history, and write new events there. Losing the thread is worse than
|
|
179
|
+
// failing loudly, so this throws.
|
|
180
|
+
return new EventLog(new SqliteStore(sqlite, path.join(loomDir, "log.db")));
|
|
181
|
+
}
|
|
182
|
+
return new EventLog(new JsonlStore(path.join(loomDir, "log.jsonl")));
|
|
183
|
+
}
|
|
184
|
+
append(e) {
|
|
185
|
+
const ev = this.store.append({
|
|
186
|
+
ts: e.ts ?? Date.now(),
|
|
187
|
+
kind: e.kind,
|
|
188
|
+
payload: e.payload,
|
|
189
|
+
...(e.agentId ? { agentId: e.agentId } : {}),
|
|
190
|
+
...(e.chat ? { chat: e.chat } : {}),
|
|
191
|
+
});
|
|
192
|
+
this.emitter.emit("event", ev);
|
|
193
|
+
return ev;
|
|
194
|
+
}
|
|
195
|
+
list(opts) {
|
|
196
|
+
return this.store.list(opts);
|
|
197
|
+
}
|
|
198
|
+
lastId() {
|
|
199
|
+
return this.store.lastId();
|
|
200
|
+
}
|
|
201
|
+
/** Live subscription to appended events; returns unsubscribe. */
|
|
202
|
+
onEvent(cb) {
|
|
203
|
+
this.emitter.on("event", cb);
|
|
204
|
+
return () => this.emitter.off("event", cb);
|
|
205
|
+
}
|
|
206
|
+
close() {
|
|
207
|
+
this.emitter.removeAllListeners();
|
|
208
|
+
this.store.close();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=eventlog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eventlog.js","sourceRoot":"","sources":["../../src/core/eventlog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source control that does something.
|
|
3
|
+
*
|
|
4
|
+
* worktree.ts reads: what changed, what the patch is. This writes: stage,
|
|
5
|
+
* unstage, discard, commit. The split is deliberate — reading is safe and runs
|
|
6
|
+
* on a timer, writing touches your repository and only ever happens because you
|
|
7
|
+
* clicked something.
|
|
8
|
+
*
|
|
9
|
+
* ## Why every path is checked instead of trusted
|
|
10
|
+
*
|
|
11
|
+
* These take file paths from an HTTP body, and `git checkout -- <path>` deletes
|
|
12
|
+
* your work. A path that escapes the project ("../../etc/…") would let a paired
|
|
13
|
+
* device discard files outside the repo entirely. Every path is resolved and
|
|
14
|
+
* confirmed to sit inside the project before git sees it, and `--` separates
|
|
15
|
+
* paths from flags so a file named `-f` can't become one.
|
|
16
|
+
*
|
|
17
|
+
* ## Why errors come back instead of being swallowed
|
|
18
|
+
*
|
|
19
|
+
* worktree.ts's git() resolves "" on failure, which is right for a read — a
|
|
20
|
+
* missing branch name isn't worth an exception. It is wrong for a write: a
|
|
21
|
+
* commit that silently does nothing is the worst outcome available. These throw
|
|
22
|
+
* with git's own stderr, which is nearly always the actual answer ("nothing to
|
|
23
|
+
* commit", "please tell me who you are").
|
|
24
|
+
*/
|
|
25
|
+
export declare class GitError extends Error {
|
|
26
|
+
readonly stderr: string;
|
|
27
|
+
constructor(message: string, stderr: string);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Keep a path inside the project.
|
|
31
|
+
*
|
|
32
|
+
* `git checkout -- <path>` is destructive and these paths arrive over HTTP from
|
|
33
|
+
* a device that could be anywhere on your tailnet. Resolve, then prove it's
|
|
34
|
+
* within the root — a prefix check on the un-normalised string would wave
|
|
35
|
+
* "../.." straight through.
|
|
36
|
+
*/
|
|
37
|
+
export declare function safeRelPath(dir: string, rel: string): string;
|
|
38
|
+
export declare function isRepo(dir: string): Promise<boolean>;
|
|
39
|
+
export declare function stage(dir: string, paths: string[]): Promise<{
|
|
40
|
+
staged: string[];
|
|
41
|
+
}>;
|
|
42
|
+
export declare function unstage(dir: string, paths: string[]): Promise<{
|
|
43
|
+
unstaged: string[];
|
|
44
|
+
}>;
|
|
45
|
+
/**
|
|
46
|
+
* Throw work away.
|
|
47
|
+
*
|
|
48
|
+
* The one operation here that can lose something you can't get back, so it is
|
|
49
|
+
* the one that is loudest in the log. Tracked files are restored from the
|
|
50
|
+
* index; untracked ones have nothing to restore to and must be deleted, which
|
|
51
|
+
* `git checkout` won't do — hence `clean -f` for those, and hence the split.
|
|
52
|
+
*/
|
|
53
|
+
export declare function discard(dir: string, paths: string[], untracked?: string[]): Promise<{
|
|
54
|
+
discarded: string[];
|
|
55
|
+
}>;
|
|
56
|
+
export interface CommitResult {
|
|
57
|
+
sha: string;
|
|
58
|
+
subject: string;
|
|
59
|
+
files: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Commit what's staged.
|
|
63
|
+
*
|
|
64
|
+
* Nothing is staged for you. "Commit all" is a convenience that has ended more
|
|
65
|
+
* afternoons than it saved — an agent's stray file swept into your commit
|
|
66
|
+
* because the button was easier than looking. If you want it in, stage it.
|
|
67
|
+
*/
|
|
68
|
+
export declare function commit(dir: string, message: string): Promise<CommitResult>;
|
|
69
|
+
export interface GitStatus {
|
|
70
|
+
branch: string;
|
|
71
|
+
/** Commits ahead / behind the upstream, when there is one. */
|
|
72
|
+
ahead: number;
|
|
73
|
+
behind: number;
|
|
74
|
+
upstream: string | null;
|
|
75
|
+
staged: {
|
|
76
|
+
status: string;
|
|
77
|
+
path: string;
|
|
78
|
+
}[];
|
|
79
|
+
unstaged: {
|
|
80
|
+
status: string;
|
|
81
|
+
path: string;
|
|
82
|
+
}[];
|
|
83
|
+
untracked: string[];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The status the UI needs: staged and unstaged as separate lists.
|
|
87
|
+
*
|
|
88
|
+
* Porcelain's XY is two columns for a reason — X is the index, Y is the working
|
|
89
|
+
* tree — and a file can be in both at once (staged, then edited again). Flatten
|
|
90
|
+
* that into one list and you get a checkbox that lies about what a commit will
|
|
91
|
+
* contain.
|
|
92
|
+
*/
|
|
93
|
+
export declare function status(dir: string): Promise<GitStatus>;
|
|
94
|
+
/**
|
|
95
|
+
* Start version control here.
|
|
96
|
+
*
|
|
97
|
+
* Refuses if the directory is already inside a repo, so an accidental click
|
|
98
|
+
* can't nest one repo inside another. Renames the initial branch to `main` when
|
|
99
|
+
* git left it on `master` — safe because a just-init'd repo has no commits, and
|
|
100
|
+
* it matches what remotes expect.
|
|
101
|
+
*/
|
|
102
|
+
export declare function init(dir: string): Promise<{
|
|
103
|
+
branch: string;
|
|
104
|
+
}>;
|
|
105
|
+
export interface Commit {
|
|
106
|
+
sha: string;
|
|
107
|
+
short: string;
|
|
108
|
+
subject: string;
|
|
109
|
+
author: string;
|
|
110
|
+
/** "2 hours ago" — git's own relative time. */
|
|
111
|
+
relative: string;
|
|
112
|
+
ts: number;
|
|
113
|
+
}
|
|
114
|
+
/** Recent commits, newest first. Empty in a repo whose first commit hasn't landed. */
|
|
115
|
+
export declare function log(dir: string, limit?: number): Promise<Commit[]>;
|
|
116
|
+
/**
|
|
117
|
+
* The unified diff for one file, HEAD → working tree (both staged and unstaged
|
|
118
|
+
* changes). Before the first commit there's no HEAD, so it diffs against the
|
|
119
|
+
* index instead. Empty string when nothing differs.
|
|
120
|
+
*/
|
|
121
|
+
export declare function fileDiff(dir: string, rel: string): Promise<string>;
|
|
122
|
+
/**
|
|
123
|
+
* The diff a commit would capture — staged changes, or the whole working tree
|
|
124
|
+
* when nothing is staged yet. Used to write a commit message from. Bounded so a
|
|
125
|
+
* giant refactor doesn't blow the LLM's context (the summary only needs the
|
|
126
|
+
* shape of the change, not every line).
|
|
127
|
+
*/
|
|
128
|
+
export declare function stagedDiff(dir: string, maxChars?: number): Promise<string>;
|
|
129
|
+
export interface Branches {
|
|
130
|
+
current: string;
|
|
131
|
+
all: string[];
|
|
132
|
+
}
|
|
133
|
+
/** Local branches and which one is checked out — for the checkout picker. */
|
|
134
|
+
export declare function branches(dir: string): Promise<Branches>;
|
|
135
|
+
/**
|
|
136
|
+
* Switch to a branch or commit.
|
|
137
|
+
*
|
|
138
|
+
* git refuses on its own when the switch would overwrite uncommitted changes,
|
|
139
|
+
* and that refusal (with its list of the files at risk) is exactly the message
|
|
140
|
+
* to surface — so we don't second-guess it, we just pass its stderr back. The
|
|
141
|
+
* ref is character-validated because it reaches a git command, though `--`
|
|
142
|
+
* already stops it being read as a flag.
|
|
143
|
+
*/
|
|
144
|
+
export declare function checkout(dir: string, ref: string): Promise<{
|
|
145
|
+
ref: string;
|
|
146
|
+
branch: string;
|
|
147
|
+
}>;
|
|
148
|
+
/**
|
|
149
|
+
* How far behind (and ahead of) the upstream this checkout is — for "check for
|
|
150
|
+
* updates". Fetches first (bounded), so it reflects the remote, not a stale
|
|
151
|
+
* local ref. null when the dir isn't a git checkout; behind 0 with no upstream
|
|
152
|
+
* means "nothing to compare against", not "up to date".
|
|
153
|
+
*/
|
|
154
|
+
export declare function remoteBehind(dir: string): Promise<{
|
|
155
|
+
behind: number;
|
|
156
|
+
ahead: number;
|
|
157
|
+
branch: string;
|
|
158
|
+
hasUpstream: boolean;
|
|
159
|
+
} | null>;
|
|
160
|
+
/**
|
|
161
|
+
* Push to the upstream, setting it on the first push.
|
|
162
|
+
*
|
|
163
|
+
* A branch with no upstream needs `-u origin <branch>` once; after that a bare
|
|
164
|
+
* `git push` is enough. Either way the network is bounded (gitNet) and auth is
|
|
165
|
+
* the user's own credential helper. A repo with no remote at all fails with
|
|
166
|
+
* git's "No configured push destination", which is the honest answer.
|
|
167
|
+
*/
|
|
168
|
+
export declare function push(dir: string): Promise<{
|
|
169
|
+
branch: string;
|
|
170
|
+
detail: string;
|
|
171
|
+
}>;
|
|
172
|
+
export interface Worktree {
|
|
173
|
+
path: string;
|
|
174
|
+
/** null when the worktree is detached (e.g. mid-review of a fork PR). */
|
|
175
|
+
branch: string | null;
|
|
176
|
+
head: string;
|
|
177
|
+
/** The repo's own main working tree — you can't remove this one. */
|
|
178
|
+
main?: boolean;
|
|
179
|
+
}
|
|
180
|
+
/** Where a new worktree for this repo goes: `<repo>--<slug>`, a sibling. */
|
|
181
|
+
export declare function worktreePath(dir: string, slug: string): string;
|
|
182
|
+
export declare function listWorktrees(dir: string): Promise<Worktree[]>;
|
|
183
|
+
/**
|
|
184
|
+
* Open a worktree. Three shapes:
|
|
185
|
+
* - `newBranch`: cut a fresh branch off `base` (default HEAD) — used for an
|
|
186
|
+
* issue or a card you want to start.
|
|
187
|
+
* - `branch`: check out an existing (or DWIM-remote) branch.
|
|
188
|
+
* - `detached`: park at HEAD, for the caller to `gh pr checkout` into (handles
|
|
189
|
+
* fork PRs, which have no local branch).
|
|
190
|
+
* Returns the created path; `git worktree add` refuses to clobber, so an
|
|
191
|
+
* existing path surfaces git's own error rather than overwriting work.
|
|
192
|
+
*/
|
|
193
|
+
export declare function addWorktree(dir: string, opts: {
|
|
194
|
+
slug: string;
|
|
195
|
+
branch?: string;
|
|
196
|
+
newBranch?: string;
|
|
197
|
+
base?: string;
|
|
198
|
+
detached?: boolean;
|
|
199
|
+
}): Promise<{
|
|
200
|
+
path: string;
|
|
201
|
+
branch: string | null;
|
|
202
|
+
}>;
|
|
203
|
+
export declare function removeWorktree(dir: string, wtPath: string, force?: boolean): Promise<void>;
|