@synaplink/orqlaude 0.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.
Files changed (66) hide show
  1. package/.mcp.json.template +8 -0
  2. package/README.md +239 -0
  3. package/dist/__tests__/hallucination.test.d.ts +1 -0
  4. package/dist/__tests__/hallucination.test.js +65 -0
  5. package/dist/__tests__/hallucination.test.js.map +1 -0
  6. package/dist/__tests__/state.test.d.ts +1 -0
  7. package/dist/__tests__/state.test.js +124 -0
  8. package/dist/__tests__/state.test.js.map +1 -0
  9. package/dist/cli.d.ts +2 -0
  10. package/dist/cli.js +322 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/lib/audit.d.ts +38 -0
  13. package/dist/lib/audit.js +108 -0
  14. package/dist/lib/audit.js.map +1 -0
  15. package/dist/lib/budgeting.d.ts +37 -0
  16. package/dist/lib/budgeting.js +67 -0
  17. package/dist/lib/budgeting.js.map +1 -0
  18. package/dist/lib/hallucination.d.ts +46 -0
  19. package/dist/lib/hallucination.js +154 -0
  20. package/dist/lib/hallucination.js.map +1 -0
  21. package/dist/lib/jsonl_tail.d.ts +40 -0
  22. package/dist/lib/jsonl_tail.js +126 -0
  23. package/dist/lib/jsonl_tail.js.map +1 -0
  24. package/dist/lib/pricing.d.ts +24 -0
  25. package/dist/lib/pricing.js +43 -0
  26. package/dist/lib/pricing.js.map +1 -0
  27. package/dist/lib/state.d.ts +118 -0
  28. package/dist/lib/state.js +138 -0
  29. package/dist/lib/state.js.map +1 -0
  30. package/dist/server.d.ts +2 -0
  31. package/dist/server.js +34 -0
  32. package/dist/server.js.map +1 -0
  33. package/dist/telegram/api.d.ts +45 -0
  34. package/dist/telegram/api.js +59 -0
  35. package/dist/telegram/api.js.map +1 -0
  36. package/dist/telegram/bot.d.ts +11 -0
  37. package/dist/telegram/bot.js +73 -0
  38. package/dist/telegram/bot.js.map +1 -0
  39. package/dist/telegram/commands.d.ts +22 -0
  40. package/dist/telegram/commands.js +217 -0
  41. package/dist/telegram/commands.js.map +1 -0
  42. package/dist/telegram/config.d.ts +30 -0
  43. package/dist/telegram/config.js +37 -0
  44. package/dist/telegram/config.js.map +1 -0
  45. package/dist/telegram/notifier.d.ts +14 -0
  46. package/dist/telegram/notifier.js +136 -0
  47. package/dist/telegram/notifier.js.map +1 -0
  48. package/dist/tools/broker.d.ts +15 -0
  49. package/dist/tools/broker.js +245 -0
  50. package/dist/tools/broker.js.map +1 -0
  51. package/dist/tools/dispatch.d.ts +14 -0
  52. package/dist/tools/dispatch.js +231 -0
  53. package/dist/tools/dispatch.js.map +1 -0
  54. package/dist/tools/lifecycle.d.ts +18 -0
  55. package/dist/tools/lifecycle.js +124 -0
  56. package/dist/tools/lifecycle.js.map +1 -0
  57. package/dist/tools/ping.d.ts +2 -0
  58. package/dist/tools/ping.js +26 -0
  59. package/dist/tools/ping.js.map +1 -0
  60. package/dist/tools/planning.d.ts +4 -0
  61. package/dist/tools/planning.js +160 -0
  62. package/dist/tools/planning.js.map +1 -0
  63. package/dist/tools/review.d.ts +18 -0
  64. package/dist/tools/review.js +93 -0
  65. package/dist/tools/review.js.map +1 -0
  66. package/package.json +56 -0
