@yegor256/dogent 0.9.0 → 0.10.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.
@@ -0,0 +1,77 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: Copyright (c) 2026 Yegor Bugayenko
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const Violation = require('../violation');
9
+ const Region = require('../region');
10
+ const mask = require('../mask');
11
+
12
+ /**
13
+ * Terms.
14
+ *
15
+ * Flags synonym drift: one concept named several ways across a file.
16
+ * Where consistent hunts word-for-word duplicates and contradictions,
17
+ * this rule catches the same idea wearing different labels, which makes
18
+ * the agent guess whether two names mean two things. A small built-in
19
+ * map of synonym groups seeds the deterministic check; the broader,
20
+ * fuzzier judgement is handed to the AI oracle through prompt().
21
+ */
22
+ class Terms {
23
+ constructor() {
24
+ this.id = 'terms';
25
+ this.groups = [
26
+ ['agent', 'assistant', 'bot'],
27
+ ['directory', 'folder'],
28
+ ['parameter', 'argument', 'param', 'arg'],
29
+ ['function', 'method', 'routine']
30
+ ];
31
+ }
32
+ prompt() {
33
+ return `${this.id}: flag any pair of words used interchangeably for one concept, and demand a single canonical term across the whole file`;
34
+ }
35
+ violations(document) {
36
+ const uri = document.uri();
37
+ const seen = this.groups.map(() => new Map());
38
+ document.walk({
39
+ header: () => [],
40
+ prose: (text, line) => this.collect(text, line, seen),
41
+ snippet: () => [],
42
+ bullets: () => [],
43
+ frontmatter: () => []
44
+ });
45
+ return this.report(seen, uri);
46
+ }
47
+ collect(text, line, seen) {
48
+ const masked = mask(text);
49
+ this.groups.forEach((group, index) => {
50
+ group.forEach((word) => {
51
+ const regex = new RegExp(`\\b${word}\\b`, 'iu');
52
+ if (regex.test(masked) && !seen[index].has(word)) {
53
+ seen[index].set(word, line);
54
+ }
55
+ });
56
+ });
57
+ return [];
58
+ }
59
+ report(seen, uri) {
60
+ const found = [];
61
+ seen.forEach((members) => {
62
+ if (members.size >= 2) {
63
+ const names = Array.from(members.keys());
64
+ const lines = Array.from(members.values());
65
+ found.push(new Violation(
66
+ this.id,
67
+ 'warning',
68
+ `concept named two ways ("${names[0]}"/"${names[1]}"), pick one term`,
69
+ new Region(uri, lines[1], 1)
70
+ ));
71
+ }
72
+ });
73
+ return found;
74
+ }
75
+ }
76
+
77
+ module.exports = Terms;
@@ -0,0 +1,61 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: Copyright (c) 2026 Yegor Bugayenko
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const Violation = require('../violation');
9
+ const Region = require('../region');
10
+ const mask = require('../mask');
11
+
12
+ /**
13
+ * ToolClarity.
14
+ *
15
+ * Demands the exact name of a tool or command, never a bare generic
16
+ * noun. An action verb such as "run", "use", or "invoke" pointed at
17
+ * "the script" or "a command" leaves the agent guessing which one. The
18
+ * mask blanks backticked spans first, so "run `npm test`" passes while
19
+ * "run the script" gets flagged. Its prompt defers subtler vague
20
+ * references to the AI oracle.
21
+ */
22
+ class ToolClarity {
23
+ constructor() {
24
+ this.id = 'tool-clarity';
25
+ }
26
+ prompt() {
27
+ return `${this.id}: flag any vague reference to a tool or command beyond the fixed list, and demand the exact name, path, or invocation instead`;
28
+ }
29
+ violations(document) {
30
+ const uri = document.uri();
31
+ return document.walk({
32
+ header: () => [],
33
+ prose: (text, line) => this.scan(text, line, uri),
34
+ snippet: () => [],
35
+ bullets: () => [],
36
+ frontmatter: () => []
37
+ });
38
+ }
39
+ scan(text, line, uri) {
40
+ const found = [];
41
+ const regex = new RegExp(
42
+ '\\b(?:run|use|call|invoke|execute|open)\\s+(?:the|a|an)\\s+' +
43
+ '(?:script|tool|command|api|file|function)\\b',
44
+ 'giu'
45
+ );
46
+ const masked = mask(text);
47
+ let hit = regex.exec(masked);
48
+ while (hit !== null) {
49
+ found.push(new Violation(
50
+ this.id,
51
+ 'warning',
52
+ `name the exact tool or command, not "${hit[0]}"`,
53
+ new Region(uri, line, hit.index + 1)
54
+ ));
55
+ hit = regex.exec(masked);
56
+ }
57
+ return found;
58
+ }
59
+ }
60
+
61
+ module.exports = ToolClarity;
@@ -0,0 +1,59 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: Copyright (c) 2026 Yegor Bugayenko
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const Violation = require('../violation');
9
+ const Region = require('../region');
10
+ const mask = require('../mask');
11
+
12
+ /**
13
+ * Untrusted.
14
+ *
15
+ * Guards against indirect prompt injection. When a line tells the agent
16
+ * to act on external content — a verb like "read", "fetch", "open",
17
+ * "follow", or "execute" applied to a "page", "url", "link", "email",
18
+ * "file", "issue", "output", or "comment" — that content can carry
19
+ * hidden instructions the agent then obeys. A standalone checker flags
20
+ * such a line when it lacks a data-only guard ("as data", "do not
21
+ * follow", "treat as untrusted", "inside delimiters"). Its prompt hands
22
+ * the deeper judgement of source trust and guard sufficiency to the AI
23
+ * oracle.
24
+ */
25
+ class Untrusted {
26
+ constructor() {
27
+ this.id = 'untrusted';
28
+ }
29
+ prompt() {
30
+ return `${this.id}: judge whether a consumed source is genuinely untrusted external input and whether its data-only guard is sufficient against prompt injection`;
31
+ }
32
+ violations(document) {
33
+ const uri = document.uri();
34
+ return document.walk({
35
+ header: () => [],
36
+ prose: (text, line) => this.scan(text, line, uri),
37
+ snippet: () => [],
38
+ bullets: () => [],
39
+ frontmatter: () => []
40
+ });
41
+ }
42
+ scan(text, line, uri) {
43
+ const masked = mask(text);
44
+ const verb = /\b(?:read|fetch|open|follow|execute)\b/iu;
45
+ const source = /\b(?:page|url|link|email|file|issue|output|comment)\b/iu;
46
+ const guard = /\b(?:as data|do not follow|treat as untrusted|inside delimiters|untrusted)\b/iu;
47
+ if (!verb.test(masked) || !source.test(masked) || guard.test(masked)) {
48
+ return [];
49
+ }
50
+ return [new Violation(
51
+ this.id,
52
+ 'warning',
53
+ 'untrusted input consumed without a data-only guard',
54
+ new Region(uri, line, 1)
55
+ )];
56
+ }
57
+ }
58
+
59
+ module.exports = Untrusted;
@@ -0,0 +1,63 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: Copyright (c) 2026 Yegor Bugayenko
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const Violation = require('../violation');
9
+ const Region = require('../region');
10
+ const mask = require('../mask');
11
+
12
+ /**
13
+ * Vague.
14
+ *
15
+ * Flags subjective, unmeasurable qualifiers that pretend to be precise:
16
+ * "properly", "good", "clean", "fast", "robust", and the like. Each
17
+ * leaves the agent to guess a criterion that varies run to run, so a
18
+ * vague qualifier is a non-instruction in disguise. The list is kept
19
+ * apart from the hedging words so the two rules never double-report. Its
20
+ * prompt hands subjective adjectives outside the fixed list to the AI
21
+ * oracle, asking it to suggest a concrete, checkable threshold.
22
+ */
23
+ class Vague {
24
+ constructor() {
25
+ this.id = 'vague';
26
+ }
27
+ prompt() {
28
+ return `${this.id}: flag any subjective or unmeasurable qualifier beyond the fixed list, and propose a concrete, checkable threshold to replace it`;
29
+ }
30
+ violations(document) {
31
+ const uri = document.uri();
32
+ return document.walk({
33
+ header: () => [],
34
+ prose: (text, line) => this.scan(text, line, uri),
35
+ snippet: () => [],
36
+ bullets: () => [],
37
+ frontmatter: () => []
38
+ });
39
+ }
40
+ scan(text, line, uri) {
41
+ const found = [];
42
+ const regex = new RegExp(
43
+ '\\b(?:properly|correctly|appropriately|good|clean|fast|slow|' +
44
+ 'large|small|robust|reasonable|efficient|as much as possible|' +
45
+ 'if needed)\\b',
46
+ 'giu'
47
+ );
48
+ const masked = mask(text);
49
+ let hit = regex.exec(masked);
50
+ while (hit !== null) {
51
+ found.push(new Violation(
52
+ this.id,
53
+ 'warning',
54
+ `vague qualifier "${hit[0]}" carries no measurable criterion`,
55
+ new Region(uri, line, hit.index + 1)
56
+ ));
57
+ hit = regex.exec(masked);
58
+ }
59
+ return found;
60
+ }
61
+ }
62
+
63
+ module.exports = Vague;
package/src/version.js CHANGED
@@ -9,8 +9,8 @@
9
9
  * Version.
10
10
  *
11
11
  * The current release of dogent, replaced on every release by rultor.
12
- * The default `0.9.0` marks an unreleased build straight from source.
12
+ * The default `0.10.0` marks an unreleased build straight from source.
13
13
  */
14
- const version = '0.9.0';
14
+ const version = '0.10.0';
15
15
 
16
16
  module.exports = version;