micode 0.4.0 → 0.5.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/index.js CHANGED
@@ -16,14 +16,12 @@ var brainstormerAgent = {
16
16
  mode: "primary",
17
17
  model: "anthropic/claude-opus-4-5",
18
18
  temperature: 0.7,
19
- tools: { ask: true },
20
19
  prompt: `<purpose>
21
20
  Turn ideas into fully formed designs through natural collaborative dialogue.
22
21
  This is DESIGN ONLY. The planner agent handles detailed implementation plans.
23
22
  </purpose>
24
23
 
25
24
  <critical-rules>
26
- <rule>ASK TOOL: Use the ask tool for EVERY question to the user. Never ask in plain text.</rule>
27
25
  <rule>NO CODE: Never write code. Never provide code examples. Design only.</rule>
28
26
  <rule>SUBAGENTS: Spawn multiple in parallel for codebase analysis.</rule>
29
27
  <rule>TOOLS (grep, read, etc.): Do NOT use directly - use subagents instead.</rule>
@@ -54,8 +52,6 @@ This is DESIGN ONLY. The planner agent handles detailed implementation plans.
54
52
  - codebase-analyzer: "Analyze existing [related feature]"
55
53
  - pattern-finder: "Find patterns for [similar functionality]"
56
54
  </spawn-example>
57
- <rule>Use the ask tool for EVERY question - never plain text</rule>
58
- <rule>Always provide MULTIPLE CHOICE options in the ask tool</rule>
59
55
  <focus>purpose, constraints, success criteria</focus>
60
56
  </phase>
61
57
 
@@ -91,9 +87,7 @@ This is DESIGN ONLY. The planner agent handles detailed implementation plans.
91
87
  <principle name="design-only">NO CODE. Describe components, not implementations. Planner writes code.</principle>
92
88
  <principle name="subagents-first">ALWAYS use subagents for code analysis, NEVER tools directly</principle>
93
89
  <principle name="parallel-spawn">Spawn multiple subagents in a SINGLE message</principle>
94
- <principle name="ask-tool-always">ALWAYS use the ask tool for questions - never plain text</principle>
95
- <principle name="one-question">Ask ONE question at a time via ask tool. Wait for answer.</principle>
96
- <principle name="multiple-choice">Present 3-5 options in ask tool questions</principle>
90
+ <principle name="one-question">Ask ONE question at a time. Wait for answer.</principle>
97
91
  <principle name="yagni">Remove unnecessary features from ALL designs</principle>
98
92
  <principle name="explore-alternatives">ALWAYS propose 2-3 approaches before settling</principle>
99
93
  <principle name="incremental-validation">Present in sections, validate each before proceeding</principle>
@@ -763,14 +757,22 @@ Batch 3 (parallel):
763
757
  Executes ONE task from the plan.
764
758
  Input: Single task with context (which files, what to do).
765
759
  Output: Changes made and verification results for that task.
760
+ Invoke with: Task tool, subagent_type="implementer"
766
761
  </subagent>
767
762
  <subagent name="reviewer" spawn="parallel-per-task">
768
763
  Reviews ONE task's implementation.
769
764
  Input: Single task's changes against its requirements.
770
765
  Output: APPROVED or CHANGES REQUESTED for that task.
766
+ Invoke with: Task tool, subagent_type="reviewer"
771
767
  </subagent>
772
768
  </available-subagents>
773
769
 
770
+ <critical-instruction>
771
+ You MUST use the Task tool to spawn implementer and reviewer subagents.
772
+ Example: Task(description="Implement task 1", prompt="...", subagent_type="implementer")
773
+ Do NOT try to implement or review yourself - delegate to subagents.
774
+ </critical-instruction>
775
+
774
776
  <per-task-cycle>
775
777
  For each task:
776
778
  1. Spawn implementer with task details
@@ -782,18 +784,17 @@ For each task:
782
784
  </per-task-cycle>
783
785
 
784
786
  <parallel-spawning>
785
- Within a batch, spawn ALL implementers in a SINGLE message:
786
-
787
- Example for batch with tasks 1, 2, 3:
788
- - In ONE message, spawn:
789
- - implementer: "Execute task 1: [details]"
790
- - implementer: "Execute task 2: [details]"
791
- - implementer: "Execute task 3: [details]"
792
-
793
- Then after all complete, in ONE message spawn:
794
- - reviewer: "Review task 1 implementation"
795
- - reviewer: "Review task 2 implementation"
796
- - reviewer: "Review task 3 implementation"
787
+ Within a batch, spawn ALL implementers in a SINGLE message using the Task tool:
788
+
789
+ Example for batch with tasks 1, 2, 3 - call Task tool 3 times in ONE message:
790
+ - Task(description="Task 1", prompt="Execute task 1: [details]", subagent_type="implementer")
791
+ - Task(description="Task 2", prompt="Execute task 2: [details]", subagent_type="implementer")
792
+ - Task(description="Task 3", prompt="Execute task 3: [details]", subagent_type="implementer")
793
+
794
+ Then after all complete, in ONE message call Task tool for reviewers:
795
+ - Task(description="Review 1", prompt="Review task 1 implementation", subagent_type="reviewer")
796
+ - Task(description="Review 2", prompt="Review task 2 implementation", subagent_type="reviewer")
797
+ - Task(description="Review 3", prompt="Review task 3 implementation", subagent_type="reviewer")
797
798
  </parallel-spawning>
798
799
 
799
800
  <rules>
@@ -858,10 +859,6 @@ If you want exception to ANY rule, STOP and get explicit permission first.
858
859
  Breaking the letter or spirit of the rules is failure.
859
860
  </rule>
860
861
 
861
- <rule priority="critical">
862
- ALWAYS use the ask tool when you need user input. Never ask questions in plain text.
863
- </rule>
864
-
865
862
  <values>
866
863
  <value>Honesty. If you lie, you'll be replaced.</value>
867
864
  <value>Do it right, not fast. Never skip steps or take shortcuts.</value>
@@ -877,8 +874,6 @@ ALWAYS use the ask tool when you need user input. Never ask questions in plain t
877
874
  <rule>If uncomfortable pushing back, say "Strange things are afoot at the Circle K"</rule>
878
875
  <rule>STOP and ask for clarification rather than making assumptions</rule>
879
876
  <rule>STOP and ask for help when human input would be valuable</rule>
880
- <rule>ALWAYS use the ask tool when asking questions - never plain text</rule>
881
- <rule>Provide multiple-choice options in the ask tool whenever possible</rule>
882
877
  </relationship>
883
878
 
884
879
  <proactiveness>
@@ -960,8 +955,7 @@ var primaryAgent = {
960
955
  budgetTokens: 32000
961
956
  },
962
957
  maxTokens: 64000,
963
- prompt: PROMPT,
964
- tools: { ask: true }
958
+ prompt: PROMPT
965
959
  };
966
960
  var PRIMARY_AGENT_NAME = process.env.OPENCODE_AGENT_NAME || "commander";
967
961
 
@@ -1032,17 +1026,25 @@ var PROMPT2 = `
1032
1026
  <subagent name="codebase-locator" spawn="multiple">
1033
1027
  Fast file/pattern finder. Spawn multiple with different queries.
1034
1028
  Examples: "Find all entry points", "Find all config files", "Find test directories"
1029
+ Invoke with: Task tool, subagent_type="codebase-locator"
1035
1030
  </subagent>
1036
1031
  <subagent name="codebase-analyzer" spawn="multiple">
1037
1032
  Deep module analyzer. Spawn multiple for different areas.
1038
1033
  Examples: "Analyze src/core", "Analyze api layer", "Analyze database module"
1034
+ Invoke with: Task tool, subagent_type="codebase-analyzer"
1039
1035
  </subagent>
1040
1036
  <subagent name="pattern-finder" spawn="multiple">
1041
1037
  Pattern extractor. Spawn for different pattern types.
1042
1038
  Examples: "Find naming patterns", "Find error handling patterns", "Find async patterns"
1039
+ Invoke with: Task tool, subagent_type="pattern-finder"
1043
1040
  </subagent>
1044
1041
  </available-subagents>
1045
1042
 
1043
+ <critical-instruction>
1044
+ You MUST use the Task tool to spawn subagents. Call multiple Task tools in a SINGLE message for parallelism.
1045
+ Example: Task(description="Find entry points", prompt="Find all entry points and main files", subagent_type="codebase-locator")
1046
+ </critical-instruction>
1047
+
1046
1048
  <language-detection>
1047
1049
  <rule>Identify language(s) by examining file extensions and config files</rule>
1048
1050
  <markers>
@@ -1136,22 +1138,19 @@ var PROMPT2 = `
1136
1138
 
1137
1139
  <execution-example>
1138
1140
  <step description="Start with maximum parallelism">
1139
- In a SINGLE message, spawn:
1140
- - codebase-locator: "Find all entry points and main files"
1141
- - codebase-locator: "Find all config files (linters, formatters, build)"
1142
- - codebase-locator: "Find test directories and test files"
1143
- - codebase-analyzer: "Analyze the directory structure and organization"
1144
- - pattern-finder: "Find naming conventions used across the codebase"
1145
-
1146
- AND run tools:
1141
+ In a SINGLE message, call Task tool multiple times AND run other tools:
1142
+ - Task(description="Find entry points", prompt="Find all entry points and main files", subagent_type="codebase-locator")
1143
+ - Task(description="Find configs", prompt="Find all config files (linters, formatters, build)", subagent_type="codebase-locator")
1144
+ - Task(description="Find tests", prompt="Find test directories and test files", subagent_type="codebase-locator")
1145
+ - Task(description="Analyze structure", prompt="Analyze the directory structure and organization", subagent_type="codebase-analyzer")
1146
+ - Task(description="Find patterns", prompt="Find naming conventions used across the codebase", subagent_type="pattern-finder")
1147
1147
  - Glob: package.json, pyproject.toml, go.mod, Cargo.toml, etc.
1148
1148
  - Glob: README*, ARCHITECTURE*, docs/*
1149
- - Bash: ls -la (root directory)
1150
1149
  </step>
1151
1150
 
1152
1151
  <step description="Parallel deep analysis">
1153
- Based on discovery, in a SINGLE message spawn:
1154
- - codebase-analyzer for each major module found
1152
+ Based on discovery, in a SINGLE message:
1153
+ - Task for each major module: subagent_type="codebase-analyzer"
1155
1154
  - Read multiple source files simultaneously
1156
1155
  - Read multiple test files simultaneously
1157
1156
  </step>
@@ -13826,6 +13825,69 @@ ${output}`;
13826
13825
  }