@@ -0,0 +1,136 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ import { StateStore } from "../lib/state.js";
4
+ const EMPTY_CURSOR = {
5
+ lastNoteId: null,
6
+ taskStatus: {},
7
+ planStatus: {},
8
+ alertedHallucinations: [],
9
+ };
10
+ export class Notifier {
11
+ projectDir;
12
+ cfg;
13
+ api;
14
+ cursorPath;
15
+ cursor = null;
16
+ constructor(projectDir, cfg, api) {
17
+ this.projectDir = projectDir;
18
+ this.cfg = cfg;
19
+ this.api = api;
20
+ this.cursorPath = path.join(projectDir, ".orqlaude", "telegram-cursor.json");
21
+ }
22
+ async loadCursor() {
23
+ if (this.cursor)
24
+ return this.cursor;
25
+ try {
26
+ const raw = await fs.readFile(this.cursorPath, "utf8");
27
+ this.cursor = { ...EMPTY_CURSOR, ...JSON.parse(raw) };
28
+ }
29
+ catch (err) {
30
+ if (err.code === "ENOENT")
31
+ this.cursor = { ...EMPTY_CURSOR };
32
+ else
33
+ throw err;
34
+ }
35
+ return this.cursor;
36
+ }
37
+ async saveCursor() {
38
+ if (!this.cursor)
39
+ return;
40
+ await fs.mkdir(path.dirname(this.cursorPath), { recursive: true });
41
+ const tmp = `${this.cursorPath}.${process.pid}.tmp`;
42
+ await fs.writeFile(tmp, JSON.stringify(this.cursor, null, 2));
43
+ await fs.rename(tmp, this.cursorPath);
44
+ }
45
+ /** One pass: detect deltas, push notifications, advance cursor. */
46
+ async tick() {
47
+ if (this.cfg.whitelist.length === 0)
48
+ return;
49
+ const cursor = await this.loadCursor();
50
+ const store = new StateStore(path.join(this.projectDir, ".orqlaude"));
51
+ const plans = await store.read((s) => Object.values(s.plans));
52
+ const messages = [];
53
+ for (const plan of plans) {
54
+ const prevStatus = cursor.planStatus[plan.id];
55
+ // Plan status transitions we care about
56
+ if (prevStatus !== plan.status) {
57
+ if (!prevStatus && plan.status === "draft") {
58
+ messages.push(`📋 *New plan* \`${plan.id.slice(0, 8)}\` — ${plan.tasks.length} task(s)\n${truncate(plan.rootTask, 100)}`);
59
+ }
60
+ else if (plan.status === "approved" && prevStatus !== "approved") {
61
+ messages.push(`✅ *Approved* \`${plan.id.slice(0, 8)}\` — spawning ${plan.tasks.length} agents`);
62
+ }
63
+ else if (plan.status === "collected") {
64
+ const total = plan.tasks.length;
65
+ const done = plan.tasks.filter((t) => t.status === "done").length;
66
+ messages.push(`🎉 *Collected* \`${plan.id.slice(0, 8)}\` — ${done}/${total} tasks done`);
67
+ }
68
+ else if (plan.status === "cancelled_overbudget") {
69
+ messages.push(`💸 *Auto-cancelled* \`${plan.id.slice(0, 8)}\` — fleet exceeded token budget`);
70
+ }
71
+ else if (plan.status === "cancelled") {
72
+ messages.push(`❌ *Cancelled* \`${plan.id.slice(0, 8)}\``);
73
+ }
74
+ cursor.planStatus[plan.id] = plan.status;
75
+ }
76
+ // Per-task status transitions
77
+ for (const task of plan.tasks) {
78
+ const prev = cursor.taskStatus[task.id];
79
+ if (prev !== task.status) {
80
+ if (task.status === "done") {
81
+ const prSuffix = task.prUrl ? `\n${task.prUrl}` : "";
82
+ messages.push(`✓ *${truncate(task.title, 60)}* — done${prSuffix}`);
83
+ }
84
+ else if (task.status === "failed") {
85
+ messages.push(`❌ *${truncate(task.title, 60)}* — failed${task.exitReason ? `\n${task.exitReason}` : ""}`);
86
+ }
87
+ else if (task.status === "cancelled") {
88
+ messages.push(`🛑 *${truncate(task.title, 60)}* — cancelled`);
89
+ }
90
+ cursor.taskStatus[task.id] = task.status;
91
+ }
92
+ }
93
+ // New notes (only after the last-seen note id)
94
+ let foundLast = cursor.lastNoteId === null;
95
+ for (const note of plan.notes) {
96
+ if (!foundLast) {
97
+ if (note.id === cursor.lastNoteId)
98
+ foundLast = true;
99
+ continue;
100
+ }
101
+ const taskTitle = plan.tasks.find((t) => t.id === note.taskId)?.title ?? note.taskId.slice(0, 8);
102
+ const blocking = note.blocking ? " 🟡 blocking" : "";
103
+ messages.push(`📝 *${truncate(taskTitle, 50)}*${blocking}\n${truncate(note.text, 300)}${note.prUrl ? `\n${note.prUrl}` : ""}`);
104
+ cursor.lastNoteId = note.id;
105
+ }
106
+ // If we never had a cursor, seed it to the last note so we don't blast history.
107
+ if (cursor.lastNoteId === null && plan.notes.length > 0) {
108
+ cursor.lastNoteId = plan.notes[plan.notes.length - 1].id;
109
+ }
110
+ }
111
+ if (messages.length === 0) {
112
+ // still save cursor in case statuses changed but no message produced
113
+ await this.saveCursor();
114
+ return;
115
+ }
116
+ // Save cursor BEFORE sending, to avoid resends on partial failures.
117
+ await this.saveCursor();
118
+ // Push.
119
+ for (const entry of this.cfg.whitelist) {
120
+ for (const msg of messages) {
121
+ try {
122
+ await this.api.sendMessage(entry.chatId, msg, { parseMode: "Markdown" });
123
+ }
124
+ catch (err) {
125
+ process.stderr.write(`[orqlaude tg notifier] send to ${entry.chatId} failed: ${err.message}\n`);
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+ function truncate(s, n) {
132
+ if (s.length <= n)
133
+ return s;
134
+ return s.slice(0, n - 1) + "…";
135
+ }
136
+ //# sourceMappingURL=notifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifier.js","sourceRoot":"","sources":["../../src/telegram/notifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StateStore } from "../lib/state.js";
3
+ import type { AuditLog } from "../lib/audit.js";
4
+ /**
5
+ * Broker tools.
6
+ *
7
+ * v0.2.0:
8
+ * • `checkin` accepts an optional `task_id`. If the session is not yet
9
+ * registered AND task_id matches a dispatched-but-unclaimed task, the
10
+ * session self-registers. This removes the manual register_spawn step.
11
+ * • New `claim_files` and `release_files` tools for cross-agent file
12
+ * ownership. Conflicting claims are returned to the caller (and surfaced
13
+ * to the primary Claude through the next status() call).
14
+ */
15
+ export declare function registerBroker(server: McpServer, store: StateStore, audit: AuditLog): void;
@@ -0,0 +1,245 @@
1
+ import { z } from "zod";
2
+ import { randomUUID } from "node:crypto";
3
+ import { planForSession, findPlan, unclaimedTaskById, normalizeClaimPath, } from "../lib/state.js";
4
+ /**
5
+ * Broker tools.
6
+ *
7
+ * v0.2.0:
8
+ * • `checkin` accepts an optional `task_id`. If the session is not yet
9
+ * registered AND task_id matches a dispatched-but-unclaimed task, the
10
+ * session self-registers. This removes the manual register_spawn step.
11
+ * • New `claim_files` and `release_files` tools for cross-agent file
12
+ * ownership. Conflicting claims are returned to the caller (and surfaced
13
+ * to the primary Claude through the next status() call).
14
+ */
15
+ export function registerBroker(server, store, audit) {
16
+ // ---- checkin (child → orqlaude) ------------------------------------------
17
+ server.tool("checkin", "Called BY A SPAWNED AGENT. Two purposes: (1) on your FIRST turn, pass your own session_id AND task_id (from the prompt) to self-register. (2) on subsequent turns, pass only session_id to pull queued messages and check ack status. Returns messages (possibly empty), STOP signal status, and ack state of any blocking notes you posted.", {
18
+ session_id: z.string().describe("Your own session id. Read from $CLAUDE_CODE_SESSION_ID or the prompt."),
19
+ task_id: z.string().optional().describe("Pass this ONCE on your first checkin to self-register against your task. The prompt you received contains it as `task_id: ...`."),
20
+ }, audit.wrap("checkin", async ({ session_id, task_id }) => {
21
+ const result = await store.update((state) => {
22
+ // Already-registered session?
23
+ let found = planForSession(state, session_id);
24
+ let selfRegistered = false;
25
+ // First-turn self-registration path.
26
+ if (!found && task_id) {
27
+ const target = unclaimedTaskById(state, task_id);
28
+ if (target) {
29
+ target.task.spawnedSessionId = session_id;
30
+ target.task.status = "running";
31
+ found = target;
32
+ selfRegistered = true;
33
+ }
34
+ }
35
+ if (!found) {
36
+ return {
37
+ registered: false,
38
+ note: task_id
39
+ ? "task_id provided but no matching unclaimed dispatched task. Either the plan moved on or another spawn claimed it."
40
+ : "This session is not registered. On your first checkin, pass your task_id too (it's in the prompt under 'task_id:').",
41
+ messages: [],
42
+ stop_signal: null,
43
+ blocking_notes_acked: [],
44
+ };
45
+ }
46
+ const { plan, task } = found;
47
+ // Deliver queued messages.
48
+ const pending = plan.messages.filter((m) => m.toSessionId === session_id && !m.delivered);
49
+ let stopSignal = null;
50
+ for (const m of pending) {
51
+ m.delivered = true;
52
+ m.deliveredAt = Date.now();
53
+ if (m.kind === "stop") {
54
+ stopSignal = { reason: m.text, at: m.queuedAt };
55
+ }
56
+ }
57
+ // Surface STOP from task-level flag too.
58
+ if (!stopSignal && task.stopRequested) {
59
+ stopSignal = { reason: task.stopRequested.reason, at: task.stopRequested.requestedAt };
60
+ }
61
+ const myBlocking = plan.notes.filter((n) => n.fromSessionId === session_id && n.blocking);
62
+ return {
63
+ registered: true,
64
+ self_registered: selfRegistered,
65
+ plan_id: plan.id,
66
+ task_id: task.id,
67
+ task_title: task.title,
68
+ messages: pending
69
+ .filter((m) => m.kind !== "stop")
70
+ .map((m) => ({ id: m.id, text: m.text, from_task: m.fromTaskId ?? null, queued_at: m.queuedAt })),
71
+ stop_signal: stopSignal,
72
+ blocking_notes_acked: myBlocking.map((n) => ({ id: n.id, acked: n.acked })),
73
+ guidance: stopSignal
74
+ ? "STOP received — commit what you have and exit."
75
+ : selfRegistered
76
+ ? "Registered with the orchestrator. Now do your task."
77
+ : "Carry on.",
78
+ };
79
+ });
80
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
81
+ }, ({ session_id }) => ({ sessionId: session_id })));
82
+ // ---- post_note (child → orqlaude) ----------------------------------------
83
+ server.tool("post_note", "Called BY A SPAWNED AGENT to share a finding or report a PR URL. Set `blocking: true` only when you must pause until the primary Claude acks. Setting `pr_url` attaches it to your task for `collect`.", {
84
+ session_id: z.string(),
85
+ text: z.string().min(1),
86
+ blocking: z.boolean().default(false),
87
+ pr_url: z.string().url().optional(),
88
+ }, audit.wrap("post_note", async ({ session_id, text, blocking, pr_url }) => {
89
+ const result = await store.update((state) => {
90
+ const found = planForSession(state, session_id);
91
+ if (!found)
92
+ return { posted: false, note: "Session not registered. Run checkin with task_id first." };
93
+ const { plan, task } = found;
94
+ const note = {
95
+ id: randomUUID(),
96
+ fromSessionId: session_id,
97
+ taskId: task.id,
98
+ text,
99
+ blocking,
100
+ postedAt: Date.now(),
101
+ acked: false,
102
+ prUrl: pr_url,
103
+ };
104
+ plan.notes.push(note);
105
+ if (pr_url)
106
+ task.prUrl = pr_url;
107
+ return {
108
+ posted: true,
109
+ note_id: note.id,
110
+ blocking,
111
+ guidance: blocking
112
+ ? "Now call `checkin` periodically until your note appears in blocking_notes_acked with acked=true."
113
+ : "Note queued. Continue.",
114
+ };
115
+ });
116
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
117
+ }, ({ session_id }) => ({ sessionId: session_id })));
118
+ // ---- claim_files (child → orqlaude) --------------------------------------
119
+ server.tool("claim_files", "Called BY A SPAWNED AGENT to register intent to edit specific files. Returns existing conflicting claims by other sessions; the caller decides whether to coordinate (via post_note) or proceed anyway. Paths can be absolute or relative; relative paths are resolved against the orqlaude server's cwd (the project root).", {
120
+ session_id: z.string(),
121
+ paths: z.array(z.string().min(1)).min(1),
122
+ reason: z.string().optional().describe("Optional human-readable reason for the claim, surfaced to other agents."),
123
+ }, audit.wrap("claim_files", async ({ session_id, paths, reason }) => {
124
+ const result = await store.update((state) => {
125
+ const found = planForSession(state, session_id);
126
+ if (!found)
127
+ return { claimed: [], conflicts: [], note: "Session not registered." };
128
+ const { plan, task } = found;
129
+ const cwd = process.cwd();
130
+ const conflicts = [];
131
+ const claimed = [];
132
+ for (const raw of paths) {
133
+ const normalized = normalizeClaimPath(raw, cwd);
134
+ const existing = plan.claims.find((c) => c.path === normalized && c.claimedBy !== session_id);
135
+ if (existing) {
136
+ conflicts.push({
137
+ path: normalized,
138
+ claimedBy: existing.claimedBy,
139
+ taskId: existing.taskId,
140
+ reason: existing.reason,
141
+ });
142
+ continue;
143
+ }
144
+ const already = plan.claims.find((c) => c.path === normalized && c.claimedBy === session_id);
145
+ if (!already) {
146
+ plan.claims.push({
147
+ path: normalized,
148
+ claimedBy: session_id,
149
+ taskId: task.id,
150
+ reason,
151
+ claimedAt: Date.now(),
152
+ });
153
+ }
154
+ claimed.push(normalized);
155
+ }
156
+ return {
157
+ claimed,
158
+ conflicts,
159
+ guidance: conflicts.length > 0
160
+ ? "Conflicts found. Consider post_note(blocking=true) to coordinate, or release_files if you don't actually need these paths."
161
+ : "Claims registered. Other agents will see them.",
162
+ };
163
+ });
164
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
165
+ }, ({ session_id }) => ({ sessionId: session_id })));
166
+ // ---- release_files (child → orqlaude) ------------------------------------
167
+ server.tool("release_files", "Called BY A SPAWNED AGENT to release file claims after finishing edits (or if you decide not to touch them).", {
168
+ session_id: z.string(),
169
+ paths: z.array(z.string().min(1)).min(1),
170
+ }, audit.wrap("release_files", async ({ session_id, paths }) => {
171
+ const result = await store.update((state) => {
172
+ const found = planForSession(state, session_id);
173
+ if (!found)
174
+ return { released: 0, note: "Session not registered." };
175
+ const { plan } = found;
176
+ const cwd = process.cwd();
177
+ const normalized = new Set(paths.map((p) => normalizeClaimPath(p, cwd)));
178
+ const before = plan.claims.length;
179
+ plan.claims = plan.claims.filter((c) => !(c.claimedBy === session_id && normalized.has(c.path)));
180
+ return { released: before - plan.claims.length };
181
+ });
182
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
183
+ }, ({ session_id }) => ({ sessionId: session_id })));
184
+ // ---- poll_notes (primary Claude → orqlaude) ------------------------------
185
+ server.tool("poll_notes", "Called BY PRIMARY CLAUDE to read notes posted by fleet agents. Returns notes since `since_ts` (or all). Pass `mark_acked` to ack blocking notes — that unblocks the posting agent on its next checkin.", {
186
+ plan_id: z.string(),
187
+ since_ts: z.number().optional(),
188
+ mark_acked: z.array(z.string()).optional(),
189
+ }, audit.wrap("poll_notes", async ({ plan_id, since_ts, mark_acked }) => {
190
+ const result = await store.update((state) => {
191
+ const plan = findPlan(state, plan_id);
192
+ if (mark_acked) {
193
+ for (const id of mark_acked) {
194
+ const n = plan.notes.find((x) => x.id === id);
195
+ if (n)
196
+ n.acked = true;
197
+ }
198
+ }
199
+ const cutoff = since_ts ?? 0;
200
+ const notes = plan.notes
201
+ .filter((n) => n.postedAt >= cutoff)
202
+ .map((n) => ({
203
+ id: n.id,
204
+ from_task_id: n.taskId,
205
+ from_session_id: n.fromSessionId,
206
+ text: n.text,
207
+ blocking: n.blocking,
208
+ acked: n.acked,
209
+ posted_at: n.postedAt,
210
+ pr_url: n.prUrl ?? null,
211
+ }));
212
+ return { plan_id, notes };
213
+ });
214
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
215
+ }, ({ plan_id }) => ({ planId: plan_id })));
216
+ // ---- send_message (primary Claude → child) -------------------------------
217
+ server.tool("send_message", "Called BY PRIMARY CLAUDE to queue a directed message for a child agent. Delivered on its next checkin. Set `kind: 'stop'` to signal that the agent should commit-and-exit.", {
218
+ plan_id: z.string(),
219
+ to_session_id: z.string(),
220
+ text: z.string().min(1),
221
+ from_task_id: z.string().optional(),
222
+ kind: z.enum(["directed", "stop"]).default("directed"),
223
+ }, audit.wrap("send_message", async ({ plan_id, to_session_id, text, from_task_id, kind }) => {
224
+ const result = await store.update((state) => {
225
+ const plan = findPlan(state, plan_id);
226
+ plan.messages.push({
227
+ id: randomUUID(),
228
+ toSessionId: to_session_id,
229
+ fromTaskId: from_task_id,
230
+ text,
231
+ queuedAt: Date.now(),
232
+ delivered: false,
233
+ kind,
234
+ });
235
+ if (kind === "stop") {
236
+ const task = plan.tasks.find((t) => t.spawnedSessionId === to_session_id);
237
+ if (task)
238
+ task.stopRequested = { reason: text, requestedAt: Date.now() };
239
+ }
240
+ return { plan_id, queued: true, kind };
241
+ });
242
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
243
+ }, ({ plan_id }) => ({ planId: plan_id })));
244
+ }
245
+ //# sourceMappingURL=broker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.js","sourceRoot":"","sources":["../../src/tools/broker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StateStore } from "../lib/state.js";
3
+ import type { AuditLog } from "../lib/audit.js";
4
+ /**
5
+ * Dispatch-phase tools: next_task, register_spawn, status, collect.
6
+ *
7
+ * v0.2.0:
8
+ * • status() now includes per-agent hallucination report + token usage.
9
+ * • status() flips the plan to `cancelled_overbudget` and queues STOP
10
+ * broker messages when total token usage exceeds the budget cap.
11
+ * • The spawn prompt embeds the task_id so children can self-register via
12
+ * `checkin` on their first turn — register_spawn becomes a fallback.
13
+ */
14
+ export declare function registerDispatch(server: McpServer, store: StateStore, audit: AuditLog): void;