vibe-coding-master 0.7.40 → 0.7.41

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.
@@ -1,3 +1,4 @@
1
+ import { roleRuntimeDisallowedTools, roleUsesLsp } from "../role-tool-policy.js";
1
2
  import { isCcrSessionModel } from "../../shared/types/session.js";
2
3
  import { VcmError } from "../errors.js";
3
4
  export function createClaudeAdapter(runner) {
@@ -20,7 +21,13 @@ export function createClaudeAdapter(runner) {
20
21
  },
21
22
  buildRoleStartCommand(role, command = "claude", permissionMode = "default", claudeSessionId, resume = false, model = "default", effort = "default", settingsOverride, appendSystemPrompt, pluginDirs = []) {
22
23
  const args = pluginDirs.flatMap((pluginDir) => ["--plugin-dir", pluginDir]);
23
- args.push("--allowedTools", "Glob,Grep");
24
+ const lspEnabled = roleUsesLsp(role) && pluginDirs.length > 0;
25
+ if (lspEnabled) {
26
+ args.push("--disallowedTools", roleRuntimeDisallowedTools(role).join(","));
27
+ }
28
+ else {
29
+ args.push("--allowedTools", "Glob,Grep");
30
+ }
24
31
  args.push("--agent", role);
25
32
  const sessionSettings = { ...settingsOverride };
26
33
  if (claudeSessionId) {
@@ -5,6 +5,7 @@ import path from "node:path";
5
5
  import process from "node:process";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { renderArchitectHarnessRules } from "../templates/harness/architect-agent.js";
8
+ import { CODE_ROLE_DISALLOWED_TOOLS, REVIEWER_DISALLOWED_TOOLS } from "../role-tool-policy.js";
8
9
  import { renderCoderHarnessRules } from "../templates/harness/coder-agent.js";
9
10
  import { renderCoderWorkerHarnessRules } from "../templates/harness/coder-worker-agent.js";
10
11
  import { renderArchitectScaffoldWorkerHarnessRules } from "../templates/harness/architect-scaffold-worker-agent.js";
@@ -67,12 +68,12 @@ const AGENT_FRONTMATTER = {
67
68
  },
68
69
  architect: {
69
70
  description: "VCM architecture role for plans, module boundaries, public contracts, verifiable behavior, and docs sync.",
70
- tools: "Read, Grep, Glob, Bash, Edit, Write, Agent, LSP",
71
+ disallowedTools: CODE_ROLE_DISALLOWED_TOOLS.join(", "),
71
72
  skills: ["vcm-code-navigation"]
72
73
  },
73
74
  coder: {
74
75
  description: "VCM implementation role for scoped code changes and focused tests.",
75
- tools: "Read, Grep, Glob, Bash, Edit, Write, Agent, LSP",
76
+ disallowedTools: CODE_ROLE_DISALLOWED_TOOLS.join(", "),
76
77
  skills: ["vcm-code-navigation"]
77
78
  },
78
79
  tester: {
@@ -80,7 +81,7 @@ const AGENT_FRONTMATTER = {
80
81
  },
81
82
  reviewer: {
82
83
  description: "VCM independent gate review role for architecture plans, validation adequacy, and code diffs.",
83
- tools: "Read, Grep, Glob, Bash, Write, LSP",
84
+ disallowedTools: REVIEWER_DISALLOWED_TOOLS.join(", "),
84
85
  skills: ["vcm-code-navigation"]
85
86
  },
86
87
  translator: {
@@ -99,10 +100,10 @@ const AGENT_FRONTMATTER = {
99
100
  effort: "xhigh"
100
101
  }
101
102
  };
102
- const REQUIRED_AGENT_TOOLS = {
103
- architect: ["Grep", "Agent", "LSP"],
104
- coder: ["Grep", "Agent", "LSP"],
105
- reviewer: ["Grep", "LSP"]
103
+ const REQUIRED_AGENT_DISALLOWED_TOOLS = {
104
+ architect: CODE_ROLE_DISALLOWED_TOOLS,
105
+ coder: CODE_ROLE_DISALLOWED_TOOLS,
106
+ reviewer: REVIEWER_DISALLOWED_TOOLS
106
107
  };
107
108
  const REQUIRED_AGENT_SKILLS = {
108
109
  architect: ["vcm-code-navigation"],
@@ -692,8 +693,9 @@ async function installManagedFile({ projectRoot, definition, dryRun, operations
692
693
  if (definition.memoryBlock) {
693
694
  nextContent = ensureVcmMemoryBlock(nextContent);
694
695
  }
695
- for (const requiredTool of REQUIRED_AGENT_TOOLS[definition.agentName] ?? []) {
696
- nextContent = ensureAgentTool(nextContent, requiredTool);
696
+ const requiredDisallowedTools = REQUIRED_AGENT_DISALLOWED_TOOLS[definition.agentName];
697
+ if (requiredDisallowedTools) {
698
+ nextContent = ensureAgentDisallowedTools(nextContent, requiredDisallowedTools);
697
699
  }
698
700
  for (const requiredSkill of REQUIRED_AGENT_SKILLS[definition.agentName] ?? []) {
699
701
  nextContent = ensureAgentSkill(nextContent, requiredSkill);
@@ -737,31 +739,34 @@ function renderNewManagedFile(definition, block) {
737
739
  const suffix = definition.contentAfterBlock?.trim();
738
740
  if (definition.agentName) {
739
741
  const frontmatter = AGENT_FRONTMATTER[definition.agentName];
740
- const tools = frontmatter.tools ?? "Read, Grep, Glob, Bash, Edit, Write";
742
+ const toolPolicy = frontmatter.disallowedTools
743
+ ? `disallowedTools: ${frontmatter.disallowedTools}`
744
+ : `tools: ${frontmatter.tools ?? "Read, Grep, Glob, Bash, Edit, Write"}`;
741
745
  const model = frontmatter.model ? `\nmodel: ${frontmatter.model}` : "";
742
746
  const effort = frontmatter.effort ? `\neffort: ${frontmatter.effort}` : "";
743
747
  const skills = frontmatter.skills?.length
744
748
  ? `\nskills:\n${frontmatter.skills.map((skill) => ` - ${skill}`).join("\n")}`
745
749
  : "";
746
- return `---\nname: ${definition.agentName}\ndescription: ${frontmatter.description}\ntools: ${tools}${model}${effort}${skills}\n---\n\n# ${definition.title}\n\n${block}${suffix ? `\n\n${suffix}` : ""}\n`;
750
+ return `---\nname: ${definition.agentName}\ndescription: ${frontmatter.description}\n${toolPolicy}${model}${effort}${skills}\n---\n\n# ${definition.title}\n\n${block}${suffix ? `\n\n${suffix}` : ""}\n`;
747
751
  }
748
752
  return `# ${definition.title}\n\n${block}${suffix ? `\n\n${suffix}` : ""}\n`;
749
753
  }
750
- function ensureAgentTool(content, requiredTool) {
754
+ function ensureAgentDisallowedTools(content, requiredTools) {
751
755
  const frontmatterMatch = content.match(/^---\r?\n[\s\S]*?\r?\n---/);
752
756
  if (!frontmatterMatch) {
753
757
  return content;
754
758
  }
755
- const toolsMatch = frontmatterMatch[0].match(/^tools:\s*(.*)$/m);
756
- if (!toolsMatch) {
757
- return content.replace(/^(---\r?\n[\s\S]*?)(\r?\n---)/, `$1\ntools: ${requiredTool}$2`);
758
- }
759
- const tools = toolsMatch[1].split(",").map((tool) => tool.trim()).filter(Boolean);
760
- if (tools.includes(requiredTool)) {
761
- return content;
762
- }
763
- const nextTools = [...tools, requiredTool].join(", ");
764
- return content.replace(frontmatterMatch[0], frontmatterMatch[0].replace(toolsMatch[0], `tools: ${nextTools}`));
759
+ const withoutAllowedTools = frontmatterMatch[0].replace(/^tools:\s*.*\r?\n?/m, "");
760
+ const disallowedMatch = withoutAllowedTools.match(/^disallowedTools:\s*(.*)$/m);
761
+ const existing = disallowedMatch?.[1]
762
+ .split(",")
763
+ .map((tool) => tool.trim())
764
+ .filter(Boolean) ?? [];
765
+ const disallowedTools = [...new Set([...existing, ...requiredTools])].join(", ");
766
+ const nextFrontmatter = disallowedMatch
767
+ ? withoutAllowedTools.replace(disallowedMatch[0], `disallowedTools: ${disallowedTools}`)
768
+ : withoutAllowedTools.replace(/\r?\n---$/, `\ndisallowedTools: ${disallowedTools}\n---`);
769
+ return content.replace(frontmatterMatch[0], nextFrontmatter);
765
770
  }
766
771
  function ensureAgentSkill(content, requiredSkill) {
767
772
  const frontmatterMatch = content.match(/^---\r?\n[\s\S]*?\r?\n---/);
@@ -0,0 +1,60 @@
1
+ const LSP_FRONTMATTER_DISALLOWED_TOOLS = [
2
+ "NotebookEdit",
3
+ "WebFetch",
4
+ "WebSearch"
5
+ ];
6
+ const NON_VCM_ROLE_RUNTIME_TOOLS = [
7
+ "AskUserQuestion",
8
+ "CronCreate",
9
+ "CronDelete",
10
+ "CronList",
11
+ "DesignSync",
12
+ "EnterPlanMode",
13
+ "EnterWorktree",
14
+ "ExitPlanMode",
15
+ "ExitWorktree",
16
+ "KillShell",
17
+ "Monitor",
18
+ "NotebookEdit",
19
+ "PushNotification",
20
+ "RemoteTrigger",
21
+ "ReportFindings",
22
+ "ScheduleWakeup",
23
+ "SendMessage",
24
+ "Skill",
25
+ "TaskCreate",
26
+ "TaskGet",
27
+ "TaskList",
28
+ "TaskOutput",
29
+ "TaskStop",
30
+ "TaskUpdate",
31
+ "TodoWrite",
32
+ "WebFetch",
33
+ "WebSearch",
34
+ "Workflow"
35
+ ];
36
+ export const CODE_ROLE_DISALLOWED_TOOLS = [...LSP_FRONTMATTER_DISALLOWED_TOOLS];
37
+ export const REVIEWER_DISALLOWED_TOOLS = [
38
+ "Agent",
39
+ "Edit",
40
+ ...LSP_FRONTMATTER_DISALLOWED_TOOLS
41
+ ];
42
+ export const CODE_ROLE_RUNTIME_DISALLOWED_TOOLS = [...NON_VCM_ROLE_RUNTIME_TOOLS];
43
+ export const REVIEWER_RUNTIME_DISALLOWED_TOOLS = [
44
+ "Agent",
45
+ "Edit",
46
+ ...NON_VCM_ROLE_RUNTIME_TOOLS
47
+ ];
48
+ const LSP_ROLE_NAMES = new Set(["architect", "coder", "reviewer"]);
49
+ export function roleUsesLsp(role) {
50
+ return LSP_ROLE_NAMES.has(role);
51
+ }
52
+ export function roleRuntimeDisallowedTools(role) {
53
+ if (role === "reviewer") {
54
+ return REVIEWER_RUNTIME_DISALLOWED_TOOLS;
55
+ }
56
+ if (role === "architect" || role === "coder") {
57
+ return CODE_ROLE_RUNTIME_DISALLOWED_TOOLS;
58
+ }
59
+ return [];
60
+ }
@@ -2,6 +2,7 @@ import { execFile } from "node:child_process";
2
2
  import path from "node:path";
3
3
  import { promisify } from "node:util";
4
4
  import { renderArchitectHarnessRules } from "../templates/harness/architect-agent.js";
5
+ import { CODE_ROLE_DISALLOWED_TOOLS, REVIEWER_DISALLOWED_TOOLS } from "../role-tool-policy.js";
5
6
  import { renderCoderHarnessRules } from "../templates/harness/coder-agent.js";
6
7
  import { renderCoderWorkerHarnessRules } from "../templates/harness/coder-worker-agent.js";
7
8
  import { renderArchitectScaffoldWorkerHarnessRules } from "../templates/harness/architect-scaffold-worker-agent.js";
@@ -207,9 +208,9 @@ const HARNESS_FILES = [
207
208
  path: ".claude/agents/reviewer.md",
208
209
  title: "Reviewer Agent",
209
210
  memoryBlock: true,
210
- requiredTools: ["Grep", "LSP"],
211
+ requiredDisallowedTools: REVIEWER_DISALLOWED_TOOLS,
211
212
  requiredSkills: ["vcm-code-navigation"],
212
- frontmatter: renderAgentFrontmatter("reviewer", "VCM independent gate review role for architecture plans, validation adequacy, and code diffs.", { tools: "Read, Grep, Glob, Bash, Write, LSP", skills: ["vcm-code-navigation"] }),
213
+ frontmatter: renderAgentFrontmatter("reviewer", "VCM independent gate review role for architecture plans, validation adequacy, and code diffs.", { disallowedTools: REVIEWER_DISALLOWED_TOOLS.join(", "), skills: ["vcm-code-navigation"] }),
213
214
  renderRules: renderReviewerAgentRules
214
215
  },
215
216
  {
@@ -282,10 +283,10 @@ const HARNESS_FILES = [
282
283
  path: ".claude/agents/architect.md",
283
284
  title: "Architect Agent",
284
285
  memoryBlock: true,
285
- requiredTools: ["Grep", "Agent", "LSP"],
286
+ requiredDisallowedTools: CODE_ROLE_DISALLOWED_TOOLS,
286
287
  requiredSkills: ["vcm-code-navigation"],
287
288
  blankLineBeforeEnd: true,
288
- frontmatter: renderAgentFrontmatter("architect", "VCM architecture role for plans, module boundaries, public contracts, verifiable behavior, and docs sync.", { tools: "Read, Grep, Glob, Bash, Edit, Write, Agent, LSP", skills: ["vcm-code-navigation"] }),
289
+ frontmatter: renderAgentFrontmatter("architect", "VCM architecture role for plans, module boundaries, public contracts, verifiable behavior, and docs sync.", { disallowedTools: CODE_ROLE_DISALLOWED_TOOLS.join(", "), skills: ["vcm-code-navigation"] }),
289
290
  renderRules: renderArchitectHarnessRules
290
291
  },
291
292
  {
@@ -293,9 +294,9 @@ const HARNESS_FILES = [
293
294
  path: ".claude/agents/coder.md",
294
295
  title: "Coder Agent",
295
296
  memoryBlock: true,
296
- requiredTools: ["Grep", "Agent", "LSP"],
297
+ requiredDisallowedTools: CODE_ROLE_DISALLOWED_TOOLS,
297
298
  requiredSkills: ["vcm-code-navigation"],
298
- frontmatter: renderAgentFrontmatter("coder", "VCM implementation role for scoped code changes and focused tests.", { tools: "Read, Grep, Glob, Bash, Edit, Write, Agent, LSP", skills: ["vcm-code-navigation"] }),
299
+ frontmatter: renderAgentFrontmatter("coder", "VCM implementation role for scoped code changes and focused tests.", { disallowedTools: CODE_ROLE_DISALLOWED_TOOLS.join(", "), skills: ["vcm-code-navigation"] }),
299
300
  renderRules: renderCoderHarnessRules
300
301
  },
301
302
  {
@@ -1386,27 +1387,28 @@ function renderNewHarnessFile(definition, block, contentAfterBlock = definition.
1386
1387
  const suffix = contentAfterBlock?.trim();
1387
1388
  return `${frontmatter}# ${definition.title}\n\n${block}${suffix ? `\n\n${suffix}` : ""}\n`;
1388
1389
  }
1389
- function ensureAgentTool(content, requiredTool) {
1390
- const frontmatterMatch = content.match(/^---\r?\n[\s\S]*?\r?\n---/);
1391
- if (!frontmatterMatch) {
1390
+ function ensureAgentDisallowedTools(content, requiredTools) {
1391
+ if (!requiredTools) {
1392
1392
  return content;
1393
1393
  }
1394
- const toolsMatch = frontmatterMatch[0].match(/^tools:\s*(.*)$/m);
1395
- if (!toolsMatch) {
1396
- return content.replace(/^(---\r?\n[\s\S]*?)(\r?\n---)/, `$1\ntools: ${requiredTool}$2`);
1397
- }
1398
- const tools = toolsMatch[1].split(",").map((tool) => tool.trim()).filter(Boolean);
1399
- if (tools.includes(requiredTool)) {
1394
+ const frontmatterMatch = content.match(/^---\r?\n[\s\S]*?\r?\n---/);
1395
+ if (!frontmatterMatch) {
1400
1396
  return content;
1401
1397
  }
1402
- const nextTools = [...tools, requiredTool].join(", ");
1403
- return content.replace(frontmatterMatch[0], frontmatterMatch[0].replace(toolsMatch[0], `tools: ${nextTools}`));
1404
- }
1405
- function ensureAgentTools(content, requiredTools) {
1406
- return (requiredTools ?? []).reduce(ensureAgentTool, content);
1398
+ const withoutAllowedTools = frontmatterMatch[0].replace(/^tools:\s*.*\r?\n?/m, "");
1399
+ const disallowedMatch = withoutAllowedTools.match(/^disallowedTools:\s*(.*)$/m);
1400
+ const existing = disallowedMatch?.[1]
1401
+ .split(",")
1402
+ .map((tool) => tool.trim())
1403
+ .filter(Boolean) ?? [];
1404
+ const disallowedTools = [...new Set([...existing, ...requiredTools])].join(", ");
1405
+ const nextFrontmatter = disallowedMatch
1406
+ ? withoutAllowedTools.replace(disallowedMatch[0], `disallowedTools: ${disallowedTools}`)
1407
+ : withoutAllowedTools.replace(/\r?\n---$/, `\ndisallowedTools: ${disallowedTools}\n---`);
1408
+ return content.replace(frontmatterMatch[0], nextFrontmatter);
1407
1409
  }
1408
1410
  function normalizeAgentFrontmatter(content, definition) {
1409
- const toolsUpdated = ensureAgentTools(content, definition.requiredTools);
1411
+ const toolsUpdated = ensureAgentDisallowedTools(content, definition.requiredDisallowedTools);
1410
1412
  return (definition.requiredSkills ?? []).reduce(ensureAgentSkill, toolsUpdated);
1411
1413
  }
1412
1414
  function ensureAgentSkill(content, requiredSkill) {
@@ -1558,13 +1560,15 @@ function isPlainObject(value) {
1558
1560
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1559
1561
  }
1560
1562
  function renderAgentFrontmatter(name, description, options = {}) {
1561
- const tools = options.tools ?? "Read, Grep, Glob, Bash, Edit, Write";
1563
+ const toolPolicy = options.disallowedTools
1564
+ ? `disallowedTools: ${options.disallowedTools}`
1565
+ : `tools: ${options.tools ?? "Read, Grep, Glob, Bash, Edit, Write"}`;
1562
1566
  const model = options.model ? `\nmodel: ${options.model}` : "";
1563
1567
  const effort = options.effort ? `\neffort: ${options.effort}` : "";
1564
1568
  const skills = options.skills?.length
1565
1569
  ? `\nskills:\n${options.skills.map((skill) => ` - ${skill}`).join("\n")}`
1566
1570
  : "";
1567
- return `---\nname: ${name}\ndescription: ${description}\ntools: ${tools}${model}${effort}${skills}\n---`;
1571
+ return `---\nname: ${name}\ndescription: ${description}\n${toolPolicy}${model}${effort}${skills}\n---`;
1568
1572
  }
1569
1573
  function renderSkillFrontmatter(name, description) {
1570
1574
  return `---\nname: ${name}\ndescription: ${description}\n---`;
@@ -1,9 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
+ export { roleUsesLsp } from "../role-tool-policy.js";
3
4
  export const VCM_LSP_PLUGIN_NAME = "vcm-lsp-bridge";
4
5
  export const VCM_LSP_PLUGIN_DIR = fileURLToPath(new URL("../../../scripts/claude-plugins/vcm-lsp-bridge", import.meta.url));
5
6
  export const VCM_LSP_PLUGIN_MANIFEST = path.join(VCM_LSP_PLUGIN_DIR, ".claude-plugin", "plugin.json");
6
- const LSP_ROLES = new Set(["architect", "coder", "reviewer"]);
7
- export function roleUsesLsp(role) {
8
- return LSP_ROLES.has(role);
9
- }
@@ -23,6 +23,7 @@ ${renderRoleMemoryRules("architect")}
23
23
 
24
24
  - Follow the preloaded \`vcm-code-navigation\` skill whenever work requires code definitions, implementations, references, callers, callees, or behavior paths. This applies in every Architect mode and in direct user communication.
25
25
  - Use LSP for semantic relationships. Use Glob to locate files, Read to inspect complete code, and generated context, architecture documents, or runtime evidence for boundaries LSP does not model.
26
+ - LSP startup or indexing time is not a reason to replace a required semantic query with text matching. Wait for the role-session LSP and follow the skill's bounded retry procedure.
26
27
  - If LSP cannot resolve a required project-owned relationship, record it as unresolved. Do not replace semantic evidence with text matches.
27
28
 
28
29
  ### Work Persistence
@@ -6,9 +6,9 @@ Use this skill when Architect, Coder, or Reviewer must establish symbol definiti
6
6
  ## Navigation Order
7
7
 
8
8
  1. Define the affected feature or module boundary and locate entry symbols with \`.ai/generated/module-index.json\` and \`.ai/generated/public-surface.json\` when available.
9
- 2. Start each navigation run with LSP \`documentSymbol\` on a known affected project source file. This initializes the actual role-session language server and proves that it can parse that file; an executable version probe is not workspace readiness.
9
+ 2. If \`LSP\` is not listed initially, call \`ToolSearch\` with query \`select:LSP\` to load the deferred plugin tool. Then start each navigation run with LSP \`documentSymbol\` on a known affected project source file. This initializes the actual role-session language server and proves that it can parse that file; an executable version probe is not workspace readiness.
10
10
  3. Use LSP workspace or file symbols, definitions, implementations, references, and incoming or outgoing call hierarchy to resolve project-owned relationships.
11
- 4. If an initial workspace-symbol request is empty or reports indexing, do not conclude that the symbol is absent. After a successful file-symbol request, retry the same bounded workspace query at most two more times. If it still cannot resolve, record the operation and result as unresolved.
11
+ 4. If an initial workspace-symbol request is empty or reports indexing, wait and retry; startup or indexing time does not permit replacing a required semantic query with text matching. After a successful file-symbol request, retry the same bounded workspace query at most two more times. If it still cannot resolve, record the operation and result as unresolved.
12
12
  5. Read the complete project-owned callable unit at every resolved location.
13
13
  6. Expand one project-owned dependency hop at a time until the required behavior path has no unresolved symbol.
14
14
  7. Use Glob, generated context, architecture documents, and runtime evidence to locate dynamic registrations, configuration or string edges, macros, documentation, and external boundaries that LSP does not model.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-coding-master",
3
- "version": "0.7.40",
3
+ "version": "0.7.41",
4
4
  "description": "Local GUI session cockpit for Claude Code role sessions.",
5
5
  "type": "module",
6
6
  "files": [
@@ -10,7 +10,8 @@
10
10
  "command": "rust-analyzer",
11
11
  "extensionToLanguage": {
12
12
  ".rs": "rust"
13
- }
13
+ },
14
+ "startupTimeout": 180000
14
15
  },
15
16
  "typescript": {
16
17
  "command": "typescript-language-server",