nia-opencode 0.1.0 → 0.1.2

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/cli.js CHANGED
@@ -7,7 +7,28 @@ import { homedir } from "node:os";
7
7
  import * as readline from "node:readline";
8
8
  var OPENCODE_CONFIG_DIR = join(homedir(), ".config", "opencode");
9
9
  var NIA_CONFIG_PATH = join(OPENCODE_CONFIG_DIR, "nia.json");
10
+ var AGENTS_MD_PATH = join(OPENCODE_CONFIG_DIR, "AGENTS.md");
10
11
  var PLUGIN_NAME = "nia-opencode@latest";
12
+ var NIA_AGENTS_INSTRUCTIONS = `
13
+ # How to use Nia
14
+
15
+ Nia provides tools for indexing and searching external repositories, research papers, local folders, documentation, packages, and performing AI-powered research. Its primary goal is to reduce hallucinations in LLMs and provide up-to-date context for AI agents.
16
+
17
+ ## Deterministic Workflow
18
+
19
+ 1. Check if the source is already indexed using manage_resource (when listing sources, use targeted query to save tokens since users can have multiple sources indexed) or check any nia.md files for already indexed sources.
20
+ 2. If it is indexed, check the tree of the source or ls relevant directories.
21
+ 3. After getting the grasp of the structure (tree), use 'search', 'nia_grep', 'nia_read' for targeted searches.
22
+ 4. If helpful, use the context tool to save your research findings to make them reusable for future conversations.
23
+ 5. Save your findings in an .md file to track: source indexed, used, its ID, and link so you won't have to list sources in the future and can get straight to work.
24
+
25
+ ## Notes
26
+
27
+ - DO NOT USE WEB RESEARCH TOOLS IF INFORMATION IS INDEXED IN NIA BY USING 'manage_resource' tool.
28
+ - If the source isn't indexed, index it. Note that for docs you should always index the root link like docs.stripe.com so it will always scrape all pages.
29
+ - If you need to index something but don't know the link for that source, use nia_research (quick or deep modes).
30
+ - Once you use the index tool, do not expect it to finish in 1-3 seconds. Stop your work or do something that will make your work pause for 1-5 minutes until the source is indexed, then run manage_resource again to check its status. You can also prompt the user to wait if needed.
31
+ `;
11
32
  function stripJsoncComments(content) {
12
33
  return content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
13
34
  }
@@ -155,6 +176,32 @@ function createNiaConfig(apiKey) {
155
176
  console.log(` Created ${NIA_CONFIG_PATH}`);
156
177
  return true;
157
178
  }
179
+ function updateAgentsMd() {
180
+ mkdirSync(OPENCODE_CONFIG_DIR, { recursive: true });
181
+ try {
182
+ if (existsSync(AGENTS_MD_PATH)) {
183
+ const content = readFileSync(AGENTS_MD_PATH, "utf-8");
184
+ if (content.includes("# How to use Nia")) {
185
+ console.log(" Nia instructions already in AGENTS.md");
186
+ return true;
187
+ }
188
+ const newContent = content.trimEnd() + `
189
+
190
+ ` + NIA_AGENTS_INSTRUCTIONS.trim() + `
191
+ `;
192
+ writeFileSync(AGENTS_MD_PATH, newContent);
193
+ console.log(" Appended Nia instructions to AGENTS.md");
194
+ } else {
195
+ writeFileSync(AGENTS_MD_PATH, NIA_AGENTS_INSTRUCTIONS.trim() + `
196
+ `);
197
+ console.log(` Created ${AGENTS_MD_PATH} with Nia instructions`);
198
+ }
199
+ return true;
200
+ } catch (err) {
201
+ console.error(" Failed to update AGENTS.md:", err);
202
+ return false;
203
+ }
204
+ }
158
205
  async function install(options) {
159
206
  console.log(`
160
207
  Nia OpenCode Plugin Installer
@@ -216,6 +263,18 @@ Step 3: Configure OpenCode`);
216
263
  }
217
264
  }
218
265
  console.log(`
266
+ Step 4: Add Nia Instructions to AGENTS.md`);
267
+ if (options.tui && rl) {
268
+ const shouldUpdate = await confirm(rl, "Add Nia usage instructions to ~/.config/opencode/AGENTS.md?");
269
+ if (shouldUpdate) {
270
+ updateAgentsMd();
271
+ } else {
272
+ console.log(" Skipped.");
273
+ }
274
+ } else {
275
+ updateAgentsMd();
276
+ }
277
+ console.log(`
219
278
  ` + "-".repeat(50));
