@jeffober/thatch 0.1.34 → 0.1.36
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 +15 -0
- package/artifacts/skills/thatch-code-review.md +8 -2
- package/artifacts/skills/thatch-review-context.md +15 -3
- package/artifacts/skills/thatch-review-synthesizer.md +7 -5
- package/bin/thatch +157 -0
- package/docs/dev/README.md +10 -3
- package/docs/dev/features/README.md +1 -0
- package/docs/dev/features/multi-host.md +16 -10
- package/docs/dev/features/watchers.md +150 -0
- package/docs/dev/mcp-parity.md +1 -1
- package/docs/dev/skills.md +7 -5
- package/docs/user/README.md +25 -1
- package/docs/user/code-review.md +11 -3
- package/docs/user/skills.md +1 -1
- package/docs/user/watchers.md +79 -0
- package/package.json +1 -1
- package/src/index.ts +61 -2
- package/src/mcp.ts +4 -1
- package/src/prompts.ts +43 -7
- package/src/session-db.ts +452 -0
- package/src/skills.ts +22 -46
- package/src/tool-defs.ts +269 -3
- package/src/tools.ts +11 -3
- package/src/watchers.ts +511 -0
package/docs/dev/skills.md
CHANGED
|
@@ -47,7 +47,7 @@ description: Extract durable project facts ... Use when ...
|
|
|
47
47
|
| `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
|
|
48
48
|
| `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar against generic praise. |
|
|
49
49
|
| `thatch-review-synthesizer` | Verify specialist findings against code, dedupe, classify, calibrate severity. Starts the final report with a workflow-change preface, then cross-references findings against prior review comments when a follow-up round register is provided. |
|
|
50
|
-
| `thatch-review-context` | Gather project/feature context (PR descriptions, git archaeology, ticket references, memory) before fan-out. Prevents false positives about intentionally deferred work. Also fetches prior review comments on a connected PR/MR for follow-up-round detection and builds a register with preliminary addressed-check status per comment. |
|
|
50
|
+
| `thatch-review-context` | Gather project/feature context (PR descriptions, git archaeology, ticket references, linked docs/tickets followed from the change, memory) before fan-out. Prevents false positives about intentionally deferred work, and checks whether main moved past the merge-base touching the same paths (staleness signal for the synthesizer). Also fetches prior review comments on a connected PR/MR for follow-up-round detection and builds a register with preliminary addressed-check status per comment. |
|
|
51
51
|
| `thatch-code-archaeology` | Investigate an existing feature, debug an unfamiliar area, or begin a new ticket. Explores the code base from multiple angles (data model, state flow, git history, sibling features, skeletons) before proposing changes. The research skill; pair with `thatch-coding-workflow`. |
|
|
52
52
|
| `thatch-review-followup` | Alternate entrypoint for follow-up review rounds. Verifies whether the author's responses and code changes since your last review round adequately addressed your prior findings, offers to reply on resolved items, then optionally re-runs the full structured review. |
|
|
53
53
|
| `thatch-change-walkthrough` | Explain a change to the user as a teaching walkthrough: resolve the delta, research each affected workflow at the merge-base, teach current behavior, then overlay the modifications with file:line citations and analogies. |
|
|
@@ -119,10 +119,12 @@ and `--cursor` pass only the shared set.
|
|
|
119
119
|
versions without users manually deleting files.
|
|
120
120
|
- **Stale cleanup**: before installing, `installSkills` removes stale skill
|
|
121
121
|
directories. Any `thatch-*` directory not in the current install set is
|
|
122
|
-
deleted (the `thatch-` prefix is our namespace).
|
|
123
|
-
|
|
124
|
-
split-overlarge-pr)
|
|
125
|
-
|
|
122
|
+
deleted (the `thatch-` prefix is our namespace). Non-prefixed directories
|
|
123
|
+
are never touched: the v0.1.27 rename migration (pr-description,
|
|
124
|
+
ticket-description, split-overlarge-pr) cleaned up old installs only
|
|
125
|
+
through a version window that closed with v0.1.35, after which those names
|
|
126
|
+
are fair game for third parties and the cleanup no longer runs. Users
|
|
127
|
+
upgrading from before v0.1.27 delete the old directories manually.
|
|
126
128
|
- **Idempotent**: re-running init or setup overwrites drifted content but leaves
|
|
127
129
|
unrelated (non-`thatch-*`) skill files alone.
|
|
128
130
|
|
package/docs/user/README.md
CHANGED
|
@@ -11,6 +11,7 @@ This README is the overview. Each feature has its own guide:
|
|
|
11
11
|
|
|
12
12
|
- [memory.md](memory.md): persistent memory store
|
|
13
13
|
- [extraction.md](extraction.md): automatic fact extraction from tool calls
|
|
14
|
+
- [watchers.md](watchers.md): event-driven notifications (PR watching)
|
|
14
15
|
- [prediction-engine.md](prediction-engine.md): user decision model
|
|
15
16
|
- [behavior-engine.md](behavior-engine.md): agent self-discipline rules
|
|
16
17
|
- [default-behaviors.md](default-behaviors.md): what ships automatically
|
|
@@ -142,6 +143,29 @@ Stores are created automatically. No setup required.
|
|
|
142
143
|
| `thatch_behavior_list` | List all codified behaviors with matchers, confidence, and provenance. |
|
|
143
144
|
| `thatch_behavior_delete` | Delete a behavior by semantic match. Edges and provenance are cascade-deleted. |
|
|
144
145
|
|
|
146
|
+
### Session tools (opencode only)
|
|
147
|
+
|
|
148
|
+
| Tool | What it does |
|
|
149
|
+
|------|-------------|
|
|
150
|
+
| `thatch_get_session_info` | Report the current session's ID and the agent name running this turn. opencode doesn't surface its session ID to the model; the agent needs it to fetch extraction payloads or look up past sessions. MCP hosts have no session concept, so this tool doesn't exist there. |
|
|
151
|
+
| `thatch_session_search` | Search past opencode conversations by substring or regex. Matches decoded message text, tool outputs, and reasoning across all sessions. Returns JSONL hits with ids for follow-up. |
|
|
152
|
+
| `thatch_session_get` | Retrieve the full content of one part or message found via `thatch_session_search`, including complete tool inputs and outputs. |
|
|
153
|
+
|
|
154
|
+
The same functionality is available on the command line as `thatch session
|
|
155
|
+
list`, `thatch session get`, `thatch session transcript`, and `thatch session
|
|
156
|
+
search` - JSONL output designed for piping to `jq` or `grep`.
|
|
157
|
+
|
|
158
|
+
### Watcher tools (opencode only)
|
|
159
|
+
|
|
160
|
+
| Tool | What it does |
|
|
161
|
+
|------|-------------|
|
|
162
|
+
| `thatch_watch_create` | Watch a GitHub PR for events (comments, review comments and replies, commits, status changes, description edits, CI completions). The plugin polls in the background and prompts the session when a watched event happens. |
|
|
163
|
+
| `thatch_watch_list` | List this session's active watchers. |
|
|
164
|
+
| `thatch_watch_cancel` | Cancel one of this session's watchers by id. |
|
|
165
|
+
|
|
166
|
+
See [watchers.md](watchers.md) for the full behavior, lifetime, and
|
|
167
|
+
requirements.
|
|
168
|
+
|
|
145
169
|
## Automatic behaviors
|
|
146
170
|
|
|
147
171
|
Beyond the tools, thatch hooks into opencode itself:
|
|
@@ -237,7 +261,7 @@ response, walkthrough, and workflow skills that support the review pipeline:
|
|
|
237
261
|
| `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
|
|
238
262
|
| `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar against generic praise. |
|
|
239
263
|
| `thatch-review-synthesizer` | Verifies and synthesizes findings from multiple specialists into a report that starts with workflow changes, then highlights, then deduplicated severity-grouped findings. |
|
|
240
|
-
| `thatch-review-context` | Gathers project context (PR descriptions, git archaeology, ticket references, memory) before a review. Prevents false positives about intentionally deferred work. |
|
|
264
|
+
| `thatch-review-context` | Gathers project context (PR descriptions, git archaeology, ticket references, linked docs/tickets, memory) before a review. Prevents false positives about intentionally deferred work. |
|
|
241
265
|
| `thatch-code-archaeology` | Investigates an existing feature, debugs an unfamiliar area, or begins a new ticket. Explores the code base from multiple angles (data model, state flow, git history, sibling features, skeletons) before proposing changes. Pairs with `thatch-coding-workflow`. |
|
|
242
266
|
| `thatch-review-followup` | Alternate entrypoint for follow-up review rounds. Verifies whether the author's responses and code changes since your last review adequately addressed your prior findings, offers to reply on resolved items, then optionally re-runs the full structured review. |
|
|
243
267
|
| `thatch-review-response` | Author-side review response: triage findings on your own PR, fix bugs one by one, reply on each thread, post a top-level summary comment. |
|
package/docs/user/code-review.md
CHANGED
|
@@ -10,9 +10,15 @@ The coordinator skill (`thatch-code-review`, opencode-only) orchestrates
|
|
|
10
10
|
the review:
|
|
11
11
|
|
|
12
12
|
1. **Resolve the target**: fetch origin, compute merge-base against
|
|
13
|
-
`origin/main`, support branch/PR/explicit range.
|
|
13
|
+
`origin/main`, support branch/PR/explicit range. All file reads and
|
|
14
|
+
comment anchors are computed against the PR head ref, not the
|
|
15
|
+
working tree, which may be checked out on a different branch.
|
|
14
16
|
2. **Gather project context**: PR descriptions, git archaeology,
|
|
15
|
-
ticket references,
|
|
17
|
+
ticket references, links to docs/designs/tickets found in the
|
|
18
|
+
change (followed one hop for scope and design context), TODO
|
|
19
|
+
markers, prior reviews, project memory. Also checks whether main
|
|
20
|
+
has moved past the merge-base touching the same paths — a stale
|
|
21
|
+
branch can make findings true only at the merge-base.
|
|
16
22
|
3. **Research affected workflows**: load `thatch-code-archaeology`,
|
|
17
23
|
trace the code paths the change touches.
|
|
18
24
|
4. **Estimate complexity**: partition the diff into review units.
|
|
@@ -21,7 +27,9 @@ the review:
|
|
|
21
27
|
6. **Synthesize**: the synthesizer reads all specialist output,
|
|
22
28
|
verifies each finding (cited text exists, claim is accurate,
|
|
23
29
|
severity is justified), deduplicates by root cause, and produces
|
|
24
|
-
the final report.
|
|
30
|
+
the final report. When the branch is stale relative to main, it
|
|
31
|
+
re-verifies behavioral findings against current main and reports
|
|
32
|
+
merge-base-only findings as rebase notes rather than defects.
|
|
25
33
|
|
|
26
34
|
## The eight specialists
|
|
27
35
|
|
package/docs/user/skills.md
CHANGED
|
@@ -46,7 +46,7 @@ becomes part of the agent's context.
|
|
|
46
46
|
| `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
|
|
47
47
|
| `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar. |
|
|
48
48
|
| `thatch-review-synthesizer` | Verifies and synthesizes findings from multiple specialists into a deduplicated, severity-grouped report. |
|
|
49
|
-
| `thatch-review-context` | Gathers project context (PRs, tickets, TODOs, deferred work) before a review. Prevents false positives about intentionally deferred work. |
|
|
49
|
+
| `thatch-review-context` | Gathers project context (PRs, tickets, linked docs/designs followed from the change, TODOs, deferred work) before a review. Prevents false positives about intentionally deferred work. |
|
|
50
50
|
| `thatch-code-archaeology` | Investigates an existing feature, debugs an unfamiliar area, or begins a new ticket. The research skill; pair with `thatch-coding-workflow`. |
|
|
51
51
|
| `thatch-review-followup` | Verifies whether the author's responses and code changes since your last review adequately addressed your prior findings. |
|
|
52
52
|
| `thatch-review-response` | Author-side review response: triage findings on your own PR, fix bugs one by one, reply on each thread, post a top-level summary comment. |
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Watchers
|
|
2
|
+
|
|
3
|
+
Watchers monitor external sources - today, GitHub pull requests - and
|
|
4
|
+
inject a notification into the conversation when something happens. You
|
|
5
|
+
ask the agent to watch a PR; thatch polls it in the background; the
|
|
6
|
+
agent gets woken up when a watched event occurs. No one has to keep
|
|
7
|
+
asking "any updates yet?"
|
|
8
|
+
|
|
9
|
+
## What it does
|
|
10
|
+
|
|
11
|
+
The agent calls `thatch_watch_create` to register a watcher on a PR.
|
|
12
|
+
thatch captures the PR's current state as a baseline, then polls the
|
|
13
|
+
GitHub API through the `gh` CLI once a minute. When the PR changes in a
|
|
14
|
+
way the watcher cares about, the plugin prompts the agent with a
|
|
15
|
+
notification.
|
|
16
|
+
|
|
17
|
+
Watched events:
|
|
18
|
+
|
|
19
|
+
- `pr_comment` - new top-level comments on the PR
|
|
20
|
+
- `pr_review_comment` - new inline comments on the diff
|
|
21
|
+
- `pr_review_reply` - replies to an existing review comment
|
|
22
|
+
- `pr_commit` - new commits (the head SHA moved)
|
|
23
|
+
- `pr_status` - the PR opened, closed, or merged
|
|
24
|
+
- `pr_description` - title or description edited
|
|
25
|
+
- `pr_ci` - a CI check run on the head SHA completed
|
|
26
|
+
|
|
27
|
+
Notifications are delivered as synthetic parts: the model sees them,
|
|
28
|
+
the transcript does not. A notification triggers a model turn, so the
|
|
29
|
+
agent can act on the event even while you are away.
|
|
30
|
+
|
|
31
|
+
## Privacy model
|
|
32
|
+
|
|
33
|
+
Notifications carry pointer data only: who commented, what happened,
|
|
34
|
+
and a URL. Comment bodies, diff contents, and CI logs never enter the
|
|
35
|
+
context from the notification itself. This is deliberate - GitHub
|
|
36
|
+
comments are written by strangers, and untrusted text flowing into a
|
|
37
|
+
model's context is a prompt-injection vector. The agent fetches details
|
|
38
|
+
on demand with `gh` when it decides to act.
|
|
39
|
+
|
|
40
|
+
## How to use it
|
|
41
|
+
|
|
42
|
+
Ask for it in conversation:
|
|
43
|
+
|
|
44
|
+
> Watch PR 1234 for review comments. If bugbot comments, handle it
|
|
45
|
+
> yourself. If a human comments, just tell me.
|
|
46
|
+
|
|
47
|
+
The handling policy lives in your instruction. State it when you ask -
|
|
48
|
+
the notification turn reads your policy from the conversation and
|
|
49
|
+
follows it. The notification says what happened and where, not what to
|
|
50
|
+
do about it.
|
|
51
|
+
|
|
52
|
+
Other tools:
|
|
53
|
+
|
|
54
|
+
- `thatch_watch_list` - shows the session's active watchers
|
|
55
|
+
- `thatch_watch_cancel` - cancels one by id
|
|
56
|
+
|
|
57
|
+
## Lifetime
|
|
58
|
+
|
|
59
|
+
Watchers are in-memory and process-scoped:
|
|
60
|
+
|
|
61
|
+
- Ending the opencode process (or restarting it) drops all watchers.
|
|
62
|
+
- A watcher expires after 8 hours by default.
|
|
63
|
+
- Each session can hold up to 5 active watchers.
|
|
64
|
+
|
|
65
|
+
If opencode restarts while a watch is active, re-register it - the
|
|
66
|
+
session's conversation survives, so the policy you stated is still
|
|
67
|
+
there.
|
|
68
|
+
|
|
69
|
+
## Requirements and limitations
|
|
70
|
+
|
|
71
|
+
- **opencode only.** MCP hosts (Claude Code, Cursor) have no way for a
|
|
72
|
+
plugin to start a conversation turn, so the watch tools are not
|
|
73
|
+
available there.
|
|
74
|
+
- **Requires the `gh` CLI** to be installed and authenticated. Watch
|
|
75
|
+
creation reports a clear error if it is not.
|
|
76
|
+
- **Polling, not webhooks.** Events appear on the next poll cycle
|
|
77
|
+
(60 seconds by default), not instantly.
|
|
78
|
+
- **No delivery during an active turn.** If the agent is mid-turn when
|
|
79
|
+
an event fires, the notification waits until the turn ends.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeffober/thatch",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"description": "Persistent memory for AI coding agents — local embeddings, SQLite stores, zero config. Works with OpenCode (as a plugin), Claude Code (as an MCP server), and Cursor (as an MCP server).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
package/src/index.ts
CHANGED
|
@@ -21,6 +21,8 @@ import { installSkills, SHARED_SKILLS, OPENCODE_ONLY_SKILLS } from "./skills";
|
|
|
21
21
|
import { hygieneReport } from "./hygiene";
|
|
22
22
|
import { seedDefaultBehaviors } from "./seed-behaviors";
|
|
23
23
|
import { startVersionChecker, stopVersionChecker, getVersionChecker, readOnDiskVersion, compareSemver } from "./version-check";
|
|
24
|
+
import { WatcherRegistry, ghApiRun, ghAvailable } from "./watchers";
|
|
25
|
+
import { watcherNotificationNudge } from "./prompts";
|
|
24
26
|
import pkg from "../package.json";
|
|
25
27
|
|
|
26
28
|
// ---------------------------------------------------------------------------
|
|
@@ -83,6 +85,43 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
83
85
|
// non-restart.
|
|
84
86
|
const runningVersion = pkg.version;
|
|
85
87
|
|
|
88
|
+
// Latest observed opencode session status per session ("busy" | "idle" |
|
|
89
|
+
// "retry"). The event hook records these; the watcher registry's
|
|
90
|
+
// canDeliver gate reads them so proactive notification prompts only fire
|
|
91
|
+
// into idle sessions - never into a turn that is already running.
|
|
92
|
+
const sessionStatus = new Map<string, string>();
|
|
93
|
+
|
|
94
|
+
// In-memory watcher registry for proactive event notifications (GitHub PR
|
|
95
|
+
// watching today). Deliberately process-scoped: no SQLite, no cross-restart
|
|
96
|
+
// state. See src/watchers.ts for the rationale.
|
|
97
|
+
//
|
|
98
|
+
// Delivery prompts the session with a synthetic part - the same mechanism
|
|
99
|
+
// opencode uses for background task completions - so a watched event
|
|
100
|
+
// triggers a model turn even when the user is away. Events only carry
|
|
101
|
+
// pointer data; the model fetches details itself with gh.
|
|
102
|
+
const watchers = new WatcherRegistry({
|
|
103
|
+
deliver: async (sessionID, events) => {
|
|
104
|
+
const target = events[0]?.url.match(/github\.com\/([^/]+\/[^/]+)\/pull\/(\d+)/)?.[0]
|
|
105
|
+
?.replace(/github\.com\//, "")
|
|
106
|
+
.replace(/\/pull\//, "#") ?? "watched PR";
|
|
107
|
+
await client.session.promptAsync({
|
|
108
|
+
path: { id: sessionID },
|
|
109
|
+
body: {
|
|
110
|
+
parts: [{ type: "text", text: watcherNotificationNudge(target, events), synthetic: true }],
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
canDeliver: (sessionID) =>
|
|
115
|
+
!compacting.has(sessionID) && sessionStatus.get(sessionID) === "idle",
|
|
116
|
+
ghRunner: ghApiRun,
|
|
117
|
+
});
|
|
118
|
+
// gh presence decides whether watch_create works; checked lazily by the
|
|
119
|
+
// tool, but log once at startup so misconfiguration is visible in debug logs.
|
|
120
|
+
void ghAvailable().then((ok) => {
|
|
121
|
+
if (!ok) console.error("[thatch] gh CLI not found - watch tools will report unavailable");
|
|
122
|
+
});
|
|
123
|
+
watchers.start();
|
|
124
|
+
|
|
86
125
|
// Sessions currently being compacted. chat.message nudges are skipped while
|
|
87
126
|
// a session is in this set - the agent can't call tools during summary
|
|
88
127
|
// generation, so a recall or extraction nudge would cause a blocked-tool
|
|
@@ -242,6 +281,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
242
281
|
if (all.length === 0) return null;
|
|
243
282
|
return extraction.buildPayload(all, repo);
|
|
244
283
|
},
|
|
284
|
+
watcherRegistry: watchers,
|
|
245
285
|
}),
|
|
246
286
|
|
|
247
287
|
// 1. System prompt - always in context.
|
|
@@ -600,8 +640,13 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
600
640
|
}
|
|
601
641
|
return;
|
|
602
642
|
}
|
|
603
|
-
if (event.type === "session.status"
|
|
643
|
+
if (event.type === "session.status") {
|
|
604
644
|
const sessionID = event.properties.sessionID;
|
|
645
|
+
const statusType = event.properties.status?.type;
|
|
646
|
+
// Record the latest status so the watcher registry can gate
|
|
647
|
+
// proactive prompt delivery on idle sessions.
|
|
648
|
+
if (sessionID && statusType) sessionStatus.set(sessionID, statusType);
|
|
649
|
+
if (statusType !== "idle") return;
|
|
605
650
|
const parentID = sessionID ? childToParent.get(sessionID) : undefined;
|
|
606
651
|
if (parentID && sessionID) {
|
|
607
652
|
// A child session went idle. Two cases:
|
|
@@ -685,6 +730,15 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
685
730
|
extracting.delete(sessionID);
|
|
686
731
|
}
|
|
687
732
|
}
|
|
733
|
+
// The session just became idle, so watcher events queued while it
|
|
734
|
+
// was busy can be delivered now - the poll interval may otherwise
|
|
735
|
+
// hold them for up to a full cycle. Best-effort; failures stay
|
|
736
|
+
// pending and retry on the next poll.
|
|
737
|
+
try {
|
|
738
|
+
await watchers.deliverPending();
|
|
739
|
+
} catch (err) {
|
|
740
|
+
console.error(`[thatch] watcher delivery on idle failed: ${err}`);
|
|
741
|
+
}
|
|
688
742
|
return;
|
|
689
743
|
}
|
|
690
744
|
if (event.type === "session.deleted") {
|
|
@@ -699,9 +753,13 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
699
753
|
parentSnapshots.delete(id);
|
|
700
754
|
childMetrics.delete(id);
|
|
701
755
|
extractionChildren.delete(id);
|
|
702
|
-
// A deleted parent takes its accepted entries with it
|
|
756
|
+
// A deleted parent takes its accepted entries with it, and its
|
|
757
|
+
// watchers die with it - the session that would receive their
|
|
758
|
+
// notifications no longer exists.
|
|
703
759
|
extraction.completeAccepted(id);
|
|
704
760
|
extracting.delete(id);
|
|
761
|
+
sessionStatus.delete(id);
|
|
762
|
+
watchers.cancelSession(id);
|
|
705
763
|
return;
|
|
706
764
|
}
|
|
707
765
|
|
|
@@ -739,6 +797,7 @@ export const server: Plugin = async ({ client, worktree }) => {
|
|
|
739
797
|
|
|
740
798
|
dispose: async () => {
|
|
741
799
|
stopVersionChecker();
|
|
800
|
+
watchers.dispose();
|
|
742
801
|
db.close();
|
|
743
802
|
},
|
|
744
803
|
};
|
package/src/mcp.ts
CHANGED
|
@@ -60,9 +60,12 @@ interface CompiledTool {
|
|
|
60
60
|
inputSchema: Record<string, unknown>;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
function compileTools(): Map<string, CompiledTool> {
|
|
63
|
+
export function compileTools(): Map<string, CompiledTool> {
|
|
64
64
|
const map = new Map<string, CompiledTool>();
|
|
65
65
|
for (const def of TOOL_DEFS) {
|
|
66
|
+
// opencode-only tools depend on host capabilities MCP servers don't
|
|
67
|
+
// have (e.g. session identity via HostToolContext) - never expose them.
|
|
68
|
+
if (def.opencodeOnly) continue;
|
|
66
69
|
const schema = z.object(def.args);
|
|
67
70
|
map.set(def.name, {
|
|
68
71
|
def,
|
package/src/prompts.ts
CHANGED
|
@@ -17,13 +17,15 @@ Thatch provides persistent memory across opencode sessions. Use it to persist
|
|
|
17
17
|
knowledge so future sessions can build on what you've already learned.
|
|
18
18
|
|
|
19
19
|
Tools: thatch_memory_remember, thatch_memory_recall, thatch_memory_list,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
thatch_memory_show, thatch_memory_forget, thatch_store_list,
|
|
21
|
+
thatch_find_duplicates, thatch_dedup_mark_checked,
|
|
22
|
+
thatch_extraction_done, thatch_get_extraction_payload,
|
|
23
|
+
thatch_prediction_query, thatch_prediction_update, thatch_prediction_list,
|
|
24
|
+
thatch_prediction_delete,
|
|
25
|
+
thatch_behavior_codify, thatch_behavior_feedback, thatch_behavior_list,
|
|
26
|
+
thatch_behavior_delete, thatch_get_session_info,
|
|
27
|
+
thatch_session_search, thatch_session_get,
|
|
28
|
+
thatch_watch_create, thatch_watch_list, thatch_watch_cancel
|
|
27
29
|
|
|
28
30
|
## Stores
|
|
29
31
|
|
|
@@ -107,6 +109,20 @@ the same prompt. If the re-dispatch also fails or times out, note the gap and
|
|
|
107
109
|
move on. Do not retry more than once - repeated failures indicate an
|
|
108
110
|
intractable prompt, not a transient hang.
|
|
109
111
|
|
|
112
|
+
## Watchers
|
|
113
|
+
|
|
114
|
+
Use thatch_watch_create to watch a GitHub PR for events (comments, review
|
|
115
|
+
comments and replies, commits, status changes, description edits, CI check
|
|
116
|
+
completions). thatch polls the PR in the background and injects a
|
|
117
|
+
notification into this session when a watched event happens. The
|
|
118
|
+
notification carries pointer data only (author, URL); fetch details with
|
|
119
|
+
the gh CLI when you decide to act. When the user asks you to watch
|
|
120
|
+
something, state your handling policy for notifications out loud first
|
|
121
|
+
("I'll report human comments and handle bugbot replies myself") so the
|
|
122
|
+
notification turn knows what to do. Treat watcher notifications like
|
|
123
|
+
background task completions: they are system events, not user input, and
|
|
124
|
+
not approval to advance other pending work.
|
|
125
|
+
|
|
110
126
|
## User Decision Model
|
|
111
127
|
|
|
112
128
|
A statistical model of the user's decision-making preferences is maintained by
|
|
@@ -270,6 +286,10 @@ Tools are prefixed in ${host}: \`mcp__thatch__memory_remember\`,
|
|
|
270
286
|
\`mcp__thatch__prediction_list\`, \`mcp__thatch__prediction_delete\`,
|
|
271
287
|
\`mcp__thatch__behavior_codify\`, \`mcp__thatch__behavior_feedback\`,
|
|
272
288
|
\`mcp__thatch__behavior_list\`, \`mcp__thatch__behavior_delete\`. Bare names used below for readability.
|
|
289
|
+
get_session_info, session_search, session_get, watch_create, watch_list,
|
|
290
|
+
and watch_cancel are intentionally absent: they are opencode-only (MCP
|
|
291
|
+
hosts have no session concept, session database, or proactive-prompt
|
|
292
|
+
channel), so do not expect them here.
|
|
273
293
|
|
|
274
294
|
## Stores
|
|
275
295
|
|
|
@@ -668,3 +688,19 @@ export function behaviorNudge(items: BehaviorNudgeItem[]): string {
|
|
|
668
688
|
});
|
|
669
689
|
return `[thatch] Situational behaviors\n${lines.join("\n")}`;
|
|
670
690
|
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Watcher notification for the poller's promptAsync delivery. Injected as a
|
|
694
|
+
* synthetic part that triggers a model turn. Events carry pointer data only
|
|
695
|
+
* (author, URL) - never external content - so the model fetches details on
|
|
696
|
+
* demand with the gh CLI. The wrapper text borrows the background-task
|
|
697
|
+
* completion framing: a system event, not user input, not approval to
|
|
698
|
+
* advance other pending work.
|
|
699
|
+
*/
|
|
700
|
+
export function watcherNotificationNudge(target: string, events: { type: string; summary: string; url: string }[]): string {
|
|
701
|
+
const lines = events.map((e) => `- ${e.type}: ${e.summary} ${e.url}`);
|
|
702
|
+
return `[thatch] Watcher notification for ${target}
|
|
703
|
+
${lines.join("\n")}
|
|
704
|
+
|
|
705
|
+
This is a system notification, not user input. Decide whether to act now or keep waiting - the user's instructions from when the watch was created govern how to handle it. Fetch details with the gh CLI if you need them. Do not treat this notification as approval to advance other pending work. If you act, tell the user what you did and why; if not, stop and wait.`;
|
|
706
|
+
}
|