net-snmp 3.26.0 → 3.26.2
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/.claude/skills/git-commit/SKILL.md +54 -0
- package/.claude/skills/prepare-release/SKILL.md +97 -0
- package/README.md +8 -0
- package/example/mib-parser.js +3 -3
- package/index.js +13 -1
- package/package.json +1 -1
- package/test/mib.test.js +10 -0
- package/test/oid-in-subtree.test.js +36 -0
- package/test/subagent.test.js +18 -10
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-commit
|
|
3
|
+
description: Creates a git commit summarizing all current working tree changes (staged and unstaged). Use when the user asks to commit, save progress, or invoke /git-commit.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Git Commit
|
|
7
|
+
|
|
8
|
+
## When to use
|
|
9
|
+
|
|
10
|
+
- When the user asks to commit current changes.
|
|
11
|
+
- When invoked via `/git-commit`.
|
|
12
|
+
|
|
13
|
+
## Arguments
|
|
14
|
+
|
|
15
|
+
- `dry-run` — perform steps 1–3 only (gather context, identify files, draft commit message) and then **ask the user** whether to proceed with the actual commit or cancel. Do **not** stage or commit until the user confirms.
|
|
16
|
+
|
|
17
|
+
## Workflow
|
|
18
|
+
|
|
19
|
+
1. **Gather context** — run these commands in parallel:
|
|
20
|
+
- `git status` — to see all tracked modifications and untracked files.
|
|
21
|
+
- `git diff` and `git diff --cached` — to see unstaged and staged changes.
|
|
22
|
+
- `git log --oneline -10` — to match the repository's commit message style.
|
|
23
|
+
|
|
24
|
+
2. **Stage all relevant changes** — add all modified and untracked files that are part of the current work. Use specific file paths rather than `git add -A`. Do **not** stage files that likely contain secrets (`.env`, credentials, etc.) — warn the user if any are present.
|
|
25
|
+
|
|
26
|
+
3. **Draft the commit message** — analyse the diff and write a concise commit message:
|
|
27
|
+
- One summary line (imperative mood, under 72 characters) describing the *why* / *what* of the change.
|
|
28
|
+
- If the change is non-trivial, add a blank line followed by bullet points elaborating key changes.
|
|
29
|
+
- **Don't pad small commits**: if the summary line already captures the change, omit the body entirely. Most single-purpose commits need only the summary line.
|
|
30
|
+
- **Stay high-level**: never reference code-level details like variable names, function names, method calls, or file paths in the commit message. Describe *what changed for the user or system*, not *which functions were modified*.
|
|
31
|
+
- Match the style and conventions visible in the recent git log.
|
|
32
|
+
|
|
33
|
+
4. **Commit** — create the commit using a heredoc for the message:
|
|
34
|
+
```bash
|
|
35
|
+
git commit -m "$(cat <<'EOF'
|
|
36
|
+
<summary line>
|
|
37
|
+
|
|
38
|
+
<optional body>
|
|
39
|
+
EOF
|
|
40
|
+
)"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
5. **Verify** — run `git status` after the commit to confirm it succeeded and the working tree is clean (or shows only intentionally unstaged files).
|
|
44
|
+
|
|
45
|
+
6. **Show the commit** — run `git log -1` and display the **entire** commit message (summary line and body) to the user so they can review it. Do not truncate or abbreviate — if the message has bullet points or a multi-line body, include all of it in your response.
|
|
46
|
+
|
|
47
|
+
## Rules
|
|
48
|
+
|
|
49
|
+
- Never amend an existing commit unless the user explicitly asks.
|
|
50
|
+
- Never push to the remote unless the user explicitly asks.
|
|
51
|
+
- Never use `--no-verify` or skip pre-commit hooks.
|
|
52
|
+
- If a pre-commit hook fails, fix the issue, re-stage, and create a **new** commit (do not amend).
|
|
53
|
+
- Never stage `.env`, credential files, or other secrets.
|
|
54
|
+
- Never add `Co-Authored-By`, `Authored-By`, `Made-with` or any other attribution trailer to commit messages.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: prepare-release
|
|
3
|
+
description: Prepare a release by running lint + tests, bumping the package.json version, and appending a version summary to README.md. Use when the user asks to "prepare a release", "cut a release", or invokes /prepare-release. Stops immediately on lint/test failure so the user can fix issues before continuing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Prepare Release
|
|
7
|
+
|
|
8
|
+
## When to use
|
|
9
|
+
|
|
10
|
+
- User asks to prepare / cut a release.
|
|
11
|
+
- User invokes `/prepare-release`.
|
|
12
|
+
- Immediately before the release commit — this skill stages no files and creates no commit; hand off to `/git-commit` afterwards.
|
|
13
|
+
|
|
14
|
+
## Release model
|
|
15
|
+
|
|
16
|
+
The release content is the union of **(a)** commits since the last tag and **(b)** uncommitted user-facing changes in the working tree. Both are valid sources; the typical flow is that the fix being released sits uncommitted alongside the version bump and README update, and the user then commits them all together in a single release commit.
|
|
17
|
+
|
|
18
|
+
Consequences:
|
|
19
|
+
- Do **not** object to uncommitted changes in the working tree — they are expected and are part of what is being released. Treat them as release content, not as a blocker.
|
|
20
|
+
- Do **not** require at least one committed change since the last tag. The release may consist entirely of working-tree changes that have not yet been committed.
|
|
21
|
+
- When drafting the README bullets in step 5, summarise the user-facing changes visible across **both** sources (committed commits since the last tag **and** the diff of the working tree before this skill began modifying it).
|
|
22
|
+
- The only changes this skill itself creates are in `package.json`, `package-lock.json`, and `README.md`. Everything else in the working tree was already the user's in-progress release content.
|
|
23
|
+
|
|
24
|
+
## Arguments
|
|
25
|
+
|
|
26
|
+
- `patch` (default) — bumps the patch component, e.g. `3.26.1` → `3.26.2`.
|
|
27
|
+
- `minor` — bumps the minor component and resets patch, e.g. `3.26.1` → `3.27.0`.
|
|
28
|
+
- `major` — bumps the major component and resets minor/patch, e.g. `3.26.1` → `4.0.0`.
|
|
29
|
+
|
|
30
|
+
If the user supplies anything else, stop and ask for clarification.
|
|
31
|
+
|
|
32
|
+
## Workflow
|
|
33
|
+
|
|
34
|
+
Run steps in order. **If any step fails, stop immediately, report the failure, and do not proceed.** Do not modify `package.json`, `package-lock.json`, or `README.md` until lint and tests pass.
|
|
35
|
+
|
|
36
|
+
### 1. Pre-flight checks (parallel)
|
|
37
|
+
|
|
38
|
+
- `git status --short` — capture the working tree state. Per the release model above, treat uncommitted changes as part of the release content, not as a blocker. Still surface the list to the user so they can spot anything that looks unintended (e.g. a modified file they don't remember touching) before the eventual release commit.
|
|
39
|
+
- `git rev-parse --abbrev-ref HEAD` — confirm the current branch. If it is not `master`, warn the user and ask whether to continue.
|
|
40
|
+
- `git log --oneline $(git describe --tags --abbrev=0 2>/dev/null || git log --format=%H | tail -1)..HEAD` — collect commits since the last tag (or since the beginning if no tags exist). These feed the README summary in step 5 alongside the working-tree diff.
|
|
41
|
+
- `git diff` and `git diff --cached` — capture the uncommitted user-facing changes. These also feed the README summary in step 5.
|
|
42
|
+
- Read current version from `package.json`.
|
|
43
|
+
|
|
44
|
+
Only stop at pre-flight if **both** the commit list and the uncommitted diff are empty — in that case there is genuinely nothing to release.
|
|
45
|
+
|
|
46
|
+
### 2. Lint
|
|
47
|
+
|
|
48
|
+
Run `npm run lint`. **Stop on non-zero exit.** Report the linter output verbatim and do not continue.
|
|
49
|
+
|
|
50
|
+
### 3. Tests
|
|
51
|
+
|
|
52
|
+
Run `npm test`. **Stop on non-zero exit.**
|
|
53
|
+
|
|
54
|
+
Exception: the `Subagent` tests in `test/subagent.test.js` require a locally-running AgentX master (`snmpd`) and will fail with `ECONNREFUSED` if one is not present. If the only failures are Subagent `ECONNREFUSED` failures, report them and ask the user whether to proceed (they may have intentionally skipped running snmpd). All other failures are hard stops.
|
|
55
|
+
|
|
56
|
+
### 4. Bump version
|
|
57
|
+
|
|
58
|
+
Run `npm version <patch|minor|major> --no-git-tag-version`. This updates both `package.json` and `package-lock.json` atomically without creating a commit or tag. Capture the new version string for the README entry.
|
|
59
|
+
|
|
60
|
+
If the argument was omitted, default to `patch`.
|
|
61
|
+
|
|
62
|
+
### 5. Append README version summary
|
|
63
|
+
|
|
64
|
+
- Read `README.md`.
|
|
65
|
+
- Locate the `# License` heading near the end.
|
|
66
|
+
- Insert a new version section **immediately before** `# License`, separated by a blank line above and below, in exactly this format:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
# Version X.Y.Z - DD/MM/YYYY
|
|
70
|
+
|
|
71
|
+
* <concise user-facing summary of change 1>
|
|
72
|
+
|
|
73
|
+
* <concise user-facing summary of change 2>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Notes:
|
|
77
|
+
- Date is **today's date** in `DD/MM/YYYY` (day/month/year) — use the date from the environment, not a hardcoded value.
|
|
78
|
+
- Each bullet begins with a single space, then `*`, then a space. There is a blank line between bullets (match the style of the existing entries).
|
|
79
|
+
- Bullets describe **user-visible changes** — not refactors, lint fixes, test additions, or internal tidy-ups. Write them like release notes, not commit subjects. Draw from **both** the commit list gathered in step 1 and the uncommitted working-tree diff; merge/reword where helpful so each line stands on its own.
|
|
80
|
+
- If there is only one user-visible change, include just one bullet.
|
|
81
|
+
- Do not touch any other part of `README.md`.
|
|
82
|
+
|
|
83
|
+
### 6. Summary
|
|
84
|
+
|
|
85
|
+
Report to the user, concisely:
|
|
86
|
+
- New version number.
|
|
87
|
+
- Bullets added to `README.md`.
|
|
88
|
+
- The full list of uncommitted files now staged for the release commit — both the pre-existing working-tree changes and the three files this skill modified (`package.json`, `package-lock.json`, `README.md`). Flag anything that looks unexpected.
|
|
89
|
+
|
|
90
|
+
Do **not** run `git add`, `git commit`, `git tag`, or `npm publish` — those are the user's decision. The next step is typically `/git-commit`.
|
|
91
|
+
|
|
92
|
+
## Things to watch for
|
|
93
|
+
|
|
94
|
+
- If `npm version` fails because the working tree is dirty, it has not been run with `--no-git-tag-version` correctly — re-check the command.
|
|
95
|
+
- If the README insertion point (`# License`) cannot be found, stop and ask the user — do not guess.
|
|
96
|
+
- If the lint or test commands are missing from `package.json`, stop and report.
|
|
97
|
+
- Never bypass a failing check with `--no-verify`, `SKIP=`, or similar; the user must fix the underlying issue.
|
package/README.md
CHANGED
|
@@ -3715,6 +3715,14 @@ Example programs are included under the module's `example` directory.
|
|
|
3715
3715
|
|
|
3716
3716
|
* Add strict integer range checking as optional
|
|
3717
3717
|
|
|
3718
|
+
# Version 3.26.1 - 21/01/2026
|
|
3719
|
+
|
|
3720
|
+
* Fix deleteTableRow string index handling
|
|
3721
|
+
|
|
3722
|
+
# Version 3.26.2 - 21/04/2026
|
|
3723
|
+
|
|
3724
|
+
* Fix TypeError in oidInSubtree when varbind OID is null
|
|
3725
|
+
|
|
3718
3726
|
# License
|
|
3719
3727
|
|
|
3720
3728
|
Copyright (c) 2020 Mark Abrahams <mark@abrahams.co.nz>
|
package/example/mib-parser.js
CHANGED
|
@@ -58,7 +58,7 @@ var ifEntryRow1 = mib.getTableRowCells ("ifEntry", [2]);
|
|
|
58
58
|
// ifXEntry
|
|
59
59
|
// AUGMENTS ifEntry - meaning a single integer foreign key
|
|
60
60
|
mib.addTableRow ("ifXEntry", [1, "eth0", 10, 2, 20, 4, counter64(1000), counter64(100), counter64(50), counter64(20),
|
|
61
|
-
counter64(2000), counter64(200), counter64(100), counter64(40), 1, 1000,
|
|
61
|
+
counter64(2000), counter64(200), counter64(100), counter64(40), 1, 1000, 1, 1, "myeth0", 10]);
|
|
62
62
|
var ifXEntryRow1 = mib.getTableRowCells ("ifXEntry", [1]);
|
|
63
63
|
// console.log (ifXEntryRow1);
|
|
64
64
|
var ifXEntryData1 = mib.getTableCells ("ifXEntry", false, false);
|
|
@@ -83,7 +83,7 @@ var ifStackEntryCell1 = mib.getTableSingleCell ("ifStackEntry", 3, [1, 2]);
|
|
|
83
83
|
|
|
84
84
|
// ifRcvAddressEntry
|
|
85
85
|
// Composite index - one foreign integer column, one local string column
|
|
86
|
-
mib.addTableRow ("ifRcvAddressEntry", [1, "24:41:8c:08:87:5c", 1,
|
|
86
|
+
mib.addTableRow ("ifRcvAddressEntry", [1, "24:41:8c:08:87:5c", 1, 1]);
|
|
87
87
|
var ifRcvAddressEntryRow1 = mib.getTableRowCells ("ifRcvAddressEntry", [1, "24:41:8c:08:87:5c"]);
|
|
88
88
|
var ifRcvAddressEntryCell1 = mib.getTableSingleCell ("ifRcvAddressEntry", 3, [1, "24:41:8c:08:87:5c"]);
|
|
89
89
|
var ifRcvAddressEntryData1 = mib.getTableCells ("ifRcvAddressEntry", false, false);
|
|
@@ -114,7 +114,7 @@ mib.addTableRow ("sysOREntry", [1, "1.3.6.1.4.1.47491.42.43.44.45", "I've dreame
|
|
|
114
114
|
// mib.dump ();
|
|
115
115
|
|
|
116
116
|
var modules = store.getModules (true);
|
|
117
|
-
var one = store.getModule ("SNMPv2-
|
|
117
|
+
var one = store.getModule ("SNMPv2-SMI");
|
|
118
118
|
var names = store.getModuleNames (true);
|
|
119
119
|
|
|
120
120
|
// console.log("All modules: ", JSON.stringify(modules, '', 2));
|
package/index.js
CHANGED
|
@@ -389,6 +389,9 @@ function oidFollowsOid (oidString, nextString) {
|
|
|
389
389
|
}
|
|
390
390
|
|
|
391
391
|
function oidInSubtree (oidString, nextString) {
|
|
392
|
+
if ( ! nextString ) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
392
395
|
var oid = oidString.split (".");
|
|
393
396
|
var next = nextString.split (".");
|
|
394
397
|
|
|
@@ -4619,7 +4622,13 @@ Mib.prototype.getTableRowInstanceFromRowIndex = function (provider, rowIndex) {
|
|
|
4619
4622
|
var keyPart;
|
|
4620
4623
|
for ( var i = 0; i < provider.tableIndex.length ; i++ ) {
|
|
4621
4624
|
indexPart = provider.tableIndex[i];
|
|
4622
|
-
|
|
4625
|
+
// If rowIndex is a string and there's only one index part, use the string directly
|
|
4626
|
+
// Otherwise, use rowIndex[i] (for arrays or when there are multiple index parts)
|
|
4627
|
+
if ( typeof rowIndex === 'string' && provider.tableIndex.length === 1 ) {
|
|
4628
|
+
keyPart = rowIndex;
|
|
4629
|
+
} else {
|
|
4630
|
+
keyPart = rowIndex[i];
|
|
4631
|
+
}
|
|
4623
4632
|
rowIndexOid = rowIndexOid.concat (this.getOidAddressFromValue (keyPart, indexPart));
|
|
4624
4633
|
}
|
|
4625
4634
|
return rowIndexOid;
|
|
@@ -6880,6 +6889,9 @@ exports.ObjectParser = {
|
|
|
6880
6889
|
readUint32: readUint32,
|
|
6881
6890
|
readVarbindValue: readVarbindValue
|
|
6882
6891
|
};
|
|
6892
|
+
exports.OidUtil = {
|
|
6893
|
+
oidInSubtree: oidInSubtree
|
|
6894
|
+
};
|
|
6883
6895
|
exports.ObjectTypeUtil = ObjectTypeUtil;
|
|
6884
6896
|
exports.Authentication = Authentication;
|
|
6885
6897
|
exports.Encryption = Encryption;
|
package/package.json
CHANGED
package/test/mib.test.js
CHANGED
|
@@ -113,6 +113,16 @@ describe('MIB', function () {
|
|
|
113
113
|
const data = mib.getTableCells('testEntry1', true, true);
|
|
114
114
|
assert.deepEqual(data, [[ [2], 'CellValue2']]);
|
|
115
115
|
});
|
|
116
|
+
|
|
117
|
+
it('deletes a table row with string index', function () {
|
|
118
|
+
const row1 = ['ABC', 100];
|
|
119
|
+
const row2 = ['XYZ', 200];
|
|
120
|
+
mib.addTableRow('testEntry2', row1);
|
|
121
|
+
mib.addTableRow('testEntry2', row2);
|
|
122
|
+
mib.deleteTableRow('testEntry2', 'ABC');
|
|
123
|
+
const data = mib.getTableCells('testEntry2', true, true);
|
|
124
|
+
assert.deepEqual(data, [[ ['XYZ'], 200]]);
|
|
125
|
+
});
|
|
116
126
|
});
|
|
117
127
|
|
|
118
128
|
describe('registerProvider() - scalar defVal', function () {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const snmp = require('..');
|
|
3
|
+
|
|
4
|
+
const oidInSubtree = snmp.OidUtil.oidInSubtree;
|
|
5
|
+
|
|
6
|
+
describe('oidInSubtree()', function () {
|
|
7
|
+
|
|
8
|
+
it('returns true when nextString is in the subtree', function () {
|
|
9
|
+
assert.strictEqual(oidInSubtree('1.3.6.1.2.1', '1.3.6.1.2.1.1.1.0'), true);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('returns true when oidString equals nextString', function () {
|
|
13
|
+
assert.strictEqual(oidInSubtree('1.3.6.1.2.1', '1.3.6.1.2.1'), true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('returns false when nextString is outside the subtree', function () {
|
|
17
|
+
assert.strictEqual(oidInSubtree('1.3.6.1.2.1', '1.3.6.1.4.1.9'), false);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('returns false when nextString is shorter than oidString', function () {
|
|
21
|
+
assert.strictEqual(oidInSubtree('1.3.6.1.2.1', '1.3.6.1'), false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('returns false when nextString is null (issue #298)', function () {
|
|
25
|
+
assert.strictEqual(oidInSubtree('1.3.6.1.2.1', null), false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('returns false when nextString is undefined', function () {
|
|
29
|
+
assert.strictEqual(oidInSubtree('1.3.6.1.2.1', undefined), false);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('returns false when nextString is an empty string', function () {
|
|
33
|
+
assert.strictEqual(oidInSubtree('1.3.6.1.2.1', ''), false);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
});
|
package/test/subagent.test.js
CHANGED
|
@@ -5,38 +5,46 @@ const snmp = require('..');
|
|
|
5
5
|
describe('Subagent', function() {
|
|
6
6
|
let subagent;
|
|
7
7
|
let mockSocket;
|
|
8
|
-
let
|
|
8
|
+
let originalSocket;
|
|
9
|
+
|
|
10
|
+
function MockSocket() {
|
|
11
|
+
this.connect = () => {};
|
|
12
|
+
this.on = () => this;
|
|
13
|
+
this.write = () => {};
|
|
14
|
+
this.end = () => {};
|
|
15
|
+
this.destroy = () => {};
|
|
16
|
+
}
|
|
9
17
|
|
|
10
18
|
beforeEach(function() {
|
|
11
|
-
//
|
|
12
|
-
|
|
19
|
+
// Stub net.Socket so createSubagent does not open a real TCP connection
|
|
20
|
+
originalSocket = net.Socket;
|
|
21
|
+
net.Socket = MockSocket;
|
|
22
|
+
|
|
13
23
|
mockSocket = {
|
|
14
24
|
connect: () => {},
|
|
15
25
|
on: () => {},
|
|
16
26
|
write: () => {},
|
|
17
27
|
end: () => {}
|
|
18
28
|
};
|
|
19
|
-
|
|
20
|
-
// Use the factory method instead of constructor
|
|
29
|
+
|
|
21
30
|
subagent = snmp.createSubagent({
|
|
22
31
|
master: 'localhost',
|
|
23
32
|
masterPort: 705,
|
|
24
33
|
timeout: 5,
|
|
25
34
|
description: 'Test Subagent'
|
|
26
35
|
});
|
|
27
|
-
|
|
28
|
-
// Mock socket connection to avoid actual networking
|
|
36
|
+
|
|
29
37
|
subagent.socket = mockSocket;
|
|
30
38
|
subagent.sessionID = 123;
|
|
31
39
|
});
|
|
32
40
|
|
|
33
41
|
afterEach(function() {
|
|
34
|
-
if (mockServer) {
|
|
35
|
-
mockServer.close();
|
|
36
|
-
}
|
|
37
42
|
if (subagent && typeof subagent.close === 'function') {
|
|
38
43
|
subagent.close();
|
|
39
44
|
}
|
|
45
|
+
if (originalSocket) {
|
|
46
|
+
net.Socket = originalSocket;
|
|
47
|
+
}
|
|
40
48
|
});
|
|
41
49
|
|
|
42
50
|
describe('Constructor', function() {
|