@jeffober/thatch 0.2.3 → 0.2.4

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/bin/thatch CHANGED
@@ -8,7 +8,7 @@ import { detectRepo } from "../src/git";
8
8
  import { BgeEmbeddingModel } from "../src/embeddings";
9
9
  import { hygieneReport } from "../src/hygiene";
10
10
  import { claudeSessionStartReminder } from "../src/prompts";
11
- import { setupClaudeCode, setupCursor, registerClaudeMcpServer } from "../src/setup";
11
+ import { setupClaudeCode, setupCursor, setupSkillsOnly, registerClaudeMcpServer } from "../src/setup";
12
12
  import { resolveOpencodeDbPath, SessionDB, partToTimelineEntry, partToTranscriptEntries, partToFullJson, messageToFullJson, type SessionPart } from "../src/session-db";
13
13
  import { chatTailDiff, chatTailBacklog, filterChatTailRows, formatChatTailJsonl, CHAT_TAIL_DEFAULT_LIMIT, parseChatTimeBound, CHAT_STALE_MS, CHAT_RENUDGE_MINUTES, chatLiveness, humanAge, splitChatRoster, sortChatRoster, mcpSessionID, isoMinutesAgo, renderChatParticipant, resolveRegisteredPredecessor, type ChatSessionRow, type ChatTailFilter } from "../src/chat";
14
14
  import { chatEnabled, loadConfig } from "../src/config";
