norn-cli 2.2.2 → 2.4.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.
Files changed (113) hide show
  1. package/.claude/settings.local.json +18 -0
  2. package/.claude/skills/norn-social-campaign/SKILL.md +70 -0
  3. package/CHANGELOG.md +22 -1
  4. package/LICENSE +20 -29
  5. package/README.md +32 -1
  6. package/demos/nornenv-region-refactor/README.md +64 -0
  7. package/demos/nornenv-showcase/README.md +62 -0
  8. package/demos/nornenv-showcase/norn.config.json +16 -0
  9. package/demos/nornenv-showcase/showcase.norn +70 -0
  10. package/demos/nornenv-showcase/showcase.nornapi +26 -0
  11. package/demos/nornenv-showcase/showcase.nornsql +20 -0
  12. package/dist/cli.js +564 -54
  13. package/out/apiResponseIntellisenseCache.js +394 -0
  14. package/out/assertionRunner.js +567 -0
  15. package/out/cacheDir.js +136 -0
  16. package/out/chatParticipant.js +763 -0
  17. package/out/cli/colors.js +127 -0
  18. package/out/cli/formatters/assertion.js +102 -0
  19. package/out/cli/formatters/index.js +23 -0
  20. package/out/cli/formatters/response.js +106 -0
  21. package/out/cli/formatters/summary.js +246 -0
  22. package/out/cli/redaction.js +237 -0
  23. package/out/cli/reporters/html.js +689 -0
  24. package/out/cli/reporters/index.js +22 -0
  25. package/out/cli/reporters/junit.js +226 -0
  26. package/out/codeLensProvider.js +351 -0
  27. package/out/compareContentProvider.js +85 -0
  28. package/out/completionProvider.js +3739 -0
  29. package/out/contractAssertionSummary.js +225 -0
  30. package/out/contractDecorationProvider.js +243 -0
  31. package/out/coverageCalculator.js +879 -0
  32. package/out/coveragePanel.js +597 -0
  33. package/out/debug/breakpointResolver.js +84 -0
  34. package/out/debug/breakpoints.js +52 -0
  35. package/out/debug/nornDebugAdapter.js +166 -0
  36. package/out/debug/nornDebugSession.js +613 -0
  37. package/out/debug/sequenceLocationIndex.js +77 -0
  38. package/out/debug/types.js +3 -0
  39. package/out/deepClone.js +21 -0
  40. package/out/diagnosticProvider.js +2554 -0
  41. package/out/environmentParser.js +736 -0
  42. package/out/environmentProvider.js +544 -0
  43. package/out/environmentTemplates.js +146 -0
  44. package/out/errors/formatError.js +113 -0
  45. package/out/errors/nornError.js +29 -0
  46. package/out/formUrlEncoded.js +89 -0
  47. package/out/httpClient.js +348 -0
  48. package/out/httpRuntimeOptions.js +16 -0
  49. package/out/importErrors.js +31 -0
  50. package/out/inlayHintResolver.js +70 -0
  51. package/out/jsonFileReader.js +323 -0
  52. package/out/mcpClient.js +193 -0
  53. package/out/mcpConfig.js +184 -0
  54. package/out/mcpToolIntellisenseCache.js +96 -0
  55. package/out/mcpToolSchema.js +50 -0
  56. package/out/nornConfig.js +132 -0
  57. package/out/nornHoverProvider.js +124 -0
  58. package/out/nornInlayHintsProvider.js +191 -0
  59. package/out/nornPrompt.js +755 -0
  60. package/out/nornSqlParser.js +286 -0
  61. package/out/nornapiHoverProvider.js +135 -0
  62. package/out/nornapiInlayHintsProvider.js +94 -0
  63. package/out/nornapiParser.js +324 -0
  64. package/out/nornenvCodeActionProvider.js +101 -0
  65. package/out/nornenvDecorationProvider.js +239 -0
  66. package/out/nornenvFoldingProvider.js +63 -0
  67. package/out/nornenvHoverProvider.js +114 -0
  68. package/out/nornenvInlayHintsProvider.js +99 -0
  69. package/out/nornenvLanguageModel.js +187 -0
  70. package/out/nornenvRegionRefactor.js +267 -0
  71. package/out/nornsqlHoverProvider.js +95 -0
  72. package/out/nornsqlInlayHintsProvider.js +114 -0
  73. package/out/parser.js +839 -0
  74. package/out/pathAccess.js +28 -0
  75. package/out/postmanImportPanel.js +732 -0
  76. package/out/postmanImportPlanner.js +1155 -0
  77. package/out/postmanImportSidebarView.js +532 -0
  78. package/out/quotedString.js +35 -0
  79. package/out/requestPreparation.js +179 -0
  80. package/out/requestValidation.js +146 -0
  81. package/out/responsePanel.js +7754 -0
  82. package/out/schemaGenerator.js +562 -0
  83. package/out/scriptRunner.js +419 -0
  84. package/out/secrets/cliSecrets.js +415 -0
  85. package/out/secrets/crypto.js +105 -0
  86. package/out/secrets/envFileSecrets.js +177 -0
  87. package/out/secrets/keyStore.js +259 -0
  88. package/out/sequenceDeclaration.js +15 -0
  89. package/out/sequenceRunner.js +3590 -0
  90. package/out/sqlAdapterRunner.js +122 -0
  91. package/out/sqlBuiltInAdapters.js +604 -0
  92. package/out/sqlConfig.js +184 -0
  93. package/out/starterCatalog.js +554 -0
  94. package/out/stringUtils.js +25 -0
  95. package/out/swaggerBodyIntellisenseCache.js +114 -0
  96. package/out/swaggerParser.js +464 -0
  97. package/out/testProvider.js +767 -0
  98. package/out/theoryCaseLoader.js +113 -0
  99. package/out/validationCache.js +211 -0
  100. package/package.json +38 -11
  101. package/.kanbn/index.md +0 -31
  102. package/.kanbn/tasks/book-first-mentor-session.md +0 -13
  103. package/.kanbn/tasks/decide-what-success-in-a-pilot-looks-like.md +0 -9
  104. package/.kanbn/tasks/do-5-customer-conversations.md +0 -9
  105. package/.kanbn/tasks/finalise-the-one-line-pitch.md +0 -11
  106. package/.kanbn/tasks/interview-script.md +0 -49
  107. package/.kanbn/tasks/make-a-list-of-10-people-to-speak-to.md +0 -11
  108. package/.kanbn/tasks/prepare-your-customer-interview-questions.md +0 -11
  109. package/.kanbn/tasks/recruit-2/342/200/2233-pilot-users.md +0 -9
  110. package/.kanbn/tasks/refine-your-pitch.md +0 -9
  111. package/.kanbn/tasks/use-the-shiplight-website-as-a-template-to-improve-norn-website.md +0 -9
  112. package/.kanbn/tasks/write-down-repeated-wording.md +0 -9
  113. package/.kanbn/tasks/write-the-one-pager.md +0 -27
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.loadNornMcpProjectConfig = loadNornMcpProjectConfig;
37
+ exports.loadResolvedNornMcpProjectConfig = loadResolvedNornMcpProjectConfig;
38
+ exports.resolveMcpServer = resolveMcpServer;
39
+ const path = __importStar(require("path"));
40
+ const parser_1 = require("./parser");
41
+ const nornConfig_1 = require("./nornConfig");
42
+ function isRawMcpStdioServerConfig(value) {
43
+ if (!(0, nornConfig_1.isObjectRecord)(value)) {
44
+ return false;
45
+ }
46
+ if (value.transport !== 'stdio') {
47
+ return false;
48
+ }
49
+ if (!Array.isArray(value.command) || value.command.length === 0) {
50
+ return false;
51
+ }
52
+ if (!value.command.every(part => typeof part === 'string' && part.length > 0)) {
53
+ return false;
54
+ }
55
+ if (value.cwd !== undefined && typeof value.cwd !== 'string') {
56
+ return false;
57
+ }
58
+ return true;
59
+ }
60
+ function isRawMcpHttpServerConfig(value) {
61
+ if (!(0, nornConfig_1.isObjectRecord)(value)) {
62
+ return false;
63
+ }
64
+ if (value.transport !== 'http') {
65
+ return false;
66
+ }
67
+ if (typeof value.url !== 'string' || value.url.length === 0) {
68
+ return false;
69
+ }
70
+ if (value.headers !== undefined && !(0, nornConfig_1.isStringRecord)(value.headers)) {
71
+ return false;
72
+ }
73
+ if (value.timeoutMs !== undefined && (typeof value.timeoutMs !== 'number' || !Number.isFinite(value.timeoutMs) || value.timeoutMs <= 0)) {
74
+ return false;
75
+ }
76
+ return true;
77
+ }
78
+ function isNornMcpProjectConfig(value) {
79
+ if (!(0, nornConfig_1.isObjectRecord)(value)) {
80
+ return false;
81
+ }
82
+ const servers = value.servers;
83
+ if (!servers || typeof servers !== 'object' || Array.isArray(servers)) {
84
+ return false;
85
+ }
86
+ return Object.values(servers).every(server => isRawMcpStdioServerConfig(server) || isRawMcpHttpServerConfig(server));
87
+ }
88
+ function resolveTemplateString(value, envVariables) {
89
+ if (!envVariables) {
90
+ return value;
91
+ }
92
+ const scopedVariables = (0, parser_1.attachEnvironmentScope)({}, envVariables);
93
+ return (0, parser_1.substituteVariables)(value, scopedVariables);
94
+ }
95
+ function resolveCommandParts(configPath, command, envVariables) {
96
+ const configDir = path.dirname(configPath);
97
+ return command.map((part, index) => {
98
+ const resolvedPart = resolveTemplateString(part, envVariables);
99
+ if (!resolvedPart) {
100
+ return resolvedPart;
101
+ }
102
+ if (index === 0) {
103
+ if (path.isAbsolute(resolvedPart) || (!resolvedPart.startsWith('.') && !resolvedPart.includes(path.sep) && !resolvedPart.includes('/'))) {
104
+ return resolvedPart;
105
+ }
106
+ return path.resolve(configDir, resolvedPart);
107
+ }
108
+ if (resolvedPart.startsWith('.')) {
109
+ return path.resolve(configDir, resolvedPart);
110
+ }
111
+ return resolvedPart;
112
+ });
113
+ }
114
+ function resolveRelativeDirectory(configPath, value, envVariables) {
115
+ if (!value) {
116
+ return undefined;
117
+ }
118
+ const resolvedValue = resolveTemplateString(value, envVariables);
119
+ if (!resolvedValue) {
120
+ return resolvedValue;
121
+ }
122
+ if (path.isAbsolute(resolvedValue)) {
123
+ return resolvedValue;
124
+ }
125
+ return path.resolve(path.dirname(configPath), resolvedValue);
126
+ }
127
+ function resolveHeaders(headers, envVariables) {
128
+ if (!headers) {
129
+ return undefined;
130
+ }
131
+ const resolved = {};
132
+ for (const [key, value] of Object.entries(headers)) {
133
+ resolved[key] = resolveTemplateString(value, envVariables);
134
+ }
135
+ return resolved;
136
+ }
137
+ function resolveServerConfig(filePath, config, envVariables) {
138
+ if (config.transport === 'stdio') {
139
+ return {
140
+ transport: 'stdio',
141
+ command: resolveCommandParts(filePath, config.command, envVariables),
142
+ cwd: resolveRelativeDirectory(filePath, config.cwd, envVariables)
143
+ };
144
+ }
145
+ return {
146
+ transport: 'http',
147
+ url: resolveTemplateString(config.url, envVariables),
148
+ headers: resolveHeaders(config.headers, envVariables),
149
+ timeoutMs: config.timeoutMs
150
+ };
151
+ }
152
+ function loadNornMcpProjectConfig(startPath) {
153
+ const { filePath, section } = (0, nornConfig_1.loadNornConfigSection)(startPath, 'mcp', isNornMcpProjectConfig);
154
+ return {
155
+ filePath,
156
+ config: {
157
+ ...section,
158
+ version: 1
159
+ }
160
+ };
161
+ }
162
+ function loadResolvedNornMcpProjectConfig(startPath, envVariables) {
163
+ const { filePath, config } = loadNornMcpProjectConfig(startPath);
164
+ const resolvedServers = {};
165
+ for (const [alias, serverConfig] of Object.entries(config.servers)) {
166
+ resolvedServers[alias] = resolveServerConfig(filePath, serverConfig, envVariables);
167
+ }
168
+ return {
169
+ filePath,
170
+ config: {
171
+ version: 1,
172
+ servers: resolvedServers
173
+ }
174
+ };
175
+ }
176
+ function resolveMcpServer(startPath, alias, envVariables) {
177
+ const { filePath, config } = loadResolvedNornMcpProjectConfig(startPath, envVariables);
178
+ const server = config.servers[alias];
179
+ if (!server) {
180
+ throw new Error(`Server alias '${alias}' was not found in ${nornConfig_1.NORN_CONFIG_FILENAME} mcp.servers`);
181
+ }
182
+ return { filePath, server };
183
+ }
184
+ //# sourceMappingURL=mcpConfig.js.map
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.saveMcpToolsForAlias = saveMcpToolsForAlias;
37
+ exports.getCachedMcpToolsForAlias = getCachedMcpToolsForAlias;
38
+ exports.getCachedMcpToolForAlias = getCachedMcpToolForAlias;
39
+ const path = __importStar(require("path"));
40
+ const cacheDir_1 = require("./cacheDir");
41
+ const mcpConfig_1 = require("./mcpConfig");
42
+ const deepClone_1 = require("./deepClone");
43
+ const CACHE_VERSION = 1;
44
+ const CACHE_FILE = 'mcp-tool-intellisense.json';
45
+ function getCachePathForConfig(configPath) {
46
+ return (0, cacheDir_1.getNornCacheFilePath)(path.dirname(configPath), CACHE_FILE);
47
+ }
48
+ function ensureCacheDirForConfig(configPath) {
49
+ return !!(0, cacheDir_1.ensureNornCacheDir)(path.dirname(configPath));
50
+ }
51
+ function loadCacheForConfig(configPath) {
52
+ return (0, cacheDir_1.loadVersionedJsonCache)({
53
+ cachePath: getCachePathForConfig(configPath),
54
+ version: CACHE_VERSION,
55
+ createDefault: () => ({ version: CACHE_VERSION, servers: {} }),
56
+ isValid: cache => typeof cache.servers === 'object' && cache.servers !== null
57
+ });
58
+ }
59
+ function saveCacheForConfig(configPath, cache) {
60
+ return (0, cacheDir_1.saveVersionedJsonCache)(getCachePathForConfig(configPath), cache, () => ensureCacheDirForConfig(configPath));
61
+ }
62
+ function toCachedMcpTool(tool) {
63
+ return {
64
+ name: tool.name,
65
+ description: typeof tool.description === 'string' ? tool.description : undefined,
66
+ inputSchema: (0, deepClone_1.cloneSerializableValue)(tool.inputSchema)
67
+ };
68
+ }
69
+ function saveMcpToolsForAlias(configPath, alias, tools) {
70
+ const cache = loadCacheForConfig(configPath);
71
+ cache.servers[alias.toLowerCase()] = {
72
+ alias,
73
+ cachedAt: new Date().toISOString(),
74
+ tools: tools.map(tool => toCachedMcpTool(tool))
75
+ };
76
+ saveCacheForConfig(configPath, cache);
77
+ }
78
+ function getCachedMcpToolsForAlias(startPath, alias) {
79
+ let configPath;
80
+ try {
81
+ configPath = (0, mcpConfig_1.loadNornMcpProjectConfig)(startPath).filePath;
82
+ }
83
+ catch {
84
+ return undefined;
85
+ }
86
+ const cache = loadCacheForConfig(configPath);
87
+ return cache.servers[alias.toLowerCase()];
88
+ }
89
+ function getCachedMcpToolForAlias(startPath, alias, toolName) {
90
+ const cachedTools = getCachedMcpToolsForAlias(startPath, alias);
91
+ if (!cachedTools) {
92
+ return undefined;
93
+ }
94
+ return cachedTools.tools.find(tool => tool.name.toLowerCase() === toolName.toLowerCase());
95
+ }
96
+ //# sourceMappingURL=mcpToolIntellisenseCache.js.map
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getMcpToolInputPropertyMap = getMcpToolInputPropertyMap;
4
+ exports.getMcpToolInputParameterNames = getMcpToolInputParameterNames;
5
+ exports.getMcpToolRequiredParameterNames = getMcpToolRequiredParameterNames;
6
+ exports.mcpToolAllowsAdditionalProperties = mcpToolAllowsAdditionalProperties;
7
+ function getInputSchemaObject(source) {
8
+ if (!source.inputSchema || typeof source.inputSchema !== 'object' || Array.isArray(source.inputSchema)) {
9
+ return undefined;
10
+ }
11
+ return source.inputSchema;
12
+ }
13
+ function getMcpToolInputPropertyMap(source) {
14
+ const schema = getInputSchemaObject(source);
15
+ if (!schema) {
16
+ return {};
17
+ }
18
+ const properties = schema.properties;
19
+ if (!properties || typeof properties !== 'object' || Array.isArray(properties)) {
20
+ return {};
21
+ }
22
+ return properties;
23
+ }
24
+ function getMcpToolInputParameterNames(source) {
25
+ const propertyMap = getMcpToolInputPropertyMap(source);
26
+ const propertyNames = Object.keys(propertyMap);
27
+ if (propertyNames.length > 0) {
28
+ return propertyNames;
29
+ }
30
+ const schema = getInputSchemaObject(source);
31
+ if (!schema || !Array.isArray(schema.required)) {
32
+ return [];
33
+ }
34
+ return schema.required.filter((entry) => typeof entry === 'string');
35
+ }
36
+ function getMcpToolRequiredParameterNames(source) {
37
+ const schema = getInputSchemaObject(source);
38
+ if (!schema || !Array.isArray(schema.required)) {
39
+ return [];
40
+ }
41
+ return schema.required.filter((entry) => typeof entry === 'string');
42
+ }
43
+ function mcpToolAllowsAdditionalProperties(source) {
44
+ const schema = getInputSchemaObject(source);
45
+ if (!schema) {
46
+ return true;
47
+ }
48
+ return schema.additionalProperties !== false;
49
+ }
50
+ //# sourceMappingURL=mcpToolSchema.js.map
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.NORN_CONFIG_FILENAME = void 0;
37
+ exports.findNearestConfigFile = findNearestConfigFile;
38
+ exports.parseJsonFile = parseJsonFile;
39
+ exports.isObjectRecord = isObjectRecord;
40
+ exports.isStringRecord = isStringRecord;
41
+ exports.loadNornConfig = loadNornConfig;
42
+ exports.loadNornConfigSection = loadNornConfigSection;
43
+ const fs = __importStar(require("fs"));
44
+ const path = __importStar(require("path"));
45
+ exports.NORN_CONFIG_FILENAME = 'norn.config.json';
46
+ function getSearchDirectory(startPath) {
47
+ if (!startPath) {
48
+ return process.cwd();
49
+ }
50
+ const absolute = path.resolve(startPath);
51
+ try {
52
+ const stats = fs.statSync(absolute);
53
+ return stats.isDirectory() ? absolute : path.dirname(absolute);
54
+ }
55
+ catch {
56
+ return path.extname(absolute) ? path.dirname(absolute) : absolute;
57
+ }
58
+ }
59
+ function findNearestConfigFile(startPath, fileName) {
60
+ let currentDir = getSearchDirectory(startPath);
61
+ while (true) {
62
+ const candidate = path.join(currentDir, fileName);
63
+ if (fs.existsSync(candidate)) {
64
+ return candidate;
65
+ }
66
+ const parentDir = path.dirname(currentDir);
67
+ if (parentDir === currentDir) {
68
+ return undefined;
69
+ }
70
+ currentDir = parentDir;
71
+ }
72
+ }
73
+ function parseJsonFile(filePath, validator, label) {
74
+ let raw;
75
+ try {
76
+ raw = fs.readFileSync(filePath, 'utf-8');
77
+ }
78
+ catch (error) {
79
+ throw new Error(`Failed to read ${label}: ${error instanceof Error ? error.message : String(error)}`);
80
+ }
81
+ let parsed;
82
+ try {
83
+ parsed = JSON.parse(raw);
84
+ }
85
+ catch (error) {
86
+ throw new Error(`Invalid JSON in ${label}: ${error instanceof Error ? error.message : String(error)}`);
87
+ }
88
+ if (!validator(parsed)) {
89
+ throw new Error(`Invalid ${label} structure`);
90
+ }
91
+ return parsed;
92
+ }
93
+ function isObjectRecord(value) {
94
+ return !!value && typeof value === 'object' && !Array.isArray(value);
95
+ }
96
+ function isStringRecord(value) {
97
+ return isObjectRecord(value) && Object.values(value).every(entry => typeof entry === 'string');
98
+ }
99
+ function isKnownSection(value) {
100
+ return value === undefined || isObjectRecord(value);
101
+ }
102
+ function isNornProjectConfig(value) {
103
+ if (!isObjectRecord(value)) {
104
+ return false;
105
+ }
106
+ if (value.version !== 1) {
107
+ return false;
108
+ }
109
+ return isKnownSection(value.sql) && isKnownSection(value.mcp);
110
+ }
111
+ function loadNornConfig(startPath) {
112
+ const filePath = findNearestConfigFile(startPath, exports.NORN_CONFIG_FILENAME);
113
+ if (!filePath) {
114
+ throw new Error(`Could not find ${exports.NORN_CONFIG_FILENAME}`);
115
+ }
116
+ return {
117
+ filePath,
118
+ config: parseJsonFile(filePath, isNornProjectConfig, exports.NORN_CONFIG_FILENAME)
119
+ };
120
+ }
121
+ function loadNornConfigSection(startPath, sectionName, validator) {
122
+ const { filePath, config } = loadNornConfig(startPath);
123
+ const section = config[sectionName];
124
+ if (section === undefined) {
125
+ throw new Error(`Could not find ${sectionName} section in ${exports.NORN_CONFIG_FILENAME}`);
126
+ }
127
+ if (!validator(section)) {
128
+ throw new Error(`Invalid ${sectionName} section in ${exports.NORN_CONFIG_FILENAME}`);
129
+ }
130
+ return { filePath, section };
131
+ }
132
+ //# sourceMappingURL=nornConfig.js.map
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.NornHoverProvider = void 0;
37
+ const vscode = __importStar(require("vscode"));
38
+ const environmentProvider_1 = require("./environmentProvider");
39
+ const inlayHintResolver_1 = require("./inlayHintResolver");
40
+ const environmentTemplates_1 = require("./environmentTemplates");
41
+ const nornInlayHintsProvider_1 = require("./nornInlayHintsProvider");
42
+ const nornapiHoverProvider_1 = require("./nornapiHoverProvider");
43
+ /**
44
+ * Hover for `.norn`. On any `{{ref}}` token it returns one of:
45
+ * - "Defined as <static value> in <scope> at line N" — when the ref is a file-local or
46
+ * sequence-local var we can statically resolve.
47
+ * - "Defined in <scope> at line N — runtime expression: <raw>" — when it's a runtime var
48
+ * (response capture, request, run-sequence return).
49
+ * - The standard env-scope hover (source + resolved value under active env) — when the
50
+ * ref isn't a local var.
51
+ */
52
+ class NornHoverProvider {
53
+ provideHover(document, position) {
54
+ try {
55
+ const filePath = document.uri.scheme === 'file' ? document.uri.fsPath : undefined;
56
+ if (!filePath) {
57
+ return undefined;
58
+ }
59
+ const lineText = document.lineAt(position.line).text;
60
+ const tokenMatch = (0, nornapiHoverProvider_1.findTemplateTokenAt)(lineText, position.character);
61
+ if (!tokenMatch) {
62
+ return undefined;
63
+ }
64
+ const parsed = (0, inlayHintResolver_1.parseInlayReference)(tokenMatch.referenceRaw);
65
+ if (!parsed) {
66
+ return undefined;
67
+ }
68
+ const config = (0, environmentProvider_1.loadEnvironmentConfig)(filePath);
69
+ const activeEnvironment = (0, environmentProvider_1.getActiveEnvironment)(filePath);
70
+ const index = (0, nornInlayHintsProvider_1.buildNornScopeIndex)(document.getText());
71
+ const inScope = (0, nornInlayHintsProvider_1.getInScopeDecls)(index, position.line);
72
+ const localDecl = inScope.find(decl => decl.name === parsed.name);
73
+ const hoverRange = new vscode.Range(new vscode.Position(position.line, tokenMatch.tokenStart), new vscode.Position(position.line, tokenMatch.tokenEnd));
74
+ if (localDecl && !parsed.envOnly) {
75
+ // Local var (sequence- or file-scope) takes precedence unless the reference
76
+ // explicitly opted into env scope via `{{$env.X}}`.
77
+ const markdown = renderLocalVarHover(localDecl, document, index, activeEnvironment, config);
78
+ return new vscode.Hover(markdown, hoverRange);
79
+ }
80
+ // No local match — fall through to the standard env-scope hover.
81
+ const markdown = (0, nornapiHoverProvider_1.renderTemplateReferenceHover)(parsed.name, config, activeEnvironment);
82
+ return new vscode.Hover(markdown, hoverRange);
83
+ }
84
+ catch {
85
+ return undefined;
86
+ }
87
+ }
88
+ }
89
+ exports.NornHoverProvider = NornHoverProvider;
90
+ function renderLocalVarHover(decl, document, index, activeEnvironment, config) {
91
+ const lines = [`**\`${decl.name}\`**`];
92
+ const scopeLabel = decl.scope === 'sequence-local'
93
+ ? `\`sequence:${decl.sequenceName ?? '?'}\``
94
+ : '`file-local`';
95
+ lines.push(`Defined in ${scopeLabel} at line ${decl.lineNumber + 1}.`);
96
+ if (decl.isRuntime) {
97
+ lines.push(`Runtime expression: \`${decl.rawValue}\` — value is only known when the sequence runs.`);
98
+ return new vscode.MarkdownString(lines.join('\n\n'));
99
+ }
100
+ // Static value — show what it resolves to under the active env (in case the value itself
101
+ // contains {{...}} that reaches back into env scope).
102
+ const filePath = document.uri.scheme === 'file' ? document.uri.fsPath : undefined;
103
+ const envVariables = (filePath && config) ? (0, environmentProvider_1.getEnvironmentVariables)(filePath) : {};
104
+ const enclosing = (0, nornInlayHintsProvider_1.findEnclosingSequence)(index, decl.lineNumber);
105
+ void enclosing; // scope tracking is implicit in index; kept for future extension
106
+ const merged = (0, nornInlayHintsProvider_1.buildScopedVariablesAtLine)(envVariables, index, decl.lineNumber + 1);
107
+ const resolved = (0, environmentTemplates_1.resolveEnvironmentTemplateValue)(decl.name, merged, config?.secretNames ?? new Set());
108
+ if (resolved.errors.length === 0) {
109
+ if (resolved.secret) {
110
+ lines.push(`Resolves to a secret value.`);
111
+ }
112
+ else if (activeEnvironment) {
113
+ lines.push(`Under active env \`${activeEnvironment}\`, resolves to \`${resolved.value}\`.`);
114
+ }
115
+ else {
116
+ lines.push(`Value: \`${resolved.value}\`.`);
117
+ }
118
+ }
119
+ else {
120
+ lines.push(`Raw value: \`${decl.rawValue}\` (could not fully resolve — some references are missing or runtime-only).`);
121
+ }
122
+ return new vscode.MarkdownString(lines.join('\n\n'));
123
+ }
124
+ //# sourceMappingURL=nornHoverProvider.js.map