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.
- package/dist/backend/adapters/claude-adapter.js +8 -1
- package/dist/backend/cli/install-vcm-harness.js +27 -22
- package/dist/backend/role-tool-policy.js +60 -0
- package/dist/backend/services/harness-service.js +27 -23
- package/dist/backend/services/lsp-plugin.js +1 -4
- package/dist/backend/templates/harness/architect-agent.js +1 -0
- package/dist/backend/templates/harness/vcm-code-navigation-skill.js +2 -2
- package/package.json +1 -1
- package/scripts/claude-plugins/vcm-lsp-bridge/.claude-plugin/plugin.json +2 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
103
|
-
architect:
|
|
104
|
-
coder:
|
|
105
|
-
reviewer:
|
|
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
|
-
|
|
696
|
-
|
|
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
|
|
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}\
|
|
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
|
|
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
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
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
|
-
|
|
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.", {
|
|
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
|
-
|
|
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.", {
|
|
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
|
-
|
|
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.", {
|
|
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
|
|
1390
|
-
|
|
1391
|
-
if (!frontmatterMatch) {
|
|
1390
|
+
function ensureAgentDisallowedTools(content, requiredTools) {
|
|
1391
|
+
if (!requiredTools) {
|
|
1392
1392
|
return content;
|
|
1393
1393
|
}
|
|
1394
|
-
const
|
|
1395
|
-
if (!
|
|
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
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
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 =
|
|
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
|
|
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}\
|
|
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.
|
|
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,
|
|
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