@@ -38,8 +38,10 @@ function usage(): never {
38
38
  thatch flush-tools [--json] Peek the queue + print an extraction nudge (hook only)
39
39
  thatch chat-notify Print a chat follow-up message when mail is unread (Cursor stop hook)
40
40
  thatch flush-predictions [--json] Query predictions for the prompt (hook only)
41
- thatch setup --claude [--cursor] [--local|--global]
42
- Install config + instructions + hooks + skills
41
+ thatch setup --claude [--cursor] [--local|--global] [--skills-only]
42
+ Install config + instructions + hooks + skills.
43
+ --skills-only refreshes just the skill files
44
+ (skips MCP config, instructions, hooks, commands)
43
45
  thatch session list -s <id> [--after T] [--before T]
44
46
  JSONL timeline of a session's parts (one line per part)
45
47
  thatch session get --id <part_id|msg_id>
@@ -839,6 +841,10 @@ switch (command) {
839
841
  const isLocal = args.includes("--local");
840
842
  const isClaude = args.includes("--claude");
841
843
  const isCursor = args.includes("--cursor");
844
+ // --skills-only narrows the run to the skill install: same host and
845
+ // scope rules, but MCP config, instructions, hooks, and commands are
846
+ // left untouched.
847
+ const skillsOnly = args.includes("--skills-only");
842
848
 
843
849
  if (isGlobal && isLocal) {
844
850
  console.error("Choose one scope: --local or --global.");
@@ -875,52 +881,73 @@ switch (command) {
875
881
  };
876
882
 
877
883
  if (isClaude) {
878
- const result = setupClaudeCode(thatchBin, isGlobal, dir);
884
+ if (skillsOnly) {
885
+ const result = setupSkillsOnly("claude", isGlobal, dir);
879
886
 
880
- console.log(`Thatch setup complete for Claude Code (${isGlobal ? "global" : "project-local"}).`);
881
- console.log();
882
- if (result.mcpConfig) {
883
- console.log(` MCP config: ${result.mcpConfig}`);
884
- }
885
- console.log(` Instructions: ${result.claudeMd}`);
886
- console.log(` Hooks: ${result.settings}`);
887
- printSkills(result);
888
- if (result.commands.length > 0) {
889
- console.log(` Commands: ${result.commands.length} written (${result.commands.map((p) => p.split("/").pop()).join(", ")})`);
890
- }
891
- console.log();
892
- if (result.mcpAddCommand) {
893
- // Global setup cannot write ~/.claude.json directly, so run the
894
- // registration on the user's behalf. Idempotent: an existing
895
- // registration is left alone; a missing or failing claude CLI
896
- // falls back to printing the manual command.
897
- const reg = await registerClaudeMcpServer(thatchBin);
898
- if (reg.status === "registered") {
899
- console.log(` MCP server: ${reg.detail}`);
900
- } else if (reg.status === "already-registered") {
901
- console.log(` MCP server: already registered (claude mcp get thatch to inspect)`);
902
- } else {
903
- console.log("To register the MCP server globally, run:");
904
- console.log(` ${result.mcpAddCommand}`);
905
- console.log(` (${reg.detail})`);
887
+ console.log(`Thatch skills updated for Claude Code (${isGlobal ? "global" : "project-local"}).`);
888
+ console.log();
889
+ printSkills(result);
890
+ console.log();
891
+ console.log("Restart Claude Code for the changes to take effect.");
892
+ } else {
893
+ const result = setupClaudeCode(thatchBin, isGlobal, dir);
894
+
895
+ console.log(`Thatch setup complete for Claude Code (${isGlobal ? "global" : "project-local"}).`);
896
+ console.log();
897
+ if (result.mcpConfig) {
898
+ console.log(` MCP config: ${result.mcpConfig}`);
899
+ }
900
+ console.log(` Instructions: ${result.claudeMd}`);
901
+ console.log(` Hooks: ${result.settings}`);
902
+ printSkills(result);
903
+ if (result.commands.length > 0) {
904
+ console.log(` Commands: ${result.commands.length} written (${result.commands.map((p) => p.split("/").pop()).join(", ")})`);
906
905
  }
907
906
  console.log();
907
+ if (result.mcpAddCommand) {
908
+ // Global setup cannot write ~/.claude.json directly, so run the
909
+ // registration on the user's behalf. Idempotent: an existing
910
+ // registration is left alone; a missing or failing claude CLI
911
+ // falls back to printing the manual command.
912
+ const reg = await registerClaudeMcpServer(thatchBin);
913
+ if (reg.status === "registered") {
914
+ console.log(` MCP server: ${reg.detail}`);
915
+ } else if (reg.status === "already-registered") {
916
+ console.log(` MCP server: already registered (claude mcp get thatch to inspect)`);
917
+ } else {
918
+ console.log("To register the MCP server globally, run:");
919
+ console.log(` ${result.mcpAddCommand}`);
920
+ console.log(` (${reg.detail})`);
921
+ }
922
+ console.log();
923
+ }
924
+ console.log("Restart Claude Code for the changes to take effect.");
908
925
  }
909
- console.log("Restart Claude Code for the changes to take effect.");
910
926
  }
911
927
 
912
928
  if (isCursor) {
913
- const result = setupCursor(thatchBin, isGlobal, dir);
929
+ if (skillsOnly) {
930
+ const result = setupSkillsOnly("cursor", isGlobal, dir);
914
931
 
915
- console.log();
916
- console.log(`Thatch setup complete for Cursor (${isGlobal ? "global" : "project-local"}).`);
917
- console.log();
918
- console.log(` MCP config: ${result.mcpConfig}`);
919
- console.log(` Instructions: ${result.agentsMd}`);
920
- console.log(` Hooks: ${result.hooks}`);
921
- printSkills(result);
922
- console.log();
923
- console.log("Restart Cursor for the changes to take effect.");
932
+ console.log();
933
+ console.log(`Thatch skills updated for Cursor (${isGlobal ? "global" : "project-local"}).`);
934
+ console.log();
935
+ printSkills(result);
936
+ console.log();
937
+ console.log("Restart Cursor for the changes to take effect.");
938
+ } else {
939
+ const result = setupCursor(thatchBin, isGlobal, dir);
940
+
941
+ console.log();
942
+ console.log(`Thatch setup complete for Cursor (${isGlobal ? "global" : "project-local"}).`);
943
+ console.log();
944
+ console.log(` MCP config: ${result.mcpConfig}`);
945
+ console.log(` Instructions: ${result.agentsMd}`);
946
+ console.log(` Hooks: ${result.hooks}`);
947
+ printSkills(result);
948
+ console.log();
949
+ console.log("Restart Cursor for the changes to take effect.");
950
+ }
924
951
  }
925
952
  break;
926
953
  }
@@ -18,6 +18,8 @@ resolution fit together.
18
18
  hooks, and skills for Cursor
19
19
  - `--global` flag --- installs to user-scoped config dirs instead of
20
20
  project-local
21
+ - `--skills-only` flag --- refreshes just the skill files (same host and
22
+ scope rules), skipping MCP config, instructions, hooks, and commands
21
23
  - **Marker system** --- idempotent replacement of the thatch instruction block
22
24
  in `CLAUDE.md` or `AGENTS.md` via start/end markers
23
25
  - **`checkSetup`** --- detects installed, not-installed, or markers-broken at
@@ -35,6 +37,11 @@ resolution fit together.
35
37
 
36
38
  At least one of `--claude` or `--cursor` is required. Both can be passed
37
39
  together. `--global` applies to whichever host or hosts are selected.
40
+ `--skills-only` narrows the run to the skill install (`setupSkillsOnly`
41
+ in `src/setup.ts`): it reuses the same path resolution and other-scope
42
+ probe as the full setup paths but only calls `installSkills`, so it is
43
+ safe to run in an already-set-up host when only the skill files need
44
+ refreshing.
38
45
 
39
46
  ### Claude Code setup (`setupClaudeCode` in `src/setup.ts`)
40
47
 
package/docs/user/cli.md CHANGED
@@ -148,7 +148,8 @@ thatch buffer-batch # append tool batch to queue (Claude Code hook)
148
148
  thatch buffer-tool # append single tool to queue (Cursor hook)
149
149
  thatch flush-tools [--json] # peek queue + print nudges (hook)
150
150
  thatch flush-predictions [--json] # prediction-only nudge (hook)
151
- thatch setup --claude [--cursor] [--global] # install config + hooks + skills
151
+ thatch setup --claude [--cursor] [--global] # install config + hooks + skills
152
+ thatch setup --claude --skills-only # refresh just the skill files
152
153
  ```
153
154
 
154
155
  ## Environment variables
@@ -60,6 +60,16 @@ Skills follow the install scope: project-local installs them to the
60
60
  repo's `.claude/skills/` so they version with the project; `--global`
61
61
  installs them to `~/.claude/skills/` (or `$CLAUDE_CONFIG_DIR/skills/`).
62
62
 
63
+ To refresh just the skill files without rewriting anything else, add
64
+ `--skills-only`:
65
+
66
+ ```bash
67
+ thatch setup --claude --skills-only
68
+ ```
69
+
70
+ This skips the MCP config, instructions, hooks, and commands, and
71
+ reports the same skills directory and install counts as a full run.
72
+
63
73
  `bun` must be on PATH (the thatch binary runs under bun). Setup is
64
74
  idempotent. Re-running it updates drifted content without clobbering
65
75
  unrelated config, and reports what it did: the skills directory plus
@@ -84,6 +94,9 @@ thatch setup --cursor --global # user-scoped (~/.cursor/)
84
94
  Skills follow the install scope: project-local installs them to the
85
95
  repo's `.cursor/skills/`; `--global` installs them to `~/.cursor/skills/`.
86
96
 
97
+ As with Claude Code, `--skills-only` refreshes just the skill files and
98
+ skips the MCP config, instructions, and hooks.
99
+
87
100
  Cursor uses a flat hooks format (`{version, hooks:{event:[{command}]}}`)
88
101
  and `--json` output for hook commands.
89
102
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeffober/thatch",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
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/setup.ts CHANGED
@@ -643,6 +643,56 @@ export function setupCursor(
643
643
  };
644
644
  }
645
645
 
646
+ // ---------------------------------------------------------------------------
647
+ // Skills-only setup - refresh skill files without touching anything else
648
+ // ---------------------------------------------------------------------------
649
+
650
+ export interface SkillsOnlyResult {
651
+ /** Skill install report for the directory this run wrote to. */
652
+ skills: InstallReport;
653
+ /** Thatch skills in the opposite scope's dir, if any; never written by this run. */
654
+ otherScopeSkills: OtherScopeSkills | null;
655
+ global: boolean;
656
+ }
657
+
658
+ /**
659
+ * Installs only the skill files, skipping MCP config, instructions, hooks,
660
+ * and commands. Intended for refreshing skills in an already-set-up host
661
+ * without rewriting the rest of the configuration. Same scope rules as full
662
+ * setup: project-local runs write to the repo's host skills dir, global runs
663
+ * to the host config dir, and the other scope is probed (surfaced in the
664
+ * report) but never written.
665
+ */
666
+ export function setupSkillsOnly(
667
+ host: HostKind,
668
+ global: boolean,
669
+ projectDir: string,
670
+ homeDir?: string,
671
+ ): SkillsOnlyResult {
672
+ const { homedir } = require("node:os");
673
+ const home = homeDir ?? homedir();
674
+
675
+ const skillsDir = host === "claude"
676
+ ? resolvePaths(global, projectDir, home).skillsDir
677
+ : resolveCursorPaths(global, projectDir, home).skillsDir;
678
+
679
+ // Same other-scope logic as the full setup paths: surface skills this run
680
+ // did not touch so the CLI can warn about leftovers.
681
+ const otherDir = host === "claude"
682
+ ? (global
683
+ ? join(projectDir, ".claude", "skills")
684
+ : join(claudeConfigDir(home), "skills"))
685
+ : (global
686
+ ? join(projectDir, ".cursor", "skills")
687
+ : join(cursorConfigDir(home), "skills"));
688
+
689
+ return {
690
+ skills: installSkills(skillsDir),
691
+ otherScopeSkills: otherScopeInfo(otherDir),
692
+ global,
693
+ };
694
+ }
695
+
646
696
  // ---------------------------------------------------------------------------
647
697
  // Setup detection - check whether setup was completed for the current host
648
698
  // ---------------------------------------------------------------------------