norn-cli 4.3.2 → 4.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/README.md +7 -7
- package/dist/cli.js +1272 -1094
- package/dist/knowledgeIndexWorker.js +78 -13
- package/package.json +13 -15
- package/schemas/norn.config.schema.json +1 -1
|
@@ -6653,7 +6653,7 @@ function ensureNornCacheDir(rootPath) {
|
|
|
6653
6653
|
}
|
|
6654
6654
|
|
|
6655
6655
|
// src/knowledge/knowledgeIndex.ts
|
|
6656
|
-
var KNOWLEDGE_SCHEMA_VERSION =
|
|
6656
|
+
var KNOWLEDGE_SCHEMA_VERSION = 3;
|
|
6657
6657
|
var BUSY_TIMEOUT_MS = 5e3;
|
|
6658
6658
|
var SCHEMA = `
|
|
6659
6659
|
CREATE TABLE IF NOT EXISTS control (
|
|
@@ -6717,6 +6717,7 @@ CREATE TABLE IF NOT EXISTS snapshot_occurrences (
|
|
|
6717
6717
|
topic_hash TEXT NOT NULL REFERENCES topics(topic_hash),
|
|
6718
6718
|
authored_type TEXT,
|
|
6719
6719
|
authored_use_when TEXT,
|
|
6720
|
+
environment_import TEXT,
|
|
6720
6721
|
effective_type TEXT NOT NULL,
|
|
6721
6722
|
start_line INTEGER NOT NULL,
|
|
6722
6723
|
end_line INTEGER NOT NULL,
|
|
@@ -6907,7 +6908,7 @@ var KnowledgeIndex = class {
|
|
|
6907
6908
|
fs2.mkdirSync(path2.dirname(this.databasePath), { recursive: true, mode: 448 });
|
|
6908
6909
|
let database = new import_node_sqlite.DatabaseSync(this.databasePath);
|
|
6909
6910
|
const version = currentSchemaVersion(database);
|
|
6910
|
-
if (version !== 0 && version !== 1 && version !== KNOWLEDGE_SCHEMA_VERSION) {
|
|
6911
|
+
if (version !== 0 && version !== 1 && version !== 2 && version !== KNOWLEDGE_SCHEMA_VERSION) {
|
|
6911
6912
|
database.close();
|
|
6912
6913
|
if (options.rejectUnsupportedSchema) {
|
|
6913
6914
|
throw new Error(`Unsupported knowledge index schema ${version}; expected ${KNOWLEDGE_SCHEMA_VERSION}.`);
|
|
@@ -6918,6 +6919,10 @@ var KnowledgeIndex = class {
|
|
|
6918
6919
|
this.database = database;
|
|
6919
6920
|
this.database.exec(`PRAGMA journal_mode = WAL; PRAGMA busy_timeout = ${BUSY_TIMEOUT_MS}; PRAGMA foreign_keys = ON;`);
|
|
6920
6921
|
this.database.exec(SCHEMA);
|
|
6922
|
+
const occurrenceColumns = this.database.prepare("PRAGMA table_info(snapshot_occurrences)").all();
|
|
6923
|
+
if (!occurrenceColumns.some((column) => column.name === "environment_import")) {
|
|
6924
|
+
this.database.exec("ALTER TABLE snapshot_occurrences ADD COLUMN environment_import TEXT");
|
|
6925
|
+
}
|
|
6921
6926
|
this.database.exec(`PRAGMA user_version = ${KNOWLEDGE_SCHEMA_VERSION}`);
|
|
6922
6927
|
try {
|
|
6923
6928
|
fs2.chmodSync(this.databasePath, 384);
|
|
@@ -6994,6 +6999,9 @@ var KnowledgeIndex = class {
|
|
|
6994
6999
|
if (row.authored_use_when) {
|
|
6995
7000
|
metadata.useWhen = { origin: "authored", value: String(row.authored_use_when) };
|
|
6996
7001
|
}
|
|
7002
|
+
if (row.environment_import) {
|
|
7003
|
+
metadata.import = { origin: "authored", value: String(row.environment_import) };
|
|
7004
|
+
}
|
|
6997
7005
|
return {
|
|
6998
7006
|
declarationId: String(row.declaration_id),
|
|
6999
7007
|
declarationPath: String(row.declaration_path),
|
|
@@ -7252,7 +7260,7 @@ function queryKnowledgeEditorFacts(query, options = {}) {
|
|
|
7252
7260
|
for (const context of query.contexts) {
|
|
7253
7261
|
const rows = index.all(`
|
|
7254
7262
|
SELECT topic_hash, domain_path, item_key, ordinal, heading_text, effective_type,
|
|
7255
|
-
authored_type, authored_use_when
|
|
7263
|
+
authored_type, authored_use_when, environment_import
|
|
7256
7264
|
FROM snapshot_occurrences
|
|
7257
7265
|
WHERE snapshot_id = ? AND declaration_id = ? AND source_id = ? AND item_key = ?
|
|
7258
7266
|
ORDER BY ordinal
|
|
@@ -7265,6 +7273,9 @@ function queryKnowledgeEditorFacts(query, options = {}) {
|
|
|
7265
7273
|
if (row.authored_use_when !== null) {
|
|
7266
7274
|
metadata.useWhen = { origin: "authored", value: String(row.authored_use_when) };
|
|
7267
7275
|
}
|
|
7276
|
+
if (row.environment_import !== null) {
|
|
7277
|
+
metadata.import = { origin: "authored", value: String(row.environment_import) };
|
|
7278
|
+
}
|
|
7268
7279
|
const topicHash = String(row.topic_hash);
|
|
7269
7280
|
const bucket = occurrencesByHash.get(topicHash) ?? [];
|
|
7270
7281
|
bucket.push({
|
|
@@ -7320,6 +7331,12 @@ function queryKnowledgeEditorFacts(query, options = {}) {
|
|
|
7320
7331
|
}
|
|
7321
7332
|
}
|
|
7322
7333
|
|
|
7334
|
+
// src/agents/agentSidecarPath.ts
|
|
7335
|
+
function isAgentSidecarPath(filePath) {
|
|
7336
|
+
const lowerPath = filePath.toLowerCase();
|
|
7337
|
+
return lowerPath.endsWith(".nornagent") || lowerPath.endsWith(".nornai");
|
|
7338
|
+
}
|
|
7339
|
+
|
|
7323
7340
|
// src/knowledge/knowledgeIndexBuilder.ts
|
|
7324
7341
|
var fs8 = __toESM(require("fs"));
|
|
7325
7342
|
var path10 = __toESM(require("path"));
|
|
@@ -7878,6 +7895,7 @@ function parseNornAgentFile(content, sourcePath) {
|
|
|
7878
7895
|
let pendingMcp;
|
|
7879
7896
|
let pendingKnowledge;
|
|
7880
7897
|
let sawAgent = false;
|
|
7898
|
+
let sawMcpDeclaration = false;
|
|
7881
7899
|
const reportBareMcpAlias = (mcp) => {
|
|
7882
7900
|
errors.push(parseError(
|
|
7883
7901
|
mcp.lineNumber,
|
|
@@ -8446,6 +8464,7 @@ end model`,
|
|
|
8446
8464
|
}
|
|
8447
8465
|
const mcpMatch = trimmed.match(new RegExp(`^mcp\\s+(${IDENTIFIER})$`, "i"));
|
|
8448
8466
|
if (mcpMatch) {
|
|
8467
|
+
sawMcpDeclaration = true;
|
|
8449
8468
|
const alias = mcpMatch[1];
|
|
8450
8469
|
let invalid = false;
|
|
8451
8470
|
if (sawAgent) {
|
|
@@ -8838,11 +8857,11 @@ end model`,
|
|
|
8838
8857
|
"agent-knowledge-end-missing"
|
|
8839
8858
|
));
|
|
8840
8859
|
}
|
|
8841
|
-
if (models.size === 0) {
|
|
8842
|
-
errors.push(parseError(0, "
|
|
8860
|
+
if (!sawMcpDeclaration && models.size === 0) {
|
|
8861
|
+
errors.push(parseError(0, "An agent sidecar must declare at least one model block.", "agent-model-required"));
|
|
8843
8862
|
}
|
|
8844
|
-
if (agentNames.size === 0) {
|
|
8845
|
-
errors.push(parseError(0, "
|
|
8863
|
+
if (!sawMcpDeclaration && agentNames.size === 0) {
|
|
8864
|
+
errors.push(parseError(0, "An agent sidecar must declare at least one agent.", "agent-required"));
|
|
8846
8865
|
}
|
|
8847
8866
|
const localScope = new Map(agents.map((agent) => [agent.name.toLowerCase(), agent]));
|
|
8848
8867
|
for (const validationError of validateAgentScope(localScope, { checkUnknownReferences: false })) {
|
|
@@ -8929,10 +8948,26 @@ function parseMetaBlock(lines, startLine, endLine, diagnostics) {
|
|
|
8929
8948
|
} else {
|
|
8930
8949
|
metadata.useWhen = authored(value);
|
|
8931
8950
|
}
|
|
8951
|
+
} else if (key === "import") {
|
|
8952
|
+
if (metadata.import) {
|
|
8953
|
+
diagnostics.push({
|
|
8954
|
+
lineNumber: startLine + offset,
|
|
8955
|
+
message: "norn:meta declares import more than once.",
|
|
8956
|
+
code: "knowledge-meta-import-duplicate"
|
|
8957
|
+
});
|
|
8958
|
+
} else if (!/^(["']).*\.nornenv\1$/.test(value)) {
|
|
8959
|
+
diagnostics.push({
|
|
8960
|
+
lineNumber: startLine + offset,
|
|
8961
|
+
message: "The environment import must be a quoted .nornenv path.",
|
|
8962
|
+
code: "knowledge-meta-import-invalid"
|
|
8963
|
+
});
|
|
8964
|
+
} else {
|
|
8965
|
+
metadata.import = authored(value.slice(1, -1));
|
|
8966
|
+
}
|
|
8932
8967
|
} else {
|
|
8933
8968
|
diagnostics.push({
|
|
8934
8969
|
lineNumber: startLine + offset,
|
|
8935
|
-
message: `Unknown norn:meta key '${match[1]}'. Expected type or
|
|
8970
|
+
message: `Unknown norn:meta key '${match[1]}'. Expected type, use_when, or import.`,
|
|
8936
8971
|
code: "knowledge-meta-key-unknown"
|
|
8937
8972
|
});
|
|
8938
8973
|
}
|
|
@@ -8985,6 +9020,15 @@ function mergeMetadata(target, incoming, lineNumber, diagnostics) {
|
|
|
8985
9020
|
} else if (incoming.useWhen) {
|
|
8986
9021
|
target.useWhen = incoming.useWhen;
|
|
8987
9022
|
}
|
|
9023
|
+
if (target.import && incoming.import) {
|
|
9024
|
+
diagnostics.push({
|
|
9025
|
+
lineNumber,
|
|
9026
|
+
message: "A topic may have only one environment import.",
|
|
9027
|
+
code: "knowledge-meta-import-duplicate"
|
|
9028
|
+
});
|
|
9029
|
+
} else if (incoming.import) {
|
|
9030
|
+
target.import = incoming.import;
|
|
9031
|
+
}
|
|
8988
9032
|
}
|
|
8989
9033
|
function firstContentLine(lines, from, to, metaByLine) {
|
|
8990
9034
|
for (let line = from; line <= to; line++) {
|
|
@@ -9077,6 +9121,14 @@ function extractKnowledgeTopics(text, filePath, headingDepth = 2) {
|
|
|
9077
9121
|
const preambleEnd = firstBoundary - 1;
|
|
9078
9122
|
const preamble = metadataFor(h1Line >= 0 ? h1Line : -1, preambleEnd);
|
|
9079
9123
|
const preambleMetadata = preamble.metadata;
|
|
9124
|
+
if (preambleMetadata.import && h1Line < 0) {
|
|
9125
|
+
diagnostics.push({
|
|
9126
|
+
lineNumber: preamble.block?.startLine ?? 0,
|
|
9127
|
+
message: "An environment import must sit under a # title.",
|
|
9128
|
+
code: "knowledge-meta-import-placement"
|
|
9129
|
+
});
|
|
9130
|
+
delete preambleMetadata.import;
|
|
9131
|
+
}
|
|
9080
9132
|
const preambleBody = bodyBetween(lines, 0, preambleEnd, removedLines);
|
|
9081
9133
|
if (h1Text || preambleBody) {
|
|
9082
9134
|
topics.push({
|
|
@@ -9100,6 +9152,17 @@ function extractKnowledgeTopics(text, filePath, headingDepth = 2) {
|
|
|
9100
9152
|
const endLine = (boundaries[index + 1] ?? lines.length) - 1;
|
|
9101
9153
|
const headingText = headingPattern.exec(lines[headingLine])?.[1].trim() ?? "";
|
|
9102
9154
|
const { metadata, block } = metadataFor(headingLine, endLine);
|
|
9155
|
+
if (metadata.import) {
|
|
9156
|
+
diagnostics.push({
|
|
9157
|
+
lineNumber: block?.startLine ?? headingLine,
|
|
9158
|
+
message: "An environment import belongs under the # title, not a section.",
|
|
9159
|
+
code: "knowledge-meta-import-placement"
|
|
9160
|
+
});
|
|
9161
|
+
delete metadata.import;
|
|
9162
|
+
}
|
|
9163
|
+
if (preambleMetadata.import) {
|
|
9164
|
+
metadata.import = preambleMetadata.import;
|
|
9165
|
+
}
|
|
9103
9166
|
const body = bodyBetween(lines, headingLine + 1, endLine, removedLines);
|
|
9104
9167
|
let excluded = fileExcluded;
|
|
9105
9168
|
let exclusionReason = fileExcluded ? "file marker <!-- norn:exclude -->" : void 0;
|
|
@@ -9152,7 +9215,7 @@ function extractKnowledgeTopics(text, filePath, headingDepth = 2) {
|
|
|
9152
9215
|
|
|
9153
9216
|
// src/knowledge/knowledgeBuilder.ts
|
|
9154
9217
|
var DEFAULT_EXTENSIONS = [".md"];
|
|
9155
|
-
var KNOWLEDGE_MARKDOWN_ANALYZER_VERSION =
|
|
9218
|
+
var KNOWLEDGE_MARKDOWN_ANALYZER_VERSION = 3;
|
|
9156
9219
|
function normalizeRelative(filePath) {
|
|
9157
9220
|
return filePath.split(path7.sep).join("/").replace(/^\.\//, "");
|
|
9158
9221
|
}
|
|
@@ -10413,7 +10476,7 @@ function walkSidecars(directory) {
|
|
|
10413
10476
|
if (entry.isDirectory()) {
|
|
10414
10477
|
return walkSidecars(candidate);
|
|
10415
10478
|
}
|
|
10416
|
-
return entry.isFile() && entry.name
|
|
10479
|
+
return entry.isFile() && isAgentSidecarPath(entry.name) ? [candidate] : [];
|
|
10417
10480
|
});
|
|
10418
10481
|
}
|
|
10419
10482
|
function discoverKnowledgeDeclarations(projectRoot) {
|
|
@@ -10715,8 +10778,8 @@ function commitSnapshot(index, projectRoot, snapshotId, manifestJson, builtAt, d
|
|
|
10715
10778
|
INSERT OR IGNORE INTO snapshot_occurrences(
|
|
10716
10779
|
snapshot_id, declaration_id, declaration_path, declaration_alias, source_id, source_path,
|
|
10717
10780
|
item_key, domain_path, heading_text, ordinal, topic_hash, authored_type, authored_use_when,
|
|
10718
|
-
effective_type, start_line, end_line
|
|
10719
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
10781
|
+
environment_import, effective_type, start_line, end_line
|
|
10782
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
10720
10783
|
`,
|
|
10721
10784
|
snapshotId,
|
|
10722
10785
|
occurrence.declarationId,
|
|
@@ -10731,6 +10794,7 @@ function commitSnapshot(index, projectRoot, snapshotId, manifestJson, builtAt, d
|
|
|
10731
10794
|
occurrence.topicHash,
|
|
10732
10795
|
occurrence.metadata.type?.value ?? null,
|
|
10733
10796
|
occurrence.metadata.useWhen?.value ?? null,
|
|
10797
|
+
occurrence.metadata.import?.value ?? null,
|
|
10734
10798
|
occurrence.effectiveType,
|
|
10735
10799
|
occurrence.startLine,
|
|
10736
10800
|
occurrence.endLine
|
|
@@ -10915,7 +10979,8 @@ function buildKnowledgeIndex(startPath, options = {}) {
|
|
|
10915
10979
|
ordinal: occurrence.ordinal,
|
|
10916
10980
|
topicHash: occurrence.topicHash,
|
|
10917
10981
|
authoredType: occurrence.metadata.type?.value ?? null,
|
|
10918
|
-
authoredUseWhen: occurrence.metadata.useWhen?.value ?? null
|
|
10982
|
+
authoredUseWhen: occurrence.metadata.useWhen?.value ?? null,
|
|
10983
|
+
authoredImport: occurrence.metadata.import?.value ?? null
|
|
10919
10984
|
})),
|
|
10920
10985
|
projectInputs: projectInputs.map((input) => ({ path: input.projectPath, contentHash: input.contentHash })).sort((left, right) => left.path.localeCompare(right.path)),
|
|
10921
10986
|
analyzers: [
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "norn-cli",
|
|
3
3
|
"displayName": "Norn",
|
|
4
|
-
"description": "
|
|
5
|
-
"version": "4.
|
|
4
|
+
"description": "Build version-controlled agentic flows in VS Code and run them from the CLI or CI.",
|
|
5
|
+
"version": "4.5.0",
|
|
6
6
|
"publisher": "Norn-PeterKrustanov",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Peter Krastanov"
|
|
@@ -47,7 +47,9 @@
|
|
|
47
47
|
"onLanguage:nornenv",
|
|
48
48
|
"onLanguage:nornk8s",
|
|
49
49
|
"onLanguage:nornagent",
|
|
50
|
+
"onLanguage:markdown",
|
|
50
51
|
"workspaceContains:**/*.nornagent",
|
|
52
|
+
"workspaceContains:**/*.nornai",
|
|
51
53
|
"workspaceContains:**/norn.config.json",
|
|
52
54
|
"onChatParticipant:norn.chat",
|
|
53
55
|
"onView:norn.sidebarHome",
|
|
@@ -55,12 +57,12 @@
|
|
|
55
57
|
"onCommand:norn.importPostmanEnvironment",
|
|
56
58
|
"onCommand:norn.createStarterCatalog",
|
|
57
59
|
"onCommand:norn.createSqlStarterFiles",
|
|
58
|
-
"onCommand:norn.createMcpStarterConfig",
|
|
59
60
|
"onCommand:norn.openTerminal",
|
|
60
61
|
"onCommand:norn.terminal.focusRawTerminal",
|
|
61
62
|
"onCommand:norn.debugSequence",
|
|
62
63
|
"onCommand:norn.debug.runToNextContractFailure",
|
|
63
64
|
"onCommand:norn.showAgentGraph",
|
|
65
|
+
"onCommand:norn.chatWithAgent",
|
|
64
66
|
"onCommand:norn.showAgentRunResults",
|
|
65
67
|
"onDebugResolve:norn"
|
|
66
68
|
],
|
|
@@ -93,6 +95,11 @@
|
|
|
93
95
|
"title": "Show Agent Graph",
|
|
94
96
|
"category": "Norn"
|
|
95
97
|
},
|
|
98
|
+
{
|
|
99
|
+
"command": "norn.chatWithAgent",
|
|
100
|
+
"title": "Chat With Agent",
|
|
101
|
+
"category": "Norn"
|
|
102
|
+
},
|
|
96
103
|
{
|
|
97
104
|
"command": "norn.showAgentRunResults",
|
|
98
105
|
"title": "Show Agent Run Results",
|
|
@@ -192,11 +199,6 @@
|
|
|
192
199
|
"title": "Open Norn Starter Catalogue",
|
|
193
200
|
"category": "Norn"
|
|
194
201
|
},
|
|
195
|
-
{
|
|
196
|
-
"command": "norn.createMcpStarterConfig",
|
|
197
|
-
"title": "Create MCP Starter Config",
|
|
198
|
-
"category": "Norn"
|
|
199
|
-
},
|
|
200
202
|
{
|
|
201
203
|
"command": "norn.encryptSecretAtLine",
|
|
202
204
|
"title": "Encrypt Secret At Line",
|
|
@@ -266,11 +268,6 @@
|
|
|
266
268
|
"command": "norn.createStarterCatalog",
|
|
267
269
|
"when": "explorerResourceIsFolder",
|
|
268
270
|
"group": "norn@1"
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
"command": "norn.createMcpStarterConfig",
|
|
272
|
-
"when": "explorerResourceIsFolder",
|
|
273
|
-
"group": "norn@2"
|
|
274
271
|
}
|
|
275
272
|
],
|
|
276
273
|
"debug/toolBar": [
|
|
@@ -369,7 +366,8 @@
|
|
|
369
366
|
"nornagent"
|
|
370
367
|
],
|
|
371
368
|
"extensions": [
|
|
372
|
-
".nornagent"
|
|
369
|
+
".nornagent",
|
|
370
|
+
".nornai"
|
|
373
371
|
],
|
|
374
372
|
"icon": {
|
|
375
373
|
"light": "./images/nornagent-icon.svg",
|
|
@@ -641,7 +639,7 @@
|
|
|
641
639
|
"test:regression": "node ./tests/test-scripts/run-regression.js",
|
|
642
640
|
"test:prerelease": "npm test && npm run test:regression",
|
|
643
641
|
"publish:npm": "node -e \"const fs=require('fs');const p=require('./package.json');p.name='norn-cli';fs.writeFileSync('package.json',JSON.stringify(p,null,2)+'\\n')\" && npm publish; exit_code=$?; node -e \"const fs=require('fs');const p=require('./package.json');p.name='norn';fs.writeFileSync('package.json',JSON.stringify(p,null,2)+'\\n')\"; exit $exit_code",
|
|
644
|
-
"publish:vsce": "
|
|
642
|
+
"publish:vsce": "node ./scripts/publish-vsce.mjs",
|
|
645
643
|
"publish:all": "npm run publish:npm && npm run publish:vsce"
|
|
646
644
|
},
|
|
647
645
|
"devDependencies": {
|
|
@@ -486,7 +486,7 @@
|
|
|
486
486
|
"agentsSection": {
|
|
487
487
|
"type": "object",
|
|
488
488
|
"additionalProperties": false,
|
|
489
|
-
"description": "Global recording behavior and global/provider-specific limits for agent runs. Per-agent .nornagent directives override limit values.",
|
|
489
|
+
"description": "Global recording behavior and global/provider-specific limits for agent runs. Per-agent .nornai or .nornagent directives override limit values.",
|
|
490
490
|
"properties": {
|
|
491
491
|
"_comment": {
|
|
492
492
|
"$ref": "#/definitions/comment",
|