13827
13826
  });
13828
13827
 
13828
+ // src/tools/btca/index.ts
13829
+ var {spawn: spawn2, which: which2 } = globalThis.Bun;
13830
+ async function checkBtcaAvailable() {
13831
+ const btcaPath = which2("btca");
13832
+ if (btcaPath) {
13833
+ return { available: true };
13834
+ }
13835
+ return {
13836
+ available: false,
13837
+ message: `btca CLI not found. Library source code search will not work.
13838
+ ` + `Install from: https://github.com/anthropics/btca
13839
+ ` + " cargo install btca"
13840
+ };
13841
+ }
13842
+ var BTCA_TIMEOUT_MS = 120000;
13843
+ async function runBtca(args) {
13844
+ try {
13845
+ const proc = spawn2(["btca", ...args], {
13846
+ stdout: "pipe",
13847
+ stderr: "pipe"
13848
+ });
13849
+ const timeoutPromise = new Promise((_, reject) => {
13850
+ setTimeout(() => {
13851
+ proc.kill();
13852
+ reject(new Error("btca command timed out after 2 minutes"));
13853
+ }, BTCA_TIMEOUT_MS);
13854
+ });
13855
+ const [stdout, stderr, exitCode] = await Promise.race([
13856
+ Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text(), proc.exited]),
13857
+ timeoutPromise
13858
+ ]);
13859
+ if (exitCode !== 0) {
13860
+ const errorMsg = stderr.trim() || `Exit code ${exitCode}`;
13861
+ return { output: "", error: errorMsg };
13862
+ }
13863
+ return { output: stdout.trim() };
13864
+ } catch (e) {
13865
+ const err = e;
13866
+ if (err.message?.includes("ENOENT")) {
13867
+ return {
13868
+ output: "",
13869
+ error: `btca CLI not found. Install from: https://github.com/anthropics/btca
13870
+ ` + " cargo install btca"
13871
+ };
13872
+ }
13873
+ return { output: "", error: err.message };
13874
+ }
13875
+ }
13876
+ var btca_ask = tool({
13877
+ description: "Ask questions about library/framework source code using btca. " + "Clones repos locally and searches source code to answer questions. " + "Use for understanding library internals, finding implementation details, or debugging.",
13878
+ args: {
13879
+ tech: tool.schema.string().describe("Resource name configured in btca (e.g., 'react', 'express')"),
13880
+ question: tool.schema.string().describe("Question to ask about the library source code")
13881
+ },
13882
+ execute: async (args) => {
13883
+ const result = await runBtca(["ask", "-t", args.tech, "-q", args.question]);
13884
+ if (result.error) {
13885
+ return `Error: ${result.error}`;
13886
+ }
13887
+ return result.output || "No answer found";
13888
+ }
13889
+ });
13890
+
13829
13891
  // src/tools/look-at.ts
