@variantree/watcher 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/dist/__tests__/git-snapshot.test.d.ts +2 -0
- package/dist/__tests__/git-snapshot.test.d.ts.map +1 -0
- package/dist/__tests__/git-snapshot.test.js +437 -0
- package/dist/__tests__/git-snapshot.test.js.map +1 -0
- package/dist/__tests__/integration.test.d.ts +10 -0
- package/dist/__tests__/integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration.test.js +316 -0
- package/dist/__tests__/integration.test.js.map +1 -0
- package/dist/__tests__/watcher.test.d.ts +2 -0
- package/dist/__tests__/watcher.test.d.ts.map +1 -0
- package/dist/__tests__/watcher.test.js +375 -0
- package/dist/__tests__/watcher.test.js.map +1 -0
- package/dist/adapters/aider.d.ts +21 -0
- package/dist/adapters/aider.d.ts.map +1 -0
- package/dist/adapters/aider.js +42 -0
- package/dist/adapters/aider.js.map +1 -0
- package/dist/adapters/base.d.ts +3 -0
- package/dist/adapters/base.d.ts.map +1 -0
- package/dist/adapters/base.js +2 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/claude-code.d.ts +17 -0
- package/dist/adapters/claude-code.d.ts.map +1 -0
- package/dist/adapters/claude-code.js +58 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/opencode.d.ts +3 -0
- package/dist/adapters/opencode.d.ts.map +1 -0
- package/dist/adapters/opencode.js +3 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/agents-md.d.ts +18 -0
- package/dist/agents-md.d.ts.map +1 -0
- package/dist/agents-md.js +93 -0
- package/dist/agents-md.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +511 -0
- package/dist/cli.js.map +1 -0
- package/dist/differ.d.ts +18 -0
- package/dist/differ.d.ts.map +1 -0
- package/dist/differ.js +23 -0
- package/dist/differ.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/node/blob-store.d.ts +16 -0
- package/dist/node/blob-store.d.ts.map +1 -0
- package/dist/node/blob-store.js +47 -0
- package/dist/node/blob-store.js.map +1 -0
- package/dist/node/fs-adapter.d.ts +17 -0
- package/dist/node/fs-adapter.d.ts.map +1 -0
- package/dist/node/fs-adapter.js +110 -0
- package/dist/node/fs-adapter.js.map +1 -0
- package/dist/node/git-snapshot.d.ts +46 -0
- package/dist/node/git-snapshot.d.ts.map +1 -0
- package/dist/node/git-snapshot.js +282 -0
- package/dist/node/git-snapshot.js.map +1 -0
- package/dist/node/session-launcher.d.ts +14 -0
- package/dist/node/session-launcher.d.ts.map +1 -0
- package/dist/node/session-launcher.js +28 -0
- package/dist/node/session-launcher.js.map +1 -0
- package/dist/node/storage.d.ts +17 -0
- package/dist/node/storage.d.ts.map +1 -0
- package/dist/node/storage.js +56 -0
- package/dist/node/storage.js.map +1 -0
- package/dist/sync.d.ts +16 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +58 -0
- package/dist/sync.js.map +1 -0
- package/dist/tools/base.d.ts +52 -0
- package/dist/tools/base.d.ts.map +1 -0
- package/dist/tools/base.js +10 -0
- package/dist/tools/base.js.map +1 -0
- package/dist/tools/claudecode/adapter.d.ts +26 -0
- package/dist/tools/claudecode/adapter.d.ts.map +1 -0
- package/dist/tools/claudecode/adapter.js +111 -0
- package/dist/tools/claudecode/adapter.js.map +1 -0
- package/dist/tools/claudecode/config.d.ts +8 -0
- package/dist/tools/claudecode/config.d.ts.map +1 -0
- package/dist/tools/claudecode/config.js +34 -0
- package/dist/tools/claudecode/config.js.map +1 -0
- package/dist/tools/claudecode/index.d.ts +9 -0
- package/dist/tools/claudecode/index.d.ts.map +1 -0
- package/dist/tools/claudecode/index.js +16 -0
- package/dist/tools/claudecode/index.js.map +1 -0
- package/dist/tools/claudecode/instructions.d.ts +7 -0
- package/dist/tools/claudecode/instructions.d.ts.map +1 -0
- package/dist/tools/claudecode/instructions.js +21 -0
- package/dist/tools/claudecode/instructions.js.map +1 -0
- package/dist/tools/index.d.ts +24 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +42 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/instructions.d.ts +19 -0
- package/dist/tools/instructions.d.ts.map +1 -0
- package/dist/tools/instructions.js +93 -0
- package/dist/tools/instructions.js.map +1 -0
- package/dist/tools/opencode/adapter.d.ts +46 -0
- package/dist/tools/opencode/adapter.d.ts.map +1 -0
- package/dist/tools/opencode/adapter.js +166 -0
- package/dist/tools/opencode/adapter.js.map +1 -0
- package/dist/tools/opencode/config.d.ts +8 -0
- package/dist/tools/opencode/config.d.ts.map +1 -0
- package/dist/tools/opencode/config.js +37 -0
- package/dist/tools/opencode/config.js.map +1 -0
- package/dist/tools/opencode/index.d.ts +9 -0
- package/dist/tools/opencode/index.d.ts.map +1 -0
- package/dist/tools/opencode/index.js +16 -0
- package/dist/tools/opencode/index.js.map +1 -0
- package/dist/tools/opencode/instructions.d.ts +10 -0
- package/dist/tools/opencode/instructions.d.ts.map +1 -0
- package/dist/tools/opencode/instructions.js +26 -0
- package/dist/tools/opencode/instructions.js.map +1 -0
- package/dist/watcher.d.ts +40 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +87 -0
- package/dist/watcher.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* All registered tool integrations.
|
|
3
|
+
*
|
|
4
|
+
* To add a new tool: create src/tools/<toolname>/ implementing ToolIntegration,
|
|
5
|
+
* then add it to the ALL_TOOLS array below.
|
|
6
|
+
*/
|
|
7
|
+
export { VARIANTREE_MARKER, VARIANTREE_INSTRUCTIONS_SECTION, mergeInstructions } from './instructions.js';
|
|
8
|
+
export { opencodeTool, OpenCodeAdapter, mergeAgentsMd } from './opencode/index.js';
|
|
9
|
+
export { claudecodeTool, ClaudeCodeAdapter } from './claudecode/index.js';
|
|
10
|
+
import { opencodeTool } from './opencode/index.js';
|
|
11
|
+
import { claudecodeTool } from './claudecode/index.js';
|
|
12
|
+
/** Every tool Variantree knows about. Used by postinstall and ensureInstructions. */
|
|
13
|
+
export const ALL_TOOLS = [opencodeTool, claudecodeTool];
|
|
14
|
+
/**
|
|
15
|
+
* Write standing instructions for all tools into the project directory.
|
|
16
|
+
* Called on every MCP session start and `variantree init`.
|
|
17
|
+
*/
|
|
18
|
+
export function ensureProjectInstructions(projectDir) {
|
|
19
|
+
for (const tool of ALL_TOOLS) {
|
|
20
|
+
try {
|
|
21
|
+
tool.writeProjectInstructions(projectDir);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Never let instruction writing break the main flow
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Register MCP server in all tools' global configs.
|
|
30
|
+
* Called once by the postinstall script.
|
|
31
|
+
*/
|
|
32
|
+
export function registerAllMcp() {
|
|
33
|
+
for (const tool of ALL_TOOLS) {
|
|
34
|
+
try {
|
|
35
|
+
tool.registerGlobalMcp?.();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Postinstall must never fail
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,iBAAiB,EAAE,+BAA+B,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE1G,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,qFAAqF;AACrF,MAAM,CAAC,MAAM,SAAS,GAAsB,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;AAE3E;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,UAAkB;IAC1D,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,IAAI,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,oDAAoD;QACtD,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,8BAA8B;QAChC,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical standing-instructions text for Variantree.
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth. Each tool module uses the marker +
|
|
5
|
+
* body to write into its own file format (AGENTS.md, CLAUDE.md, etc.).
|
|
6
|
+
*/
|
|
7
|
+
export declare const VARIANTREE_MARKER = "<!-- variantree:instructions -->";
|
|
8
|
+
export declare const VARIANTREE_INSTRUCTIONS_BODY = "## Variantree \u2014 AI Version Control\n\nYou have access to Variantree MCP tools for managing conversation context and\ncode snapshots. Use them **proactively** \u2014 don't wait for the user to ask.\n\n### On session start\n- If `.variantree/branch-context.md` exists, read it immediately for context\n on prior work done on this branch.\n\n### When to checkpoint\n- After completing a distinct task or sub-task (e.g. \"auth is working\",\n \"tests pass\", \"refactor done\").\n- When the user says \"done\", \"looks good\", \"ship it\", or \"let's move on\".\n- Before any branch, switch, or restore \u2014 the tools will warn you if you\n forget, but it's better to checkpoint proactively.\n\n### When to branch\n- When the user wants to explore an alternative approach (\"let's try X\n instead\", \"what if we used Y\").\n- When the user asks to experiment without losing current progress.\n\n### When to switch / restore\n- When the user wants to go back to a previous line of work or a known-good\n state (\"go back to main\", \"restore the working version\").\n\n### Handling unsaved-message warnings\nIf a tool returns an unsaved-message warning (e.g. \"4 messages will be lost\"):\n1. **STOP** \u2014 do NOT silently pass `force: true`.\n2. Tell the user exactly how many messages will be lost.\n3. Ask: *\"Should I checkpoint first to save them, or discard them and\n proceed?\"*\n4. Only use `force: true` after the user explicitly says to discard /\n proceed without saving.\n\n### Presenting results to the user\n**IMPORTANT:** Always relay the COMPLETE tool output to the user. Do not\nsummarise or omit details. Specifically:\n\n- **checkpoint:** Show messages synced count, snapshot diff (files added,\n modified, deleted), and total file count.\n- **branch / switch / restore:** Show files written and deleted, then show\n the full conversation context summary that was returned.\n- **status:** Show ALL fields: active branch, message count, every branch\n name, and every checkpoint label with snapshot indicator.\n- **tree:** Show the FULL tree output exactly as returned \u2014 branches AND\n checkpoints. Do not collapse or summarise it.\n- **log:** Show the full conversation history returned by the tool.\n\n### Tool reference\n| Tool | Purpose |\n|-------------|----------------------------------------------|\n| checkpoint | Sync conversation + snapshot code |\n| branch | Create a new branch from a checkpoint |\n| switch | Switch to an existing branch |\n| restore | Restore code to a specific checkpoint |\n| status | Show active branch, checkpoints |\n| tree | ASCII tree of branches and checkpoints |\n| log | Show conversation history for a branch |";
|
|
9
|
+
/** The full fenced section, ready to embed in any markdown file. */
|
|
10
|
+
export declare const VARIANTREE_INSTRUCTIONS_SECTION = "<!-- variantree:instructions -->\n## Variantree \u2014 AI Version Control\n\nYou have access to Variantree MCP tools for managing conversation context and\ncode snapshots. Use them **proactively** \u2014 don't wait for the user to ask.\n\n### On session start\n- If `.variantree/branch-context.md` exists, read it immediately for context\n on prior work done on this branch.\n\n### When to checkpoint\n- After completing a distinct task or sub-task (e.g. \"auth is working\",\n \"tests pass\", \"refactor done\").\n- When the user says \"done\", \"looks good\", \"ship it\", or \"let's move on\".\n- Before any branch, switch, or restore \u2014 the tools will warn you if you\n forget, but it's better to checkpoint proactively.\n\n### When to branch\n- When the user wants to explore an alternative approach (\"let's try X\n instead\", \"what if we used Y\").\n- When the user asks to experiment without losing current progress.\n\n### When to switch / restore\n- When the user wants to go back to a previous line of work or a known-good\n state (\"go back to main\", \"restore the working version\").\n\n### Handling unsaved-message warnings\nIf a tool returns an unsaved-message warning (e.g. \"4 messages will be lost\"):\n1. **STOP** \u2014 do NOT silently pass `force: true`.\n2. Tell the user exactly how many messages will be lost.\n3. Ask: *\"Should I checkpoint first to save them, or discard them and\n proceed?\"*\n4. Only use `force: true` after the user explicitly says to discard /\n proceed without saving.\n\n### Presenting results to the user\n**IMPORTANT:** Always relay the COMPLETE tool output to the user. Do not\nsummarise or omit details. Specifically:\n\n- **checkpoint:** Show messages synced count, snapshot diff (files added,\n modified, deleted), and total file count.\n- **branch / switch / restore:** Show files written and deleted, then show\n the full conversation context summary that was returned.\n- **status:** Show ALL fields: active branch, message count, every branch\n name, and every checkpoint label with snapshot indicator.\n- **tree:** Show the FULL tree output exactly as returned \u2014 branches AND\n checkpoints. Do not collapse or summarise it.\n- **log:** Show the full conversation history returned by the tool.\n\n### Tool reference\n| Tool | Purpose |\n|-------------|----------------------------------------------|\n| checkpoint | Sync conversation + snapshot code |\n| branch | Create a new branch from a checkpoint |\n| switch | Switch to an existing branch |\n| restore | Restore code to a specific checkpoint |\n| status | Show active branch, checkpoints |\n| tree | ASCII tree of branches and checkpoints |\n| log | Show conversation history for a branch |\n<!-- variantree:instructions -->";
|
|
11
|
+
/**
|
|
12
|
+
* Merge the Variantree instructions section into an existing file's content.
|
|
13
|
+
*
|
|
14
|
+
* - No existing content → wraps in a minimal markdown document.
|
|
15
|
+
* - Content without the marker → appends the section.
|
|
16
|
+
* - Content with the marker → replaces the section in-place.
|
|
17
|
+
*/
|
|
18
|
+
export declare function mergeInstructions(existingContent: string | null, heading: string): string;
|
|
19
|
+
//# sourceMappingURL=instructions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../src/tools/instructions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,iBAAiB,qCAAqC,CAAC;AAEpE,eAAO,MAAM,4BAA4B,oyFA0DuB,CAAC;AAEjE,oEAAoE;AACpE,eAAO,MAAM,+BAA+B,w2FACmC,CAAC;AAEhF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAoBzF"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical standing-instructions text for Variantree.
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth. Each tool module uses the marker +
|
|
5
|
+
* body to write into its own file format (AGENTS.md, CLAUDE.md, etc.).
|
|
6
|
+
*/
|
|
7
|
+
export const VARIANTREE_MARKER = '<!-- variantree:instructions -->';
|
|
8
|
+
export const VARIANTREE_INSTRUCTIONS_BODY = `\
|
|
9
|
+
## Variantree — AI Version Control
|
|
10
|
+
|
|
11
|
+
You have access to Variantree MCP tools for managing conversation context and
|
|
12
|
+
code snapshots. Use them **proactively** — don't wait for the user to ask.
|
|
13
|
+
|
|
14
|
+
### On session start
|
|
15
|
+
- If \`.variantree/branch-context.md\` exists, read it immediately for context
|
|
16
|
+
on prior work done on this branch.
|
|
17
|
+
|
|
18
|
+
### When to checkpoint
|
|
19
|
+
- After completing a distinct task or sub-task (e.g. "auth is working",
|
|
20
|
+
"tests pass", "refactor done").
|
|
21
|
+
- When the user says "done", "looks good", "ship it", or "let's move on".
|
|
22
|
+
- Before any branch, switch, or restore — the tools will warn you if you
|
|
23
|
+
forget, but it's better to checkpoint proactively.
|
|
24
|
+
|
|
25
|
+
### When to branch
|
|
26
|
+
- When the user wants to explore an alternative approach ("let's try X
|
|
27
|
+
instead", "what if we used Y").
|
|
28
|
+
- When the user asks to experiment without losing current progress.
|
|
29
|
+
|
|
30
|
+
### When to switch / restore
|
|
31
|
+
- When the user wants to go back to a previous line of work or a known-good
|
|
32
|
+
state ("go back to main", "restore the working version").
|
|
33
|
+
|
|
34
|
+
### Handling unsaved-message warnings
|
|
35
|
+
If a tool returns an unsaved-message warning (e.g. "4 messages will be lost"):
|
|
36
|
+
1. **STOP** — do NOT silently pass \`force: true\`.
|
|
37
|
+
2. Tell the user exactly how many messages will be lost.
|
|
38
|
+
3. Ask: *"Should I checkpoint first to save them, or discard them and
|
|
39
|
+
proceed?"*
|
|
40
|
+
4. Only use \`force: true\` after the user explicitly says to discard /
|
|
41
|
+
proceed without saving.
|
|
42
|
+
|
|
43
|
+
### Presenting results to the user
|
|
44
|
+
**IMPORTANT:** Always relay the COMPLETE tool output to the user. Do not
|
|
45
|
+
summarise or omit details. Specifically:
|
|
46
|
+
|
|
47
|
+
- **checkpoint:** Show messages synced count, snapshot diff (files added,
|
|
48
|
+
modified, deleted), and total file count.
|
|
49
|
+
- **branch / switch / restore:** Show files written and deleted, then show
|
|
50
|
+
the full conversation context summary that was returned.
|
|
51
|
+
- **status:** Show ALL fields: active branch, message count, every branch
|
|
52
|
+
name, and every checkpoint label with snapshot indicator.
|
|
53
|
+
- **tree:** Show the FULL tree output exactly as returned — branches AND
|
|
54
|
+
checkpoints. Do not collapse or summarise it.
|
|
55
|
+
- **log:** Show the full conversation history returned by the tool.
|
|
56
|
+
|
|
57
|
+
### Tool reference
|
|
58
|
+
| Tool | Purpose |
|
|
59
|
+
|-------------|----------------------------------------------|
|
|
60
|
+
| checkpoint | Sync conversation + snapshot code |
|
|
61
|
+
| branch | Create a new branch from a checkpoint |
|
|
62
|
+
| switch | Switch to an existing branch |
|
|
63
|
+
| restore | Restore code to a specific checkpoint |
|
|
64
|
+
| status | Show active branch, checkpoints |
|
|
65
|
+
| tree | ASCII tree of branches and checkpoints |
|
|
66
|
+
| log | Show conversation history for a branch |`;
|
|
67
|
+
/** The full fenced section, ready to embed in any markdown file. */
|
|
68
|
+
export const VARIANTREE_INSTRUCTIONS_SECTION = `${VARIANTREE_MARKER}\n${VARIANTREE_INSTRUCTIONS_BODY}\n${VARIANTREE_MARKER}`;
|
|
69
|
+
/**
|
|
70
|
+
* Merge the Variantree instructions section into an existing file's content.
|
|
71
|
+
*
|
|
72
|
+
* - No existing content → wraps in a minimal markdown document.
|
|
73
|
+
* - Content without the marker → appends the section.
|
|
74
|
+
* - Content with the marker → replaces the section in-place.
|
|
75
|
+
*/
|
|
76
|
+
export function mergeInstructions(existingContent, heading) {
|
|
77
|
+
const section = VARIANTREE_INSTRUCTIONS_SECTION;
|
|
78
|
+
if (!existingContent) {
|
|
79
|
+
return `# ${heading}\n\n${section}\n`;
|
|
80
|
+
}
|
|
81
|
+
const start = existingContent.indexOf(VARIANTREE_MARKER);
|
|
82
|
+
if (start === -1) {
|
|
83
|
+
return existingContent.trimEnd() + '\n\n' + section + '\n';
|
|
84
|
+
}
|
|
85
|
+
const end = existingContent.indexOf(VARIANTREE_MARKER, start + VARIANTREE_MARKER.length);
|
|
86
|
+
if (end === -1) {
|
|
87
|
+
return existingContent.trimEnd() + '\n\n' + section + '\n';
|
|
88
|
+
}
|
|
89
|
+
const before = existingContent.slice(0, start);
|
|
90
|
+
const after = existingContent.slice(end + VARIANTREE_MARKER.length);
|
|
91
|
+
return before + section + after;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=instructions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../../src/tools/instructions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,kCAAkC,CAAC;AAEpE,MAAM,CAAC,MAAM,4BAA4B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gEA0DoB,CAAC;AAEjE,oEAAoE;AACpE,MAAM,CAAC,MAAM,+BAA+B,GAC1C,GAAG,iBAAiB,KAAK,4BAA4B,KAAK,iBAAiB,EAAE,CAAC;AAEhF;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,eAA8B,EAAE,OAAe;IAC/E,MAAM,OAAO,GAAG,+BAA+B,CAAC;IAEhD,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,OAAO,KAAK,OAAO,OAAO,OAAO,IAAI,CAAC;IACxC,CAAC;IAED,MAAM,KAAK,GAAG,eAAe,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzD,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QACjB,OAAO,eAAe,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IAC7D,CAAC;IAED,MAAM,GAAG,GAAG,eAAe,CAAC,OAAO,CAAC,iBAAiB,EAAE,KAAK,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACzF,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACf,OAAO,eAAe,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IAC7D,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACpE,OAAO,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @variantree/watcher — OpenCode Session Adapter
|
|
3
|
+
*
|
|
4
|
+
* OpenCode stores all data in a SQLite database (WAL mode).
|
|
5
|
+
* Location varies by OS:
|
|
6
|
+
* macOS/Linux: ~/.local/share/opencode/opencode.db
|
|
7
|
+
* Windows: %APPDATA%/opencode/opencode.db
|
|
8
|
+
*
|
|
9
|
+
* Uses better-sqlite3 (native binding) so WAL-mode writes are visible
|
|
10
|
+
* immediately — sql.js only reads the main DB file and misses WAL data.
|
|
11
|
+
*
|
|
12
|
+
* Schema:
|
|
13
|
+
* session → message (data JSON: {role, time, ...})
|
|
14
|
+
* → part (data JSON: {type:"text", text:"..."})
|
|
15
|
+
*/
|
|
16
|
+
import type { Message } from '@variantree/core';
|
|
17
|
+
import type { SessionAdapter } from '../base.js';
|
|
18
|
+
export declare class OpenCodeAdapter implements SessionAdapter {
|
|
19
|
+
readonly name = "opencode";
|
|
20
|
+
private getDbPath;
|
|
21
|
+
private openDb;
|
|
22
|
+
/**
|
|
23
|
+
* Returns the path to the WAL file — this changes on every DB write,
|
|
24
|
+
* making it the perfect file for chokidar to watch.
|
|
25
|
+
*/
|
|
26
|
+
findSessionFile(workspacePath: string): Promise<string | null>;
|
|
27
|
+
/**
|
|
28
|
+
* parseMessages reads from the SQLite DB directly.
|
|
29
|
+
* The `raw` parameter is ignored — use readMessagesAsync instead.
|
|
30
|
+
*/
|
|
31
|
+
parseMessages(_raw: string): Message[];
|
|
32
|
+
/**
|
|
33
|
+
* Get the ID of the most recently active OpenCode session for a directory.
|
|
34
|
+
* Returns null if no session exists yet.
|
|
35
|
+
*/
|
|
36
|
+
getCurrentSessionId(workspacePath: string): Promise<string | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Read messages from OpenCode's DB, optionally scoped to a specific session.
|
|
39
|
+
*
|
|
40
|
+
* @param workspacePath - Filter to sessions for this directory
|
|
41
|
+
* @param sessionId - If provided, read from this specific session instead of
|
|
42
|
+
* querying for the latest. Prevents stale messages from old sessions.
|
|
43
|
+
*/
|
|
44
|
+
readMessagesAsync(workspacePath?: string, sessionId?: string): Promise<Message[]>;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/tools/opencode/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAkBjD,qBAAa,eAAgB,YAAW,cAAc;IACpD,QAAQ,CAAC,IAAI,cAAc;IAE3B,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,MAAM;IAKd;;;OAGG;IACG,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAkBpE;;;OAGG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE;IAItC;;;OAGG;IACG,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAaxE;;;;;;OAMG;IACG,iBAAiB,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAqExF"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @variantree/watcher — OpenCode Session Adapter
|
|
3
|
+
*
|
|
4
|
+
* OpenCode stores all data in a SQLite database (WAL mode).
|
|
5
|
+
* Location varies by OS:
|
|
6
|
+
* macOS/Linux: ~/.local/share/opencode/opencode.db
|
|
7
|
+
* Windows: %APPDATA%/opencode/opencode.db
|
|
8
|
+
*
|
|
9
|
+
* Uses better-sqlite3 (native binding) so WAL-mode writes are visible
|
|
10
|
+
* immediately — sql.js only reads the main DB file and misses WAL data.
|
|
11
|
+
*
|
|
12
|
+
* Schema:
|
|
13
|
+
* session → message (data JSON: {role, time, ...})
|
|
14
|
+
* → part (data JSON: {type:"text", text:"..."})
|
|
15
|
+
*/
|
|
16
|
+
import Database from 'better-sqlite3';
|
|
17
|
+
import fs from 'node:fs';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
import os from 'node:os';
|
|
20
|
+
/**
|
|
21
|
+
* Get the OpenCode data directory based on the current OS.
|
|
22
|
+
*
|
|
23
|
+
* macOS/Linux: ~/.local/share/opencode/
|
|
24
|
+
* Windows: %APPDATA%/opencode/
|
|
25
|
+
*/
|
|
26
|
+
function getOpenCodeDataDir() {
|
|
27
|
+
const platform = os.platform();
|
|
28
|
+
if (platform === 'win32') {
|
|
29
|
+
const appData = process.env.APPDATA ?? path.join(os.homedir(), 'AppData', 'Roaming');
|
|
30
|
+
return path.join(appData, 'opencode');
|
|
31
|
+
}
|
|
32
|
+
const dataHome = process.env.XDG_DATA_HOME ?? path.join(os.homedir(), '.local', 'share');
|
|
33
|
+
return path.join(dataHome, 'opencode');
|
|
34
|
+
}
|
|
35
|
+
export class OpenCodeAdapter {
|
|
36
|
+
name = 'opencode';
|
|
37
|
+
getDbPath() {
|
|
38
|
+
return path.join(getOpenCodeDataDir(), 'opencode.db');
|
|
39
|
+
}
|
|
40
|
+
openDb() {
|
|
41
|
+
const dbPath = this.getDbPath();
|
|
42
|
+
return new Database(dbPath, { readonly: true });
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Returns the path to the WAL file — this changes on every DB write,
|
|
46
|
+
* making it the perfect file for chokidar to watch.
|
|
47
|
+
*/
|
|
48
|
+
async findSessionFile(workspacePath) {
|
|
49
|
+
const dbPath = this.getDbPath();
|
|
50
|
+
try {
|
|
51
|
+
fs.accessSync(dbPath);
|
|
52
|
+
const db = this.openDb();
|
|
53
|
+
const row = db.prepare(`SELECT id FROM session WHERE directory = ? ORDER BY time_updated DESC LIMIT 1`).get(workspacePath);
|
|
54
|
+
db.close();
|
|
55
|
+
if (!row)
|
|
56
|
+
return null;
|
|
57
|
+
const walPath = dbPath + '-wal';
|
|
58
|
+
try {
|
|
59
|
+
fs.accessSync(walPath);
|
|
60
|
+
return walPath;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return dbPath;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* parseMessages reads from the SQLite DB directly.
|
|
72
|
+
* The `raw` parameter is ignored — use readMessagesAsync instead.
|
|
73
|
+
*/
|
|
74
|
+
parseMessages(_raw) {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get the ID of the most recently active OpenCode session for a directory.
|
|
79
|
+
* Returns null if no session exists yet.
|
|
80
|
+
*/
|
|
81
|
+
async getCurrentSessionId(workspacePath) {
|
|
82
|
+
try {
|
|
83
|
+
const db = this.openDb();
|
|
84
|
+
const row = db.prepare(`SELECT id FROM session WHERE directory = ? ORDER BY time_updated DESC LIMIT 1`).get(workspacePath);
|
|
85
|
+
db.close();
|
|
86
|
+
return row?.id ?? null;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Read messages from OpenCode's DB, optionally scoped to a specific session.
|
|
94
|
+
*
|
|
95
|
+
* @param workspacePath - Filter to sessions for this directory
|
|
96
|
+
* @param sessionId - If provided, read from this specific session instead of
|
|
97
|
+
* querying for the latest. Prevents stale messages from old sessions.
|
|
98
|
+
*/
|
|
99
|
+
async readMessagesAsync(workspacePath, sessionId) {
|
|
100
|
+
try {
|
|
101
|
+
const db = this.openDb();
|
|
102
|
+
let resolvedSessionId;
|
|
103
|
+
if (sessionId) {
|
|
104
|
+
const check = db.prepare(`SELECT id FROM session WHERE id = ? LIMIT 1`).get(sessionId);
|
|
105
|
+
if (!check) {
|
|
106
|
+
db.close();
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
resolvedSessionId = sessionId;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
let row;
|
|
113
|
+
if (workspacePath) {
|
|
114
|
+
row = db.prepare(`SELECT id FROM session WHERE directory = ? ORDER BY time_updated DESC LIMIT 1`).get(workspacePath);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
row = db.prepare(`SELECT id FROM session ORDER BY time_updated DESC LIMIT 1`).get();
|
|
118
|
+
}
|
|
119
|
+
if (!row) {
|
|
120
|
+
db.close();
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
resolvedSessionId = row.id;
|
|
124
|
+
}
|
|
125
|
+
const msgRows = db.prepare(`SELECT id, data, time_created FROM message WHERE session_id = ? ORDER BY time_created ASC`).all(resolvedSessionId);
|
|
126
|
+
const partRows = db.prepare(`SELECT message_id, data FROM part WHERE session_id = ? ORDER BY time_created ASC`).all(resolvedSessionId);
|
|
127
|
+
db.close();
|
|
128
|
+
// Group text parts by message ID
|
|
129
|
+
const partsByMsg = new Map();
|
|
130
|
+
for (const row of partRows) {
|
|
131
|
+
try {
|
|
132
|
+
const partData = JSON.parse(row.data);
|
|
133
|
+
if (partData.type === 'text' && partData.text) {
|
|
134
|
+
if (!partsByMsg.has(row.message_id))
|
|
135
|
+
partsByMsg.set(row.message_id, []);
|
|
136
|
+
partsByMsg.get(row.message_id).push(partData.text);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch { /* skip malformed parts */ }
|
|
140
|
+
}
|
|
141
|
+
// Build Message array
|
|
142
|
+
const result = [];
|
|
143
|
+
for (const msg of msgRows) {
|
|
144
|
+
try {
|
|
145
|
+
const msgData = JSON.parse(msg.data);
|
|
146
|
+
const textParts = partsByMsg.get(msg.id) ?? [];
|
|
147
|
+
const content = textParts.join('');
|
|
148
|
+
if (!content)
|
|
149
|
+
continue;
|
|
150
|
+
result.push({
|
|
151
|
+
id: msg.id,
|
|
152
|
+
role: msgData.role === 'user' ? 'user' : 'assistant',
|
|
153
|
+
content,
|
|
154
|
+
timestamp: msg.time_created,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
catch { /* skip malformed messages */ }
|
|
158
|
+
}
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/tools/opencode/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode global MCP registration.
|
|
3
|
+
*
|
|
4
|
+
* Writes the Variantree MCP server entry into ~/.config/opencode/opencode.json.
|
|
5
|
+
* Called once by the postinstall script.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerGlobalMcp(): void;
|
|
8
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/tools/opencode/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH,wBAAgB,iBAAiB,IAAI,IAAI,CAiBxC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode global MCP registration.
|
|
3
|
+
*
|
|
4
|
+
* Writes the Variantree MCP server entry into ~/.config/opencode/opencode.json.
|
|
5
|
+
* Called once by the postinstall script.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import os from 'node:os';
|
|
10
|
+
const MCP_ENTRY = {
|
|
11
|
+
type: 'local',
|
|
12
|
+
command: ['npx', '-y', '@variantree/mcp'],
|
|
13
|
+
environment: { VARIANTREE_DIR: '.' },
|
|
14
|
+
};
|
|
15
|
+
function getConfigPath() {
|
|
16
|
+
const configDir = process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), '.config');
|
|
17
|
+
return path.join(configDir, 'opencode', 'opencode.json');
|
|
18
|
+
}
|
|
19
|
+
export function registerGlobalMcp() {
|
|
20
|
+
const configPath = getConfigPath();
|
|
21
|
+
const configDir = path.dirname(configPath);
|
|
22
|
+
let config = {};
|
|
23
|
+
try {
|
|
24
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
25
|
+
}
|
|
26
|
+
catch { }
|
|
27
|
+
if (!config.mcp)
|
|
28
|
+
config.mcp = {};
|
|
29
|
+
const mcp = config.mcp;
|
|
30
|
+
if (mcp.variantree)
|
|
31
|
+
return; // already registered
|
|
32
|
+
mcp.variantree = MCP_ENTRY;
|
|
33
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
34
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
35
|
+
console.log('[variantree] OpenCode: MCP server registered in', configPath);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/tools/opencode/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,SAAS,GAAG;IAChB,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,iBAAiB,CAAC;IACzC,WAAW,EAAE,EAAE,cAAc,EAAE,GAAG,EAAE;CACrC,CAAC;AAEF,SAAS,aAAa;IACpB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IACpF,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAE3C,IAAI,MAAM,GAA4B,EAAE,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,IAAI,CAAC,MAAM,CAAC,GAAG;QAAE,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,MAAM,CAAC,GAA8B,CAAC;IAClD,IAAI,GAAG,CAAC,UAAU;QAAE,OAAO,CAAC,qBAAqB;IAEjD,GAAG,CAAC,UAAU,GAAG,SAAS,CAAC;IAC3B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,iDAAiD,EAAE,UAAU,CAAC,CAAC;AAC7E,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode tool integration.
|
|
3
|
+
*/
|
|
4
|
+
import type { ToolIntegration } from '../base.js';
|
|
5
|
+
export { OpenCodeAdapter } from './adapter.js';
|
|
6
|
+
export { writeProjectInstructions, mergeAgentsMd } from './instructions.js';
|
|
7
|
+
export { registerGlobalMcp } from './config.js';
|
|
8
|
+
export declare const opencodeTool: ToolIntegration;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/opencode/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKlD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,YAAY,EAAE,eAK1B,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode tool integration.
|
|
3
|
+
*/
|
|
4
|
+
import { OpenCodeAdapter } from './adapter.js';
|
|
5
|
+
import { writeProjectInstructions } from './instructions.js';
|
|
6
|
+
import { registerGlobalMcp } from './config.js';
|
|
7
|
+
export { OpenCodeAdapter } from './adapter.js';
|
|
8
|
+
export { writeProjectInstructions, mergeAgentsMd } from './instructions.js';
|
|
9
|
+
export { registerGlobalMcp } from './config.js';
|
|
10
|
+
export const opencodeTool = {
|
|
11
|
+
name: 'opencode',
|
|
12
|
+
adapter: new OpenCodeAdapter(),
|
|
13
|
+
registerGlobalMcp,
|
|
14
|
+
writeProjectInstructions,
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/opencode/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,CAAC,MAAM,YAAY,GAAoB;IAC3C,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,IAAI,eAAe,EAAE;IAC9B,iBAAiB;IACjB,wBAAwB;CACzB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode standing instructions — writes/merges into AGENTS.md.
|
|
3
|
+
*
|
|
4
|
+
* OpenCode reads AGENTS.md (and AGENTS, .agents.md variants) from the project
|
|
5
|
+
* root. OpenAI Codex also follows the same convention.
|
|
6
|
+
*/
|
|
7
|
+
export declare function writeProjectInstructions(projectDir: string): void;
|
|
8
|
+
/** @deprecated Use writeProjectInstructions. Kept for backwards compatibility. */
|
|
9
|
+
export declare function mergeAgentsMd(existingContent: string | null): string;
|
|
10
|
+
//# sourceMappingURL=instructions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../../src/tools/opencode/instructions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAMjE;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEpE"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode standing instructions — writes/merges into AGENTS.md.
|
|
3
|
+
*
|
|
4
|
+
* OpenCode reads AGENTS.md (and AGENTS, .agents.md variants) from the project
|
|
5
|
+
* root. OpenAI Codex also follows the same convention.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { mergeInstructions, VARIANTREE_MARKER } from '../instructions.js';
|
|
10
|
+
const FILENAME = 'AGENTS.md';
|
|
11
|
+
export function writeProjectInstructions(projectDir) {
|
|
12
|
+
const filePath = path.join(projectDir, FILENAME);
|
|
13
|
+
let existing = null;
|
|
14
|
+
try {
|
|
15
|
+
existing = fs.readFileSync(filePath, 'utf8');
|
|
16
|
+
}
|
|
17
|
+
catch { }
|
|
18
|
+
if (existing?.includes(VARIANTREE_MARKER))
|
|
19
|
+
return;
|
|
20
|
+
fs.writeFileSync(filePath, mergeInstructions(existing, 'AGENTS'), 'utf8');
|
|
21
|
+
}
|
|
22
|
+
/** @deprecated Use writeProjectInstructions. Kept for backwards compatibility. */
|
|
23
|
+
export function mergeAgentsMd(existingContent) {
|
|
24
|
+
return mergeInstructions(existingContent, 'AGENTS');
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=instructions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../../../src/tools/opencode/instructions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE1E,MAAM,QAAQ,GAAG,WAAW,CAAC;AAE7B,MAAM,UAAU,wBAAwB,CAAC,UAAkB;IACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACjD,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,CAAC;QAAC,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAC9D,IAAI,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC;QAAE,OAAO;IAClD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;AAC5E,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,aAAa,CAAC,eAA8B;IAC1D,OAAO,iBAAiB,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @variantree/watcher — VariantreeWatcher
|
|
3
|
+
*
|
|
4
|
+
* Watches an AI tool's session for new messages using chokidar.
|
|
5
|
+
* On every change event:
|
|
6
|
+
* 1. Reads messages via the adapter's readMessagesAsync
|
|
7
|
+
* 2. Diffs to find new messages
|
|
8
|
+
* 3. Adds new messages to the active Variantree branch
|
|
9
|
+
*/
|
|
10
|
+
import { VariantTree } from '@variantree/core';
|
|
11
|
+
import type { SessionAdapter } from './tools/base.js';
|
|
12
|
+
export interface WatcherOptions {
|
|
13
|
+
/** Absolute path to the workspace being watched */
|
|
14
|
+
workspacePath: string;
|
|
15
|
+
/** Session adapter for the AI tool (e.g. OpenCodeAdapter) */
|
|
16
|
+
adapter: SessionAdapter;
|
|
17
|
+
/** Pre-configured VariantTree engine instance */
|
|
18
|
+
engine: VariantTree;
|
|
19
|
+
/** Called when new messages are synced (optional, for logging) */
|
|
20
|
+
onSync?: (count: number) => void;
|
|
21
|
+
/** Called on errors (optional) */
|
|
22
|
+
onError?: (err: Error) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare class VariantreeWatcher {
|
|
25
|
+
private watcher;
|
|
26
|
+
private readonly differ;
|
|
27
|
+
private readonly opts;
|
|
28
|
+
private sessionId;
|
|
29
|
+
constructor(opts: WatcherOptions);
|
|
30
|
+
start(): Promise<void>;
|
|
31
|
+
stop(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Pick the best file to watch for changes.
|
|
34
|
+
* OpenCode: the WAL file changes on every DB write.
|
|
35
|
+
* Claude Code: the session JSONL file itself.
|
|
36
|
+
* Fallback: poll the workspace directory.
|
|
37
|
+
*/
|
|
38
|
+
private resolveWatchTarget;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGtD,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,OAAO,EAAE,cAAc,CAAC;IACxB,iDAAiD;IACjD,MAAM,EAAE,WAAW,CAAC;IACpB,kEAAkE;IAClE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,kCAAkC;IAClC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;CAChC;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiB;IACtC,OAAO,CAAC,SAAS,CAAuB;gBAE5B,IAAI,EAAE,cAAc;IAI1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiDtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;CAS3B"}
|