net-snmp 3.26.1 → 3.26.3
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/.claude/skills/propose-action/SKILL.md +111 -0
- package/.claude/skills/publish-release/SKILL.md +68 -0
- package/README.md +37 -1
- package/index.js +6 -0
- package/package.json +1 -1
- 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.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: propose-action
|
|
3
|
+
description: Review a GitHub issue or PR by number and propose a concrete action plan — either a reasoned recommendation not to action it, or the code and test changes required to action it. Use when the user asks to "propose an action" for an issue/PR, "look at issue/PR #N", or invokes /propose-action with an issue or PR number. Ends by asking whether to proceed, proceed with modifications, or abandon.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Propose Action
|
|
7
|
+
|
|
8
|
+
## When to use
|
|
9
|
+
|
|
10
|
+
- The user asks to review a GitHub issue or PR and recommend what to do about it.
|
|
11
|
+
- The user invokes `/propose-action <number>`.
|
|
12
|
+
|
|
13
|
+
This skill **plans only** for steps 1–5 — it does not edit code, run tests, commit, push, or comment on the issue/PR during the proposal phase. Implementation happens after the user approves the plan in step 5's closing question. Once the user has approved and you have carried out the agreed actions, step 6 produces a ready-to-paste reply to the issue/PR aligned with what was actually done — but never posts it.
|
|
14
|
+
|
|
15
|
+
## Arguments
|
|
16
|
+
|
|
17
|
+
- `<number>` (required) — the GitHub issue or PR number. Bare integer, or `#N`, or a full GitHub URL are all acceptable forms.
|
|
18
|
+
|
|
19
|
+
If the number is missing, ambiguous, or does not resolve to an issue/PR in the current repository, stop and ask the user to clarify.
|
|
20
|
+
|
|
21
|
+
## Workflow
|
|
22
|
+
|
|
23
|
+
### 1. Identify the target
|
|
24
|
+
|
|
25
|
+
- Determine the current repository: `gh repo view --json nameWithOwner -q .nameWithOwner`.
|
|
26
|
+
- Resolve the number to either an issue or a PR. GitHub numbers them in the same namespace, so try PR first, then issue:
|
|
27
|
+
- `gh pr view <number> --json number,title,state,author,body,headRefName,baseRefName,isDraft,mergeable,additions,deletions,changedFiles,labels,comments,reviews`
|
|
28
|
+
- If that fails, `gh issue view <number> --json number,title,state,author,body,labels,comments,assignees`
|
|
29
|
+
- Record whether the target is an **issue** or a **PR** — the two branches below differ.
|
|
30
|
+
|
|
31
|
+
### 2a. If the target is an issue
|
|
32
|
+
|
|
33
|
+
Gather context in parallel:
|
|
34
|
+
- The issue body and all comments (from the `gh issue view` JSON above).
|
|
35
|
+
- `gh issue view <number> --json linkedPullRequests` — check for linked PRs that may already address it.
|
|
36
|
+
- Identify the files or subsystems the issue points at. Search the repo (`Grep`, `Glob`, `Read`) for the relevant code. Do not guess — read the actual files the issue describes.
|
|
37
|
+
- If the issue references specific OIDs, error messages, function names, or SNMP behaviours, locate them in the source.
|
|
38
|
+
|
|
39
|
+
### 2b. If the target is a PR
|
|
40
|
+
|
|
41
|
+
Gather context in parallel:
|
|
42
|
+
- PR body, comments, and reviews (from the `gh pr view` JSON above).
|
|
43
|
+
- `gh pr diff <number>` — the full diff.
|
|
44
|
+
- `gh pr view <number> --json files -q '.files[].path'` — changed files.
|
|
45
|
+
- Read the **current** version of each changed file on the base branch so you understand what the PR is replacing, not just what it adds.
|
|
46
|
+
- If the PR closes or references an issue (via `Fixes #N`, `Closes #N`, etc.), also fetch that issue for context.
|
|
47
|
+
- Check CI status if available: `gh pr checks <number>`.
|
|
48
|
+
|
|
49
|
+
### 3. Form a judgement
|
|
50
|
+
|
|
51
|
+
Decide which of these recommendations fits, and be willing to recommend **against** actioning:
|
|
52
|
+
|
|
53
|
+
- **Do not action** — the issue is invalid, already fixed, out of scope, based on a misunderstanding, a duplicate, or the PR is the wrong approach / would regress behaviour / conflicts with project direction. Explain *why* clearly, citing the code or prior commits that support the conclusion.
|
|
54
|
+
- **Action as-is** — the issue is valid and the fix is clear, or the PR is correct and should be merged as submitted.
|
|
55
|
+
- **Action with modifications** — the issue is valid but the obvious fix is wrong; or the PR has the right idea but needs specific changes before it can be merged.
|
|
56
|
+
- **Needs more information** — the report is plausible but underspecified. List the exact questions to ask the reporter / author before any code change is possible.
|
|
57
|
+
|
|
58
|
+
Base the judgement on what the code actually does today, not on what the issue/PR claims. If the two disagree, surface the disagreement.
|
|
59
|
+
|
|
60
|
+
### 4. Draft the proposal
|
|
61
|
+
|
|
62
|
+
Structure the written proposal in this order. Keep it concrete — name files, line numbers, function names, and the specific behaviours being changed.
|
|
63
|
+
|
|
64
|
+
1. **Target** — `Issue #N: <title>` or `PR #N: <title>`, plus one sentence on its state (open/closed/draft/merged, CI status for PRs).
|
|
65
|
+
2. **Summary of the report** — one short paragraph in your own words describing what the reporter is asking for or proposing. Do not just quote the body.
|
|
66
|
+
3. **Findings** — what the code currently does, whether the report is accurate, and any related context (linked issues/PRs, prior commits, existing tests covering this area). Cite `file:line` locations.
|
|
67
|
+
4. **Recommendation** — one of the four options from step 3, stated plainly in a sentence or two.
|
|
68
|
+
5. **Proposed changes** (omit if the recommendation is *do not action* or *needs more information*):
|
|
69
|
+
- **Code** — for each file to change, list the edit as a bullet: `path/to/file.js:<line-range> — <what changes and why>`. For non-trivial edits, include a short before/after sketch (a few lines, not a full diff).
|
|
70
|
+
- **Tests** — list tests to **add**, **modify**, or **delete**, each with the file and a one-line description of what the test asserts. If no test changes are needed, say so explicitly and justify (e.g. "covered by existing test at `test/x.test.js:42`").
|
|
71
|
+
- **Docs / README** — note any README or inline-doc updates required. Release-note bullets are handled by `/prepare-release`; do not pre-empt them here.
|
|
72
|
+
6. **Risks and unknowns** — anything that could make the plan wrong: behaviours you could not verify, edge cases the tests would not catch, compatibility concerns, or assumptions about the reporter's environment.
|
|
73
|
+
7. **Out of scope** — closely-related issues you noticed while investigating but are **not** proposing to fix in this action. Keeps the scope honest.
|
|
74
|
+
|
|
75
|
+
### 5. Closing question
|
|
76
|
+
|
|
77
|
+
End the response with exactly one question, offering three choices:
|
|
78
|
+
|
|
79
|
+
> Proceed with this plan as-is, proceed with modifications (tell me what to change), or abandon it?
|
|
80
|
+
|
|
81
|
+
Do not start implementing until the user answers. If the user says "proceed", begin implementing the plan in the next turn. If the user asks for modifications, revise the proposal and ask the same question again. If the user says to abandon, stop and skip step 6.
|
|
82
|
+
|
|
83
|
+
### 6. Ready-to-paste issue/PR reply
|
|
84
|
+
|
|
85
|
+
After the agreed actions have been carried out (code edits, tests, docs, or a reasoned decision not to action), produce a single ready-to-paste reply for the issue/PR. This is the **last** thing you output, rendered in a fenced block or delimited by `---` so the user can copy it cleanly.
|
|
86
|
+
|
|
87
|
+
The reply must be aligned with **what actually happened**, not with the original plan — if the user asked for modifications during implementation, reflect the modified outcome. If a step was skipped or failed, say so honestly; do not describe work that was not done.
|
|
88
|
+
|
|
89
|
+
Tailor the content to the recommendation from step 3:
|
|
90
|
+
|
|
91
|
+
- **Action as-is / with modifications** — acknowledge the report, give the user a short, concrete summary of the fix (with the key code change or snippet inline if it helps them adopt it), point at the files/sections that changed (e.g. "updated in `README.md` under *Scalar providers*"), and note when it will ship (e.g. "will land in the next release" — do not invent a version number unless `package.json` has already been bumped). If there's a workaround the reporter can apply before the release, include it.
|
|
92
|
+
- **Do not action** — explain the reasoning in the reporter's terms, citing the code or prior history that supports the decision. Be respectful: the reporter put effort into the report. Offer an alternative path if one exists (a different API, a related issue, a config change). If the issue should be closed, say so; do not close it yourself.
|
|
93
|
+
- **Needs more information** — list the specific questions you need answered, each as its own bullet. Explain briefly *why* each is needed so the reporter can see what would unblock progress.
|
|
94
|
+
|
|
95
|
+
Style:
|
|
96
|
+
|
|
97
|
+
- Match the tone of prior replies in this repository if they are visible in the issue/PR thread — don't suddenly adopt a different register.
|
|
98
|
+
- Write as the maintainer would: first person, conversational, no corporate voice, no marketing copy, no emoji unless the repo's existing replies use them.
|
|
99
|
+
- Do not include a signature, do not add attribution trailers (no "generated by", no `Co-Authored-By`), do not tag the reporter more than once.
|
|
100
|
+
- Keep it focused — one screen of text is almost always enough. If the reply needs code blocks, prefer short, complete snippets over long diffs.
|
|
101
|
+
|
|
102
|
+
Hand the reply to the user with one sentence above it saying where to paste it (e.g. "Ready-to-paste reply for issue #297:"). Do **not** run `gh issue comment` / `gh pr comment` / `gh issue close` / `gh pr merge` — the user posts it.
|
|
103
|
+
|
|
104
|
+
## Rules
|
|
105
|
+
|
|
106
|
+
- **Never** edit files, run tests, or modify git state during steps 1–5. Planning only.
|
|
107
|
+
- **Never** post a comment on the issue/PR, add labels, request reviews, merge, or close — not in step 6, not ever within this skill. Those are the user's decision.
|
|
108
|
+
- **Never** fabricate line numbers or function names — if you cite `file:line`, you must have read it.
|
|
109
|
+
- If `gh` is not authenticated or the number does not exist, stop and report the error verbatim.
|
|
110
|
+
- If the issue/PR is in a different repository than the current working directory, stop and confirm with the user before proceeding — the plan would target the wrong codebase.
|
|
111
|
+
- Keep the proposal focused. A plan that touches ten files for a one-line bug is a signal to re-read the issue, not to write a bigger plan.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: publish-release
|
|
3
|
+
description: Publish the currently-committed release by pushing master to origin, publishing to npm, tagging the commit with the package.json version, and pushing the tag. Use when the user asks to "publish the release", "push and publish", or invokes /publish-release. Stops immediately on any failure.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Publish Release
|
|
7
|
+
|
|
8
|
+
## When to use
|
|
9
|
+
|
|
10
|
+
- After `/prepare-release` and the release commit have both been completed — this skill assumes the release commit (version bump + README entry + fix) is already `HEAD` on `master`.
|
|
11
|
+
- User asks to publish / ship / release to npm.
|
|
12
|
+
- User invokes `/publish-release`.
|
|
13
|
+
|
|
14
|
+
Run after `/prepare-release` + `/git-commit`, never in place of them. This skill does not run lint, tests, or modify any files.
|
|
15
|
+
|
|
16
|
+
## Workflow
|
|
17
|
+
|
|
18
|
+
Run steps in order. **If any step fails, stop immediately, report the failure, and do not proceed.** There is no rollback — each step is externally observable (a push, a publish, a tag on origin), so a mid-flight failure leaves the release in a partial state the user will need to reason about. Be explicit about which steps succeeded and which did not.
|
|
19
|
+
|
|
20
|
+
### 1. Pre-flight checks (parallel)
|
|
21
|
+
|
|
22
|
+
- `git rev-parse --abbrev-ref HEAD` — confirm the current branch is `master`. If not, stop and ask the user.
|
|
23
|
+
- `git status --short` — confirm the working tree is clean. If not, stop — the release commit must already exist as `HEAD`, with nothing else pending.
|
|
24
|
+
- Read the current version from `package.json` (this becomes the tag name).
|
|
25
|
+
- `git tag --list <version>` — confirm the tag does not already exist locally. If it does, stop.
|
|
26
|
+
- `git ls-remote --tags origin refs/tags/<version>` — confirm the tag does not already exist on the remote. If it does, stop.
|
|
27
|
+
- `git log -1 --format=%s` — capture the subject of the HEAD commit for the summary.
|
|
28
|
+
|
|
29
|
+
### 2. Push master to origin
|
|
30
|
+
|
|
31
|
+
Run `git push origin master`. **Stop on non-zero exit.** Report the output.
|
|
32
|
+
|
|
33
|
+
### 3. Publish to npm
|
|
34
|
+
|
|
35
|
+
Run `npm publish`. **Stop on non-zero exit.**
|
|
36
|
+
|
|
37
|
+
Notes:
|
|
38
|
+
- If the registry prompts for a one-time password (2FA OTP), relay the prompt to the user and wait for their input. Do not attempt to bypass 2FA.
|
|
39
|
+
- If the registry rejects with `403` or `You do not have permission`, stop and surface the full error — the user may need to `npm login` or check their credentials.
|
|
40
|
+
- If the registry rejects with `You cannot publish over the previously published versions`, stop — the version was not bumped correctly upstream of this skill.
|
|
41
|
+
|
|
42
|
+
### 4. Tag the release
|
|
43
|
+
|
|
44
|
+
Tags in this repo are bare version numbers (no `v` prefix) — verified against the existing tag list.
|
|
45
|
+
|
|
46
|
+
Run `git tag <version>` where `<version>` is the exact value read from `package.json` in step 1 (e.g., `3.26.2`, not `v3.26.2`).
|
|
47
|
+
|
|
48
|
+
**Stop on non-zero exit.**
|
|
49
|
+
|
|
50
|
+
### 5. Push the tag
|
|
51
|
+
|
|
52
|
+
Run `git push origin <version>`. **Stop on non-zero exit.**
|
|
53
|
+
|
|
54
|
+
### 6. Summary
|
|
55
|
+
|
|
56
|
+
Report to the user, concisely:
|
|
57
|
+
- The version that was published.
|
|
58
|
+
- Confirmation of: master pushed, npm publish succeeded, tag created, tag pushed.
|
|
59
|
+
- The release commit subject (from pre-flight).
|
|
60
|
+
- The npm package URL, if it can be derived from `package.json` name (`https://www.npmjs.com/package/<name>`).
|
|
61
|
+
|
|
62
|
+
## Things to watch for
|
|
63
|
+
|
|
64
|
+
- If step 2 (push master) succeeds but step 3 (npm publish) fails, the commit is on GitHub but not on npm. Do not tag — the user must either resolve the npm issue and re-run publish, or roll back the push.
|
|
65
|
+
- If step 3 (npm publish) succeeds but step 4 (tag) or step 5 (tag push) fails, the package is on npm but not tagged. Surface this clearly — the user needs to manually create / push the tag, and an un-tagged published release is a fix-it-now situation, not something to leave for later.
|
|
66
|
+
- Never use `--force`, `--no-verify`, or any flag that bypasses checks, even to recover from a mid-flight failure. Always ask the user.
|
|
67
|
+
- Never create or push tags for versions other than the one in `package.json`.
|
|
68
|
+
- Never run this skill on a branch other than `master` without explicit user confirmation.
|
package/README.md
CHANGED
|
@@ -1950,7 +1950,12 @@ var myScalarProvider = {
|
|
|
1950
1950
|
scalarType: snmp.ObjectType.OctetString,
|
|
1951
1951
|
maxAccess: snmp.MaxAccess["read-write"],
|
|
1952
1952
|
handler: function (mibRequest) {
|
|
1953
|
-
//
|
|
1953
|
+
// For a dynamically-calculated read-only scalar, publish the current value
|
|
1954
|
+
// by assigning to the instance node before calling done(). For read-write scalars,
|
|
1955
|
+
// the agent has already cast and validated mibRequest.setValue by the
|
|
1956
|
+
// time the handler runs, and will commit it on your behalf — the handler
|
|
1957
|
+
// usually just needs to call done().
|
|
1958
|
+
mibRequest.instanceNode.value = yourFunctionToComputeCurrentValue ();
|
|
1954
1959
|
mibRequest.done ();
|
|
1955
1960
|
}
|
|
1956
1961
|
// Note: handler is optional for scalar providers - if omitted,
|
|
@@ -2174,6 +2179,29 @@ objects`, below, for details.
|
|
|
2174
2179
|
with the instance OID being operated on, and an `operation` field with the request type from
|
|
2175
2180
|
`snmp.PduType`. If the `MibRequest` is for a `SetRequest` PDU, then variables `setValue` and
|
|
2176
2181
|
`setType` contain the value and type received in the `SetRequest` varbind.
|
|
2182
|
+
|
|
2183
|
+
How the handler should interact with the MIB value depends on the request type:
|
|
2184
|
+
|
|
2185
|
+
* For `GetRequest`, `GetNextRequest` and `GetBulkRequest`, the response varbind is taken
|
|
2186
|
+
from `mibRequest.instanceNode.value` at the moment `done()` is called. A handler that
|
|
2187
|
+
serves a dynamically-computed read-only scalar (e.g. `sysUpTime`) should therefore
|
|
2188
|
+
assign the current value to `mibRequest.instanceNode.value` before calling `done()`.
|
|
2189
|
+
Equivalent and validated alternative: call `mib.setScalarValue(providerName, value)`
|
|
2190
|
+
from the handler, which casts and constraint-checks the value before storing it.
|
|
2191
|
+
For table columns the pattern is the same — assign to `mibRequest.instanceNode.value`.
|
|
2192
|
+
* For `SetRequest`, the agent has already cast and validated the incoming value into
|
|
2193
|
+
`mibRequest.setValue` before the handler runs, and will commit it to
|
|
2194
|
+
`mibRequest.instanceNode.value` on your behalf during the commit pass. A handler
|
|
2195
|
+
typically only needs to call `done()` (or `done({errorStatus: ...})` to reject the set).
|
|
2196
|
+
You generally don't need to assign to `instanceNode.value` yourself on the set path.
|
|
2197
|
+
|
|
2198
|
+
If you do need to validate an externally-supplied value inside a handler, three helpers
|
|
2199
|
+
are exposed on the public API: `ObjectTypeUtil.castSetValue(type, value, constraints)`
|
|
2200
|
+
casts and range/constraint-checks a value (throwing on bad input);
|
|
2201
|
+
`MibNode#validateValue(type, value)` returns a boolean against the node's provider
|
|
2202
|
+
constraints; and `MibNode#getConstraintsFromProvider()` returns the constraints object
|
|
2203
|
+
for the current instance node.
|
|
2204
|
+
|
|
2177
2205
|
* `constraints` *(optional for scalar types)* - an optional object to specify constraints for
|
|
2178
2206
|
integer-based enumerated types, integer range restrictions and string size restrictions. Note that
|
|
2179
2207
|
table columns can specify such `constraints` in an identical way, except that these are stored under
|
|
@@ -3719,6 +3747,14 @@ Example programs are included under the module's `example` directory.
|
|
|
3719
3747
|
|
|
3720
3748
|
* Fix deleteTableRow string index handling
|
|
3721
3749
|
|
|
3750
|
+
# Version 3.26.2 - 21/04/2026
|
|
3751
|
+
|
|
3752
|
+
* Fix TypeError in oidInSubtree when varbind OID is null
|
|
3753
|
+
|
|
3754
|
+
# Version 3.26.3 - 21/04/2026
|
|
3755
|
+
|
|
3756
|
+
* Document how MIB scalar and table handlers should interact with `mibRequest.instanceNode.value` for Get vs Set operations
|
|
3757
|
+
|
|
3722
3758
|
# License
|
|
3723
3759
|
|
|
3724
3760
|
Copyright (c) 2020 Mark Abrahams <mark@abrahams.co.nz>
|
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
|
|
|
@@ -6886,6 +6889,9 @@ exports.ObjectParser = {
|
|
|
6886
6889
|
readUint32: readUint32,
|
|
6887
6890
|
readVarbindValue: readVarbindValue
|
|
6888
6891
|
};
|
|
6892
|
+
exports.OidUtil = {
|
|
6893
|
+
oidInSubtree: oidInSubtree
|
|
6894
|
+
};
|
|
6889
6895
|
exports.ObjectTypeUtil = ObjectTypeUtil;
|
|
6890
6896
|
exports.Authentication = Authentication;
|
|
6891
6897
|
exports.Encryption = Encryption;
|
package/package.json
CHANGED
|
@@ -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() {
|