13830
13892
  import { readFileSync, statSync } from "fs";
13831
13893
  import { extname, basename } from "path";
@@ -14850,20 +14912,22 @@ function createTokenAwareTruncationHook(ctx) {
14850
14912
  };
14851
14913
  }
14852
14914
 
14853
- // src/hooks/context-window-monitor.ts
14854
- var WARNING_THRESHOLD = 0.7;
14855
- var CRITICAL_THRESHOLD = 0.85;
14856
- var DEFAULT_CONTEXT_LIMIT2 = 200000;
14915
+ // src/utils/model-limits.ts
14857
14916
  var MODEL_CONTEXT_LIMITS = {
14858
14917
  "claude-opus": 200000,
14859
14918
  "claude-sonnet": 200000,
14860
14919
  "claude-haiku": 200000,
14920
+ "claude-3": 200000,
14921
+ "claude-4": 200000,
14922
+ "gpt-4o": 128000,
14923
+ "gpt-4-turbo": 128000,
14861
14924
  "gpt-4": 128000,
14862
14925
  "gpt-5": 200000,
14863
14926
  o1: 200000,
14864
14927
  o3: 200000,
14865
14928
  gemini: 1e6
14866
14929
  };
14930
+ var DEFAULT_CONTEXT_LIMIT2 = 200000;
14867
14931
  function getContextLimit(modelID) {
14868
14932
  const modelLower = modelID.toLowerCase();
14869
14933
  for (const [pattern, limit] of Object.entries(MODEL_CONTEXT_LIMITS)) {
@@ -14873,6 +14937,10 @@ function getContextLimit(modelID) {
14873
14937
  }
14874
14938
  return DEFAULT_CONTEXT_LIMIT2;
14875
14939
  }
14940
+
14941
+ // src/hooks/context-window-monitor.ts
14942
+ var WARNING_THRESHOLD = 0.7;
14943
+ var CRITICAL_THRESHOLD = 0.85;
14876
14944
  var WARNING_COOLDOWN_MS = 120000;
14877
14945
  function createContextWindowMonitorHook(ctx) {
14878
14946
  const state = {
@@ -15151,33 +15219,9 @@ function createFileOpsTrackerHook(_ctx) {
15151
15219
  }
15152
15220
 
15153
15221
  // src/hooks/auto-clear-ledger.ts
15154
- var MODEL_CONTEXT_LIMITS2 = {
15155
- "claude-opus": 200000,
15156
- "claude-sonnet": 200000,
15157
- "claude-haiku": 200000,
15158
- "claude-3": 200000,
15159
- "claude-4": 200000,
15160
- "gpt-4o": 128000,
15161
- "gpt-4-turbo": 128000,
15162
- "gpt-4": 128000,
15163
- "gpt-5": 200000,
15164
- o1: 200000,
15165
- o3: 200000,
15166
- gemini: 1e6
15167
- };
15168
- var DEFAULT_CONTEXT_LIMIT3 = 200000;
15169
15222
  var DEFAULT_THRESHOLD = 0.8;
15170
15223
  var MIN_TOKENS_FOR_CLEAR = 50000;
15171
15224
  var CLEAR_COOLDOWN_MS = 60000;
15172
- function getContextLimit2(modelID) {
15173
- const modelLower = modelID.toLowerCase();
15174
- for (const [pattern, limit] of Object.entries(MODEL_CONTEXT_LIMITS2)) {
15175
- if (modelLower.includes(pattern)) {
15176
- return limit;
15177
- }
15178
- }
15179
- return DEFAULT_CONTEXT_LIMIT3;
15180
- }
15181
15225
  function createAutoClearLedgerHook(ctx) {
15182
15226
  const state = {
15183
15227
  lastClearTime: new Map,
@@ -15212,7 +15256,7 @@ function createAutoClearLedgerHook(ctx) {
15212
15256
  if (totalUsed < MIN_TOKENS_FOR_CLEAR)
15213
15257
  return;
15214
15258
  const model = modelID || info?.modelID || "";
15215
- const contextLimit = getContextLimit2(model);
15259
+ const contextLimit = getContextLimit(model);
15216
15260
  const usageRatio = totalUsed / contextLimit;
15217
15261
  if (usageRatio < DEFAULT_THRESHOLD)
15218
15262
  return;
@@ -15911,6 +15955,10 @@ var OpenCodeConfigPlugin = async (ctx) => {
15911
15955
  if (!astGrepStatus.available) {
15912
15956
  console.warn(`[micode] ${astGrepStatus.message}`);
15913
15957
  }
15958
+ const btcaStatus = await checkBtcaAvailable();
15959
+ if (!btcaStatus.available) {
15960
+ console.warn(`[micode] ${btcaStatus.message}`);
15961
+ }
15914
15962
  const userConfig = await loadMicodeConfig();
15915
15963
  if (userConfig?.agents) {
15916
15964
  console.log(`[micode] Loaded model overrides for: ${Object.keys(userConfig.agents).join(", ")}`);
@@ -15932,6 +15980,7 @@ var OpenCodeConfigPlugin = async (ctx) => {
15932
15980
  tool: {
15933
15981
  ast_grep_search,
15934
15982
  ast_grep_replace,
15983
+ btca_ask,
15935
15984
  look_at,
15936
15985
  artifact_search,
15937
15986
  ...backgroundTaskTools
@@ -15947,11 +15996,13 @@ var OpenCodeConfigPlugin = async (ctx) => {
15947
15996
  };
15948
15997
  const mergedAgents = mergeAgentConfigs(agents, userConfig);
15949
15998
  config2.agent = {
15950
- [PRIMARY_AGENT_NAME]: mergedAgents[PRIMARY_AGENT_NAME],
15951
- ...Object.fromEntries(Object.entries(mergedAgents).filter(([k]) => k !== PRIMARY_AGENT_NAME)),
15952
15999
  ...config2.agent,
15953
16000
  build: { ...config2.agent?.build, mode: "subagent" },
15954
- plan: { ...config2.agent?.plan, mode: "subagent" }
16001
+ plan: { ...config2.agent?.plan, mode: "subagent" },
16002
+ triage: { ...config2.agent?.triage, mode: "subagent" },
16003
+ docs: { ...config2.agent?.docs, mode: "subagent" },
16004
+ ...Object.fromEntries(Object.entries(mergedAgents).filter(([k]) => k !== PRIMARY_AGENT_NAME)),
16005
+ [PRIMARY_AGENT_NAME]: mergedAgents[PRIMARY_AGENT_NAME]
15955
16006
  };
15956
16007
  config2.mcp = {
15957
16008
  ...config2.mcp,
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Check if btca CLI is available on the system.
3
+ * Returns installation instructions if not found.
4
+ */
5
+ export declare function checkBtcaAvailable(): Promise<{
6
+ available: boolean;
7
+ message?: string;
8
+ }>;
9
+ export declare const btca_ask: {
10
+ description: string;
11
+ args: {
12
+ tech: import("zod").ZodString;
13
+ question: import("zod").ZodString;
14
+ };
15
+ execute(args: {
16
+ tech: string;
17
+ question: string;
18
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
19
+ };
@@ -0,0 +1,7 @@
1
+ export declare const MODEL_CONTEXT_LIMITS: Record<string, number>;
2
+ export declare const DEFAULT_CONTEXT_LIMIT = 200000;
3
+ /**
4
+ * Get the context window limit for a given model ID.
5
+ * Matches against known patterns and falls back to default.
6
+ */
7
+ export declare function getContextLimit(modelID: string): number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micode",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "OpenCode plugin with Brainstorm-Research-Plan-Implement workflow",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -44,7 +44,7 @@
44
44
  "url": "https://github.com/vtemian/micode/issues"
45
45
  },
46
46
  "dependencies": {
47
- "@opencode-ai/plugin": "1.0.207"
47
+ "@opencode-ai/plugin": "^1.0.219"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@biomejs/biome": "^2.3.10",