220
279
  console.log(`
221
280
  Setup Complete!
package/dist/index.js CHANGED
@@ -46,7 +46,7 @@ function isConfigured() {
46
46
  // src/keywords.ts
47
47
  var CODE_BLOCK_PATTERN = /```[\s\S]*?```/g;
48
48
  var INLINE_CODE_PATTERN = /`[^`]+`/g;
49
- var DEFAULT_PATTERNS = [
49
+ var RESEARCH_PATTERNS = [
50
50
  /\b(research|look\s*up|find\s*docs?)\b/i,
51
51
  /\b(search\s+for|search\s+codebase|search\s+repo|search\s+docs?)\b/i,
52
52
  /\b(grep\s+for|grep\s+in)\b/i,
@@ -55,6 +55,14 @@ var DEFAULT_PATTERNS = [
55
55
  /\bcheck\s+(the\s+)?(docs?|documentation)\s+(for|about|on)\b/i,
56
56
  /\bfind\s+(examples?|usage)\s+(of|for)\b/i
57
57
  ];
58
+ var SAVE_PATTERNS = [
59
+ /\b(save\s+(this\s+)?(context|conversation|session|chat))\b/i,
60
+ /\b(continue\s+(this\s+)?(later|tomorrow|in\s+\w+))\b/i,
61
+ /\b(pick\s+(this\s+)?up\s+(later|tomorrow|in\s+\w+))\b/i,
62
+ /\b(hand\s*off|switch(ing)?\s+to)\s+(cursor|claude|windsurf|copilot|another\s+agent)\b/i,
63
+ /\b(save\s+for\s+later|bookmark\s+this)\b/i,
64
+ /\b(preserve|store)\s+(this\s+)?(context|conversation|session)\b/i
65
+ ];
58
66
  function removeCodeBlocks(text) {
59
67
  return text.replace(CODE_BLOCK_PATTERN, "").replace(INLINE_CODE_PATTERN, "");
60
68
  }
@@ -67,19 +75,25 @@ function compileCustomPatterns() {
67
75
  }
68
76
  }).filter((p) => p !== null);
69
77
  }
70
- function detectResearchKeyword(text) {
78
+ function detectKeyword(text) {
71
79
  if (!CONFIG.keywords.enabled) {
72
- return { detected: false };
80
+ return { type: null };
73
81
  }
74
82
  const textWithoutCode = removeCodeBlocks(text);
75
- const allPatterns = [...DEFAULT_PATTERNS, ...compileCustomPatterns()];
76
- for (const pattern of allPatterns) {
83
+ for (const pattern of SAVE_PATTERNS) {
84
+ const match = textWithoutCode.match(pattern);
85
+ if (match) {
86
+ return { type: "save", match: match[0] };
87
+ }
88
+ }
89
+ const researchPatterns = [...RESEARCH_PATTERNS, ...compileCustomPatterns()];
90
+ for (const pattern of researchPatterns) {
77
91
  const match = textWithoutCode.match(pattern);
78
92
  if (match) {
79
- return { detected: true, match: match[0] };
93
+ return { type: "research", match: match[0] };
80
94
  }
81
95
  }
82
- return { detected: false };
96
+ return { type: null };
83
97
  }
84
98
  var NIA_NUDGE_MESSAGE = `[NIA KNOWLEDGE TRIGGER]
85
99
  The user is asking for research, documentation, or codebase exploration. You have access to **Nia** tools via MCP.
@@ -99,6 +113,30 @@ The user is asking for research, documentation, or codebase exploration. You hav
99
113
  3. Read specific files if needed for deeper context
100
114
 
101
115
  Use these tools to provide accurate, up-to-date information instead of relying solely on training data.`;
116
+ var NIA_SAVE_NUDGE_MESSAGE = `[NIA CONTEXT SAVE TRIGGER]
117
+ The user wants to save this conversation to continue later or hand off to another agent.
118
+
119
+ **Use \`nia.context\` to save:**
120
+ \`\`\`
121
+ nia.context({
122
+ action: "save",
123
+ title: "Brief title describing this session",
124
+ summary: "What was accomplished and what's pending",
125
+ content: "Key decisions, code snippets, and important context",
126
+ tags: ["relevant", "tags"],
127
+ edited_files: [{ path: "file/path.ts", action: "modified" }]
128
+ })
129
+ \`\`\`
130
+
131
+ **What to include:**
132
+ - Summary of what was discussed/accomplished
133
+ - Key decisions made
134
+ - Code snippets or plans created
135
+ - Files that were edited
136
+ - Next steps or pending tasks
137
+ - Any Nia sources that were referenced
138
+
139
+ This context can be loaded in Cursor, Claude Code, Windsurf, or any agent with Nia access.`;
102
140
 
103
141
  // src/services/logger.ts
104
142
  var DEBUG = process.env.NIA_DEBUG === "true" || process.env.NIA_DEBUG === "1";
@@ -143,20 +181,21 @@ var NiaPlugin = async (ctx) => {
143
181
  messagePreview: userMessage.slice(0, 100),
144
182
  partsCount: output.parts.length
145
183
  });
146
- const { detected, match } = detectResearchKeyword(userMessage);
147
- if (detected) {
148
- log("chat.message: research keyword detected", { match });
184
+ const { type, match } = detectKeyword(userMessage);
185
+ if (type) {
186
+ const nudgeText = type === "save" ? NIA_SAVE_NUDGE_MESSAGE : NIA_NUDGE_MESSAGE;
187
+ log(`chat.message: ${type} keyword detected`, { match });
149
188
  const nudgePart = {
150
- id: `nia-nudge-${Date.now()}`,
189
+ id: `nia-${type}-nudge-${Date.now()}`,
151
190
  sessionID: input.sessionID,
152
191
  messageID: output.message.id,
153
192
  type: "text",
154
- text: NIA_NUDGE_MESSAGE,
193
+ text: nudgeText,
155
194
  synthetic: true
156
195
  };
157
196
  output.parts.push(nudgePart);
158
197
  const duration = Date.now() - start;
159
- log("chat.message: nudge injected", { duration, match });
198
+ log(`chat.message: ${type} nudge injected`, { duration, match });
160
199
  }
161
200
  } catch (error) {
162
201
  log("chat.message: ERROR", { error: String(error) });
@@ -1,5 +1,11 @@
1
+ export type KeywordType = "research" | "save" | null;
2
+ export declare function detectKeyword(text: string): {
3
+ type: KeywordType;
4
+ match?: string;
5
+ };
1
6
  export declare function detectResearchKeyword(text: string): {
2
7
  detected: boolean;
3
8
  match?: string;
4
9
  };
5
10
  export declare const NIA_NUDGE_MESSAGE = "[NIA KNOWLEDGE TRIGGER]\nThe user is asking for research, documentation, or codebase exploration. You have access to **Nia** tools via MCP.\n\n**Available Nia tools:**\n- `nia.search` - Semantic search across indexed repos, docs, and papers\n- `nia.nia_research` - Web search (quick) or deep AI research (deep/oracle modes)\n- `nia.index` - Index new GitHub repos, documentation sites, or arXiv papers\n- `nia.nia_read` - Read specific files from indexed sources\n- `nia.nia_grep` - Regex search across indexed codebases\n- `nia.nia_explore` - Browse file trees of indexed repos/docs\n- `nia.manage_resource` - List/check status of indexed sources\n\n**Workflow:**\n1. Check what's indexed: `nia.manage_resource(action: \"list\")`\n2. Search or research based on the user's question\n3. Read specific files if needed for deeper context\n\nUse these tools to provide accurate, up-to-date information instead of relying solely on training data.";
11
+ export declare const NIA_SAVE_NUDGE_MESSAGE = "[NIA CONTEXT SAVE TRIGGER]\nThe user wants to save this conversation to continue later or hand off to another agent.\n\n**Use `nia.context` to save:**\n```\nnia.context({\n action: \"save\",\n title: \"Brief title describing this session\",\n summary: \"What was accomplished and what's pending\",\n content: \"Key decisions, code snippets, and important context\",\n tags: [\"relevant\", \"tags\"],\n edited_files: [{ path: \"file/path.ts\", action: \"modified\" }]\n})\n```\n\n**What to include:**\n- Summary of what was discussed/accomplished\n- Key decisions made\n- Code snippets or plans created\n- Files that were edited\n- Next steps or pending tasks\n- Any Nia sources that were referenced\n\nThis context can be loaded in Cursor, Claude Code, Windsurf, or any agent with Nia access.";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nia-opencode",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "OpenCode plugin that integrates Nia Knowledge Agent for research and documentation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",