@niroai/niro 0.17.0 → 0.18.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 (177) hide show
  1. package/CHANGELOG.md +136 -0
  2. package/README.md +123 -302
  3. package/bin/niro.js +12 -1
  4. package/docs/agent-antigravity.md +37 -0
  5. package/docs/agent-claude-code.md +48 -0
  6. package/docs/agent-claude-desktop.md +47 -0
  7. package/docs/agent-cline.md +42 -0
  8. package/docs/agent-codex.md +45 -0
  9. package/docs/agent-copilot-cli.md +42 -0
  10. package/docs/agent-cursor.md +44 -0
  11. package/docs/agent-factory.md +42 -0
  12. package/docs/agent-gemini-cli.md +42 -0
  13. package/docs/agent-goose.md +42 -0
  14. package/docs/agent-kiro.md +37 -0
  15. package/docs/agent-opencode.md +37 -0
  16. package/docs/agent-vscode.md +45 -0
  17. package/docs/agent-windsurf.md +38 -0
  18. package/docs/answer-shapes.md +69 -0
  19. package/docs/builds-and-updates.md +68 -0
  20. package/docs/cloud-README.md +372 -0
  21. package/docs/configuring-a-folder.md +51 -0
  22. package/docs/connect-ci.md +24 -0
  23. package/docs/connect-overview.md +20 -0
  24. package/docs/connect-review-bots.md +17 -0
  25. package/docs/connect-team-server.md +12 -0
  26. package/docs/connect-terminal.md +49 -0
  27. package/docs/connect-web-agents.md +9 -0
  28. package/docs/connect-your-ai-assistant.md +59 -175
  29. package/docs/coverage-audit-and-consent.md +51 -0
  30. package/docs/evaluate-what-niro-did.md +271 -0
  31. package/docs/faq-assistants-and-mcp.md +122 -0
  32. package/docs/faq-feedback-and-receipts.md +33 -0
  33. package/docs/faq-indexing.md +127 -0
  34. package/docs/faq-install-and-setup.md +103 -0
  35. package/docs/faq-licence-and-plans.md +86 -0
  36. package/docs/faq-login-and-account.md +69 -0
  37. package/docs/faq-offline.md +34 -0
  38. package/docs/faq-performance.md +33 -0
  39. package/docs/faq-privacy-and-security.md +113 -0
  40. package/docs/faq-uninstall.md +47 -0
  41. package/docs/faq-updates.md +59 -0
  42. package/docs/faq-worktrees-and-branches.md +59 -0
  43. package/docs/faq-wrong-or-missing-answers.md +275 -0
  44. package/docs/hosted-only.md +33 -0
  45. package/docs/how-the-graph-works.md +47 -0
  46. package/docs/index.md +157 -0
  47. package/docs/licence-and-plans.md +72 -0
  48. package/docs/lifecycle-debug.md +48 -0
  49. package/docs/lifecycle-onboarding.md +32 -0
  50. package/docs/lifecycle-overview.md +77 -0
  51. package/docs/lifecycle-plan-and-design.md +44 -0
  52. package/docs/lifecycle-review.md +30 -0
  53. package/docs/lifecycle-security-and-privacy.md +35 -0
  54. package/docs/lifecycle-test.md +28 -0
  55. package/docs/lifecycle-write-code.md +35 -0
  56. package/docs/llms-full.txt +8015 -0
  57. package/docs/llms.txt +126 -0
  58. package/docs/playbook-add-a-feature.md +108 -0
  59. package/docs/playbook-change-safely.md +93 -0
  60. package/docs/playbook-data-and-events.md +107 -0
  61. package/docs/playbook-debug-after-a-change.md +96 -0
  62. package/docs/playbook-debug-config.md +95 -0
  63. package/docs/playbook-debug-exception.md +124 -0
  64. package/docs/playbook-debug-failing-service-call.md +119 -0
  65. package/docs/playbook-debug-slow-path.md +80 -0
  66. package/docs/playbook-debug-wrong-value.md +137 -0
  67. package/docs/playbook-onboard.md +95 -0
  68. package/docs/playbook-review-a-change.md +72 -0
  69. package/docs/playbook-test-a-change.md +73 -0
  70. package/docs/reference-cli.md +113 -0
  71. package/docs/reference-config-files.md +42 -0
  72. package/docs/reference-engine-commands.md +56 -0
  73. package/docs/reference-environment-variables.md +89 -0
  74. package/docs/reference-exit-codes.md +67 -0
  75. package/docs/reference-limits.md +75 -0
  76. package/docs/reference-mcp-tools.md +326 -0
  77. package/docs/reference-messages.md +180 -0
  78. package/docs/secrets-and-masking.md +48 -0
  79. package/docs/supported-c.md +130 -0
  80. package/docs/supported-cpp.md +157 -0
  81. package/docs/supported-csharp.md +211 -0
  82. package/docs/supported-go.md +258 -0
  83. package/docs/supported-java.md +226 -0
  84. package/docs/supported-javascript.md +223 -0
  85. package/docs/supported-kotlin.md +124 -0
  86. package/docs/supported-overview.md +89 -0
  87. package/docs/supported-php.md +157 -0
  88. package/docs/supported-python.md +224 -0
  89. package/docs/supported-ruby.md +162 -0
  90. package/docs/supported-rust.md +150 -0
  91. package/docs/supported-swift.md +133 -0
  92. package/docs/supported-typescript.md +220 -0
  93. package/docs/tokens-speed-and-accuracy.md +99 -0
  94. package/docs/troubleshooting.md +42 -0
  95. package/docs/uninstall.md +74 -0
  96. package/docs/what-leaves-your-machine.md +71 -0
  97. package/docs/where-things-are-stored.md +59 -0
  98. package/docs/worktrees-and-branches.md +55 -0
  99. package/package.json +5 -3
  100. package/src/commands/add-repo.js +5 -0
  101. package/src/commands/auditSend.js +67 -0
  102. package/src/commands/build.js +6 -0
  103. package/src/commands/docsSend.js +73 -0
  104. package/src/commands/engine.js +120 -0
  105. package/src/commands/engineRoutes.js +105 -0
  106. package/src/commands/guide.js +254 -0
  107. package/src/commands/init.js +6 -2
  108. package/src/commands/initLocal.js +96 -0
  109. package/src/commands/journalSend.js +47 -0
  110. package/src/commands/login.js +89 -12
  111. package/src/commands/mcp.js +22 -6
  112. package/src/commands/plan.js +99 -0
  113. package/src/commands/repoPush.js +33 -0
  114. package/src/commands/requestIntegration.js +38 -0
  115. package/src/commands/share.js +56 -0
  116. package/src/commands/start.js +451 -371
  117. package/src/commands/status.js +57 -0
  118. package/src/commands/takeover.js +6 -0
  119. package/src/commands/uninstall.js +180 -0
  120. package/src/commands/upgrade.js +38 -8
  121. package/src/commands/watch.js +420 -6
  122. package/src/index.js +174 -3
  123. package/src/lib/agentApi.js +32 -1
  124. package/src/lib/api.js +20 -6
  125. package/src/lib/auditUpload.js +293 -0
  126. package/src/lib/branchDrift.js +149 -0
  127. package/src/lib/choose.js +116 -0
  128. package/src/lib/cloudGuard.js +74 -0
  129. package/src/lib/credentials.js +2 -2
  130. package/src/lib/docsMarked.js +55 -0
  131. package/src/lib/docsState.js +213 -0
  132. package/src/lib/docsUpload.js +481 -0
  133. package/src/lib/engine.js +619 -0
  134. package/src/lib/folderSync.js +2 -1
  135. package/src/lib/graphCheck.js +40 -0
  136. package/src/lib/guide.js +293 -0
  137. package/src/lib/guideSearch.js +252 -0
  138. package/src/lib/integrationRequest.js +89 -0
  139. package/src/lib/journalUpload.js +147 -0
  140. package/src/lib/languages.js +129 -0
  141. package/src/lib/lease.js +375 -0
  142. package/src/lib/localBuild.js +285 -0
  143. package/src/lib/localEngine.js +210 -0
  144. package/src/lib/localOnboard.js +124 -0
  145. package/src/lib/localWorktrees.js +243 -0
  146. package/src/lib/machineCheck.js +58 -0
  147. package/src/lib/mcpClients.js +10 -1
  148. package/src/lib/migrationNotice.js +118 -0
  149. package/src/lib/modelFetch.js +153 -0
  150. package/src/lib/nestedOutput.js +23 -9
  151. package/src/lib/onboardingLog.js +34 -0
  152. package/src/lib/planUsage.js +165 -0
  153. package/src/lib/progressBar.js +46 -0
  154. package/src/lib/prompt.js +1 -1
  155. package/src/lib/redact.js +155 -0
  156. package/src/lib/release.js +33 -0
  157. package/src/lib/repoPush.js +495 -0
  158. package/src/lib/secret.js +1 -1
  159. package/src/lib/service.js +372 -63
  160. package/src/lib/shareCode.js +367 -0
  161. package/src/lib/shareExclusions.js +114 -0
  162. package/src/lib/shareFiles.js +129 -0
  163. package/src/lib/spinner.js +9 -5
  164. package/src/lib/watchDaemon.js +33 -10
  165. package/src/lib/watchState.js +12 -1
  166. package/src/lib/windowsPaths.js +67 -0
  167. package/src/mcp/lineCheck.js +382 -0
  168. package/src/mcp/lineName.js +92 -0
  169. package/src/mcp/localBackend.js +751 -0
  170. package/src/mcp/localMode.js +383 -0
  171. package/src/mcp/localSkill.js +189 -0
  172. package/src/mcp/server.js +610 -79
  173. package/src/mcp/setup.js +519 -131
  174. package/src/mcp/shellSearchHook.js +509 -0
  175. package/src/mcp/teardown.js +173 -91
  176. package/src/mcp/usingNiro.js +39 -0
  177. package/docs/working-on-branches.md +0 -162
@@ -0,0 +1,383 @@
1
+ /**
2
+ * What `niro mcp install --local` writes instead of the cloud texts: the assistant is pointed at
3
+ * niro-local, the engine on this machine, rather than at a Niro project in the cloud.
4
+ *
5
+ * Why a separate set at all. The cloud hooks, CLAUDE.md section and skill decide where to speak up
6
+ * from a `.niro-project` file and name tools the engine does not serve (resolve_fqn,
7
+ * should_create_temp_project, get_state_at_entry, list_projects ...), so in a
8
+ * folder only niro-local indexes they either stay silent or send the assistant after tools that are
9
+ * not there. Here every gate reads niro-local's own list of indexed folders and every text names
10
+ * only the engine's tools.
11
+ *
12
+ * Swapping back and forth is the point (Niraj, 2026-11-02: "I may have to remove niro local and
13
+ * reinstall niro's current mcp, skill etc and vice versa"). So each local text keeps the identity
14
+ * token the cloud one has (the PostCompact prefix, the NIRO ACTIVE marker, niro-explore-,
15
+ * niro-impact-, the <!-- niro-mcp --> marker, the same skill files): installing one mode replaces
16
+ * the other in place, and `niro mcp uninstall` removes either.
17
+ *
18
+ * The mode is remembered in ~/.niro/config.json (`mcpMode`), so `niro upgrade`, which re-runs the
19
+ * installer per client with no mode flag, keeps what the person chose.
20
+ */
21
+
22
+ /**
23
+ * Whether this release has the cloud (src/lib/release.js). Without it, the engine is the released one, which builds and
24
+ * answers only with the licence niro-cli passes it, so a `niro-local build` or `niro-local ask` typed by the assistant
25
+ * is refused. The texts below then name the niro-cli commands that do the same through niro-cli (`niro build`,
26
+ * `niro status`, `niro init`) and the MCP tools, and never a direct `niro-local` command (the release's own
27
+ * niro-local skill: "Never run the engine (`niro-local`) directly"). Read once, when this module loads.
28
+ */
29
+ const CLOUD_RELEASE = require("../lib/release").cloud !== false;
30
+ const { USING_NIRO } = require("./usingNiro");
31
+
32
+ /**
33
+ * The two rules niro-local's own server instructions carry word for word (its `mcp/server.py`
34
+ * WORKTREE_SENTENCE and OFFER_SENTENCE), so the skill, the CLAUDE.md section and the engine say one
35
+ * thing. Pinned on both sides (test/localMode.test.js; niro-local tests/test_agent_guidance.py). The release
36
+ * wordings are the same rules through niro-cli; niro-local's server text is being changed to match (lead, 2026-11-06).
37
+ */
38
+ const ENGINE_WORKTREE_SENTENCE = "When you work in another folder (a git worktree, a sibling service), ask from that folder with `niro-local ask <tool> key=value`, and run `niro-local build` there after each edit.";
39
+ const ENGINE_OFFER_SENTENCE = "If a tool says a folder is not indexed, follow its answer: ask the user once, and index it only on a yes.";
40
+ const RELEASE_WORKTREE_SENTENCE = "When you work in another folder (a git worktree, a sibling service), the niro tools still answer for the folder the session started in: run `niro status` in that folder to see whether it is indexed, and `niro build <that folder>` after each edit there.";
41
+ const RELEASE_OFFER_SENTENCE = "If a tool says a folder is not indexed, ask the user once, and only on a yes run `niro init` in that folder.";
42
+ const WORKTREE_SENTENCE = CLOUD_RELEASE ? ENGINE_WORKTREE_SENTENCE : RELEASE_WORKTREE_SENTENCE;
43
+ const OFFER_SENTENCE = CLOUD_RELEASE ? ENGINE_OFFER_SENTENCE : RELEASE_OFFER_SENTENCE;
44
+ /** How the graph is rebuilt by hand, as the texts name it. */
45
+ const REBUILD_COMMAND = CLOUD_RELEASE ? "niro-local build" : "niro build";
46
+
47
+ const MODES = ["cloud", "local"];
48
+
49
+ /**
50
+ * LLM documentation (`niro-local build --llm`, find_reusable_code, find_known_issues) is off in this release
51
+ * (src/lib/release.js `llmDocs`; niro-local `reuse.IN_THIS_RELEASE`), so no text below names it. Read once, when this
52
+ * module loads: the texts are constants that the installer writes and the uninstaller matches.
53
+ */
54
+ const LLM_DOCS = require("../lib/release").llmDocs === true;
55
+
56
+ /** The mode asked for on the command line (`--local` / `--cloud`), or null when neither was. */
57
+ function modeFromArgs(args) {
58
+ if (args.includes("--local")) return "local";
59
+ if (args.includes("--cloud")) return "cloud";
60
+ return null;
61
+ }
62
+
63
+ /** The mode to install: the one asked for, else the one saved by the last install, else cloud. */
64
+ function chooseMode(args, saved) {
65
+ const asked = modeFromArgs(args);
66
+ if (asked) return asked;
67
+ return MODES.includes(saved) ? saved : "cloud";
68
+ }
69
+
70
+ /**
71
+ * The shell test the local hooks use instead of walking up for `.niro-project`: is `$d`, or a folder
72
+ * above it, one niro-local indexes? niro-local writes the list beside its registry, one resolved path
73
+ * per line (niro-local `registry.FOLDER_LIST_NAME`). A shell grep of a small file, because these
74
+ * hooks run on every prompt and every native search; asking `niro-local status --check` took 0.54 s.
75
+ */
76
+ const FOLDER_LIST = '"${NIRO_LOCAL_HOME:-$HOME/.niro-local}/indexed-folders"';
77
+ const LOCAL_WALK =
78
+ `IF=${FOLDER_LIST}; [ -f "$IF" ] || exit 0; ` +
79
+ 'd="$d0"; ok=0; while [ -n "$d" ] && [ "$d" != "/" ] && [ "$d" != "." ]; do if grep -qxF "$d" "$IF"; then ok=1; break; fi; p="$(dirname "$d")"; [ "$p" = "$d" ] && break; d="$p"; done';
80
+
81
+ /** The cloud hooks' walk up for `.niro-project`, as it appears in the explore and impact commands. */
82
+ const CLOUD_WALK =
83
+ 'd="$d0"; ok=0; while [ -n "$d" ] && [ "$d" != "/" ] && [ "$d" != "." ]; do if [ -f "$d/.niro-project" ]; then ok=1; break; fi; p="$(dirname "$d")"; [ "$p" = "$d" ] && break; d="$p"; done';
84
+
85
+ /**
86
+ * The same two walks without a process per folder level, used by the Bash hook (shellSearchHook.js),
87
+ * which runs before every shell command. The walks above start a `dirname` and, in local mode, a
88
+ * `grep` at each level: about 23 ms for a folder six levels deep under load. These read the folder
89
+ * list once and match each level with `case`, and take the parent with `${d%/*}`. The explore and
90
+ * impact hooks keep the walks above, so their installed text does not change.
91
+ */
92
+ const FAST_LOCAL_WALK =
93
+ `IF=${FOLDER_LIST}; [ -f "$IF" ] || exit 0; L="$(cat "$IF")"; N="$(printf '\\n.')"; N="\${N%.}"; ` +
94
+ 'd="$d0"; ok=0; while [ -n "$d" ] && [ "$d" != "/" ] && [ "$d" != "." ]; do case "$N$L$N" in *"$N$d$N"*) ok=1; break ;; esac; p="${d%/*}"; [ -z "$p" ] && p=/; [ "$p" = "$d" ] && break; d="$p"; done';
95
+ const FAST_CLOUD_WALK =
96
+ 'd="$d0"; ok=0; while [ -n "$d" ] && [ "$d" != "/" ] && [ "$d" != "." ]; do if [ -f "$d/.niro-project" ]; then ok=1; break; fi; p="${d%/*}"; [ -z "$p" ] && p=/; [ "$p" = "$d" ] && break; d="$p"; done';
97
+
98
+ /** Cloud tool names, and wording, that mean something else on this machine. */
99
+ const LOCAL_WORDING = [
100
+ ["get_source_code or resolve_fqn", "get_source_code or resolve_name"],
101
+ ["resolve_fqn", "resolve_name"],
102
+ LLM_DOCS
103
+ ? ["find_reusable_code (before new code)", "find_reusable_code (before new code, when the folder was built with --llm)"]
104
+ : [", find_reusable_code (before new code)", ""],
105
+ ["synced and rebuilt", "rebuilt by niro-local"],
106
+ ["the Niro bridge has not answered", "the niro-local engine has not answered"],
107
+ ["niro-indexed repo", "folder niro-local indexes"],
108
+ ];
109
+
110
+ /**
111
+ * A cloud hook command made local: its `.niro-project` walk swapped for the folder-list test, its
112
+ * tool names for the engine's. Throws when the walk is not found, because a command that kept the
113
+ * cloud gate would install silently and then never fire in a local folder.
114
+ */
115
+ function localHook(command) {
116
+ let local;
117
+ if (command.includes(CLOUD_WALK)) local = command.replace(CLOUD_WALK, LOCAL_WALK);
118
+ else if (command.includes(FAST_CLOUD_WALK)) local = command.replace(FAST_CLOUD_WALK, FAST_LOCAL_WALK);
119
+ else throw new Error("the cloud hook no longer contains the .niro-project walk localHook replaces");
120
+ for (const [cloud, here] of LOCAL_WORDING) local = local.split(cloud).join(here);
121
+ return local;
122
+ }
123
+
124
+ /**
125
+ * The standing reminder before every prompt, in a folder niro-local indexes. Keeps the cloud
126
+ * reminder's opening, "NIRO ACTIVE. Standing rule for this whole session", which is how the
127
+ * installer and the uninstaller recognise its own hook (setup.js isNiroUserPromptHook). No branch notice: niro-local
128
+ * follows the folder, whatever branch it is on.
129
+ */
130
+ const LOCAL_USER_PROMPT_COMMAND =
131
+ 'IN="$(cat)"; d="${CLAUDE_PROJECT_DIR:-$PWD}"; d="$(cd -P "$d" 2>/dev/null && pwd -P || printf \'%s\' "$d")"; ' +
132
+ `IF=${FOLDER_LIST}; [ -f "$IF" ] || exit 0; ` +
133
+ 'while [ -n "$d" ] && [ "$d" != "/" ] && [ "$d" != "." ]; do if grep -qxF "$d" "$IF"; then ' +
134
+ "echo 'NIRO ACTIVE. Standing rule for this whole session, at the start and mid-task alike: this folder is " +
135
+ "indexed by niro-local on this machine. Before Grep/Glob/Read or any native file hunt, use the niro tools " +
136
+ "(code_grep, get_source_code, resolve_name, get_call_chain, get_reverse_call_chain, get_blast_radius). " +
137
+ (LLM_DOCS
138
+ ? "Before writing new code, call find_reusable_code when it is in your toolset (it is there only for a folder " +
139
+ "built with --llm). "
140
+ : "") +
141
+ "Before you plan or propose a change to existing code, call get_blast_radius to see who " +
142
+ "calls it and what it calls, and put that impact in the plan. Keep that list and verify those flows after " +
143
+ "the edit; the graph changes only when niro-local rebuilds, so do not re-query it to verify. A log line or " +
144
+ "comment needs no map. Native tools only for config, docs, logs, generated or non-code text. If the niro " +
145
+ "tools are not in your toolset at all, use native tools and do not mention Niro.'; break; fi; " +
146
+ 'd="$(dirname "$d")"; done';
147
+
148
+ /** After compaction. Starts with the cloud prefix, which is how the installer finds its own hook. */
149
+ const LOCAL_POST_COMPACT_COMMAND =
150
+ "echo 'Niro MCP tools are available for code intelligence, answered by niro-local on this machine "
151
+ + "(call chains, blast radius, source lookup, data and event flows). Use niro tools before native "
152
+ + "grep/read for code questions in a folder niro-local indexes. Before you plan or propose a change to "
153
+ + "existing code, call get_blast_radius to see who calls it and what it calls, and put that impact in the "
154
+ + "plan. Keep that list and verify those flows after the edit; the graph changes only when niro-local "
155
+ + "rebuilds, so do not re-query it to verify. The niro tools answer for the folder the MCP server was "
156
+ + "started in. " + WORKTREE_SENTENCE.replace(/`/g, "") + " The niro-skill has the full routing playbook.'";
157
+
158
+ const MD_MARKER = "<!-- niro-mcp -->";
159
+
160
+ /**
161
+ * The ~/.claude/CLAUDE.md section. Its own heading, after the shared marker, as every niro section has. Both
162
+ * wordings (with and without the LLM sentence) are kept for the uninstaller, which removes a section only by its
163
+ * exact text, so one written by a release with LLM documentation on is still removed.
164
+ */
165
+ const localClaudeMdSection = (llm, usingNiro = !CLOUD_RELEASE) => `\n${MD_MARKER}\n## Niro MCP (niro-local)\n`
166
+ + "The niro MCP tools answer from niro-local, a code graph built on this machine from the files on disk. "
167
+ + "Nothing is sent to the cloud to answer them. Use them before native grep/read for code questions in "
168
+ + "a folder niro-local indexes; the niro-skill has the routing playbook.\n"
169
+ + "MUST FOLLOW: before you run grep, find, glob, or open a file to hunt for something, first check whether "
170
+ + "a niro tool answers it (code_grep for content search, resolve_name and get_source_code for a known "
171
+ + "symbol, find_handler and find_api_endpoints for entry points). Use the connection tools (get_call_chain, "
172
+ + "get_reverse_call_chain, get_blast_radius, get_service_topology, get_exception_flow) to understand how code "
173
+ + "connects BEFORE deciding which file to read next. Native search is the fallback for what the graph does "
174
+ + "not cover (config files, docs, logs, generated output, non-code text) and for a folder niro-local does "
175
+ + "not index. This rule does not expire.\n"
176
+ + "MUST FOLLOW: before you plan, propose, or start any change to existing code, call get_blast_radius on it "
177
+ + "and put both sides in the plan: who depends on it (callers, HTTP and event callers, tests) and what it "
178
+ + "depends on. Keep the list and verify those flows after the edit; the graph changes only when niro-local "
179
+ + "rebuilds (`" + REBUILD_COMMAND + "`, or the watcher), so verify from the list, not a fresh query.\n"
180
+ + (llm
181
+ ? "Before writing new code, call find_reusable_code when it is in your toolset (a folder built with "
182
+ + "`niro-local build --llm`).\n"
183
+ : "")
184
+ + "In a folder niro-local does not index, call get_index_status once. " + OFFER_SENTENCE + " "
185
+ + "The niro tools answer for the folder the MCP server was started in. " + WORKTREE_SENTENCE + "\n"
186
+ // Using Niro (src/mcp/usingNiro.js) names niro-cli's own commands (`niro init`, `niro build`), which are the
187
+ // engine's only in a release without the cloud; a cloud release's local mode keeps the text it had.
188
+ + (usingNiro ? `${USING_NIRO}\n` : "");
189
+ const LOCAL_CLAUDE_MD_SECTION = localClaudeMdSection(LLM_DOCS);
190
+ /** Every wording, for the uninstaller and a refresh: the current two, then the two from before Using Niro (9255e24). */
191
+ const LOCAL_CLAUDE_MD_SECTIONS = [
192
+ localClaudeMdSection(true), localClaudeMdSection(false), localClaudeMdSection(true, false), localClaudeMdSection(false, false),
193
+ ].filter((section, i, all) => all.indexOf(section) === i);
194
+
195
+ const LOCAL_SKILL = `---
196
+ name: niro-skill
197
+ description: Use the niro MCP tools, answered by niro-local from a code graph built on this machine, to answer questions about THIS codebase (structure, call chains, blast radius, exception flow, HTTP routes, data and event flows) instead of grep/read. Invoke whenever a task involves understanding, tracing, debugging, or assessing the impact of code, or BEFORE changing it.
198
+ ---
199
+
200
+ # Niro code intelligence, on this machine (niro-local)
201
+
202
+ niro-local builds a code graph from the files on disk (classes, methods, calls, HTTP routes and
203
+ calls, events, data stores) and serves it through the \`niro\` MCP server. Nothing leaves the
204
+ machine to answer a question. For anything outside the indexed code (config files, docs, runtime
205
+ state), use your native tools.
206
+
207
+ ## Is this folder indexed? Read FIRST
208
+
209
+ 1. **Are the tools present?** Only call \`mcp__niro__*\` tools that appear in your toolset. If none
210
+ do, use native tools and do not mention Niro.
211
+ 2. **Is this folder indexed?** \`get_index_status\` says what the graph holds for this folder. If
212
+ the folder is not indexed, the answer says whether it can be, and which projects it can join.
213
+ ${OFFER_SENTENCE}
214
+ - **When it offers, ask the user once, in plain words:** should it be indexed, and into which
215
+ project or a new one? Show the projects as the answer lists them and let the user choose, even
216
+ when only one fits. Never choose for them, and never index without a yes.
217
+ - **On a yes,** run the commands the answer gives, from that folder, then ask your question again.
218
+ - **On a no,** use native tools and do not ask again in this session. Do not loop.
219
+ - **When it makes no offer** (no source niro-local reads, a protected folder), use native tools and
220
+ do not bring it up.
221
+ - **The branch rule.** Every folder of a project must be on one branch. A folder outside git, or on
222
+ a detached HEAD, has no branch and can join any project. A project on another branch is not
223
+ offered and refuses the folder: start a new project, as the answer says.
224
+ - **A branch switch is followed.** niro-local keeps one index per folder and branch, and answers
225
+ from the index of the branch the folder is on at each call. After \`git checkout\`, a branch it
226
+ has indexed answers at once. On a new one, niro-local makes a temporary copy of the project by
227
+ itself: nothing to ask. Use native tools for a moment and ask again; the answer says what to run
228
+ if nothing builds by itself.
229
+ 3. **Is the question in scope?** Structure, behaviour, impact, routes, data and event flows ->
230
+ niro. Config, docs, runtime state, anything non-code -> native tools.
231
+
232
+ ## Explore first (MUST FOLLOW)
233
+
234
+ Before you run grep, find, glob, or open a file to hunt for something, check whether a niro tool
235
+ answers it: \`code_grep\` for content, \`get_source_code\` for a known method, class or line range,
236
+ \`resolve_name\` when a name may match several things, \`find_handler\` and \`find_api_endpoints\` for
237
+ entry points. Use the connection tools (\`get_call_chain\`, \`get_reverse_call_chain\`,
238
+ \`get_blast_radius\`, \`get_service_topology\`, \`get_exception_flow\`) to see how the code connects
239
+ BEFORE you decide which file to read next.
240
+
241
+ ## Check both directions before you change anything (MUST FOLLOW)
242
+
243
+ Before you plan, propose, or start any change to existing code, call \`get_blast_radius\` on it. One
244
+ call returns both sides: what depends on it (callers, HTTP and event callers, and the files that hold
245
+ them) and what it depends on. Put that in the plan you show the user: the callers you found, which you
246
+ will update, and which you are deliberately leaving alone. A one-line change is not exempt.
247
+
248
+ Keep the list. After the edit, verify those flows still hold (run their tests, trace them, read the
249
+ callers) and say what you verified. The graph changes only when niro-local rebuilds the folder, so a
250
+ fresh query right after your edit still shows the old code: use the list you captured. A change that
251
+ cannot alter behaviour (a log line, a comment, formatting) needs no map: say so in one sentence.
252
+
253
+ ## Keeping the graph current
254
+
255
+ The graph is what the last \`${REBUILD_COMMAND}\` saw. When a tool says the graph is behind, or files
256
+ were edited since the build, run \`${REBUILD_COMMAND}\` in that folder (it updates only what changed,
257
+ usually in seconds) and ask again. The niro watcher (\`niro watch\`) does this by itself when it runs.
258
+
259
+ ## Working in another folder (MUST FOLLOW)
260
+
261
+ The niro tools answer for the folder the MCP server was started in, not for where you are working.
262
+ ${WORKTREE_SENTENCE}
263
+ ${CLOUD_RELEASE ? "\`niro-local ask\` alone lists the tools. " : ""}A folder that is not indexed yet gets the same offer as above.
264
+
265
+ ## Calling conventions
266
+
267
+ - **Short names work.** Pass \`ClassName.method\` or a bare method name; tools resolve it. Use
268
+ \`resolve_name\` only when a name may match several things.
269
+ - **\`from_line\`** on most tools continues a paged answer.
270
+ - **\`purpose\`** (LOCATE, ORIENT, COMPREHEND, TRACE, DEBUG, PROPAGATE, ASSESS_RISK, ...) on the
271
+ chain and blast-radius tools tunes how much comes back.
272
+ - **Collapse stacked calls.** \`get_blast_radius\` covers callers, callees and files in one call;
273
+ do not follow it with \`get_reverse_call_chain\` for the same name.
274
+
275
+ ## Routing (most specific wins)
276
+
277
+ | Intent | Tool |
278
+ |---|---|
279
+ | What breaks if I change X: callers and callees in one call | \`get_blast_radius\` |
280
+ | Upstream callers that break, several levels up (lighter than blast radius) | \`get_impact_analysis\` |
281
+ | Who calls X (\`scope=transitive\` for further up) | \`get_reverse_call_chain\` |
282
+ | What X calls, or callers with \`direction\` | \`get_call_chain\` |
283
+ | Which exceptions can escape a method, and where they are caught | \`get_exception_flow\` |
284
+ | Source of a method, class, or a line range of a file | \`get_source_code\` |
285
+ | Search inside source files (regex or literal) | \`code_grep\` |
286
+ | Members of a class, interface or enum | \`get_class_structure\` |
287
+ | Every class, interface and enum | \`list_types\` |
288
+ | What a name matches (at most 25) | \`resolve_name\` |
289
+ | HTTP endpoints this project exposes | \`find_api_endpoints\` |
290
+ | HTTP calls it makes, and where they land | \`find_outbound_http_calls\` |
291
+ | What answers the HTTP calls a method makes | \`find_handler\` |
292
+ | Which folder of the project calls which, over HTTP | \`get_service_topology\` |
293
+ | Databases, caches and queues it touches | \`list_data_resources\` |
294
+ | Who reads, writes or deletes one store | \`get_data_resource_usage\` |
295
+ | Events it publishes or listens to | \`list_events\` |
296
+ | Who publishes and who handles one event | \`get_event_producers_and_handlers\` |
297
+ | Events with only one side | \`find_orphaned_events\` |
298
+ | What is indexed for this folder | \`get_index_status\` |
299
+ ${LLM_DOCS ? "| Reusable code, and known issues (folder built with \`--llm\` only) | \`find_reusable_code\`, \`find_known_issues\` |\n" : ""}
300
+ Not on this machine: \`trace_execution_path\`, \`get_state_at_entry\`, \`explain_code\`, temporary projects and
301
+ \`list_projects\`. There is no project id to pass: niro-local answers for the folder the session runs in. For another
302
+ folder, see "Working in another folder".
303
+
304
+ ## Task completion
305
+
306
+ Call \`mark_task_complete\` before your reply on every turn where you called a niro tool, or read or
307
+ searched this project's source yourself, as the server's instructions say. If it returns a line
308
+ starting with the receipt prefix, copy it as the last line of your reply in single backticks. A reply
309
+ without that line is unfinished: it is how the person sees what the niro tools did.
310
+ `;
311
+
312
+ const LOCAL_CLI_SKILL = `---
313
+ name: niro-cli
314
+ description: drive niro-local and the niro CLI from chat on this machine: index a folder, rebuild it, check what is indexed, remove a folder, and check the engine and the login
315
+ ---
316
+
317
+ # niro-local from chat
318
+
319
+ The niro MCP tools answer from niro-local, the engine on this machine. You manage it by running
320
+ commands in the shell and reporting back in plain words. Run ONE command per action, from the
321
+ folder it is about.
322
+
323
+ ## Golden rules
324
+
325
+ 1. **Login is the user's.** \`niro whoami --json\` says whether the user is signed in. If not, tell
326
+ them to run \`niro login\` themselves; it opens a browser. You cannot complete it for them.
327
+ 2. **Never print a secret.** Do not echo environment values, tokens or credential files.
328
+ 3. **Confirm before removing.** \`niro-local remove\` takes a folder out of the graph; ask first.
329
+ 4. **Ask before indexing.** Index a folder only after the user says yes and has chosen the project.
330
+ These commands never wait for an answer when run from your shell.
331
+
332
+ ## Tasks
333
+
334
+ | The user wants | Run |
335
+ |---|---|
336
+ | Which project this folder belongs to, and when it was built | \`niro-local status\` |
337
+ | Every project and its folders | \`niro-local projects\` |
338
+ | Index this folder for the first time | \`niro-local status\` first (it lists the projects this folder can join), then \`niro-local init --project <name>\` (it adds the folder and builds it) |
339
+ | Add another folder to the same project (it must be on the same branch, or have no branch) | in that folder: \`niro-local init --project <name>\` |
340
+ | A project refuses this folder because of its branch | start a new one with the name the refusal gives: \`niro-local init --project <name>\` |
341
+ | A second project uses this folder (a shared library) | \`niro-local init --project <second>\`; each project keeps its own copy, and a build refreshes them all |
342
+ | Answer from another project's copy of this folder | \`niro-local build --project <name>\` |
343
+ | Remove this folder from one project | \`niro-local remove --project <name>\` (confirm first); its copies in other projects stay |
344
+ | This folder is on a new branch | nothing to choose: \`niro-local build\` makes a temporary copy of its project, and the old branch's index is kept |
345
+ | Free the space of folders gone from disk | \`niro-local clean\` (\`--dry-run\` shows what it would remove); done by itself after 14 days |
346
+ | Bring the graph up to date after edits | \`niro-local build\` (only what changed; \`--full\` rebuilds all) |
347
+ ${LLM_DOCS ? "| Reusable-code search and known issues for this folder | \`niro-local build --llm\` (makes LLM documentation in the background) |\n" : ""}| Stop indexing this folder | \`niro-local remove\` (confirm first) |
348
+ | Is the graph file healthy | \`niro-local db status\`, or \`niro-local db check\` |
349
+ | Ask one tool from the shell | \`niro-local ask <tool> key=value ...\` (\`niro-local ask\` lists them) |
350
+ | A Niro error message, or how Niro works | \`niro guide --search <the message>\`, then \`niro guide <page>\` (the pages ship with niro, offline) |
351
+ | Is the engine installed, and where | \`niro engine status\` (\`niro engine install\` puts it on this machine) |
352
+ | Keep folders rebuilt as files change | \`niro watch\`, or \`niro service install\` to run it in the background |
353
+ | What the MCP server was asked, waiting to be sent | \`niro-local journal\`; \`niro journal-send\` sends it |
354
+ | What the builds found wrong with their own graph | \`niro-local audit\`; \`niro audit-send\` sends it |
355
+ | Point the assistant back at the Niro cloud | \`niro mcp install --cloud\` (the user runs it, then restarts the assistant) |
356
+
357
+ Report what each command printed, in plain words. A command that fails prints why and what to run;
358
+ pass that on rather than guessing.
359
+ `;
360
+
361
+ module.exports = {
362
+ MODES,
363
+ modeFromArgs,
364
+ chooseMode,
365
+ localHook,
366
+ LOCAL_USER_PROMPT_COMMAND,
367
+ LOCAL_POST_COMPACT_COMMAND,
368
+ LOCAL_CLAUDE_MD_SECTION,
369
+ LOCAL_CLAUDE_MD_SECTIONS,
370
+ LLM_DOCS,
371
+ LOCAL_SKILL,
372
+ LOCAL_CLI_SKILL,
373
+ CLOUD_WALK,
374
+ LOCAL_WALK,
375
+ FAST_CLOUD_WALK,
376
+ FAST_LOCAL_WALK,
377
+ WORKTREE_SENTENCE,
378
+ OFFER_SENTENCE,
379
+ ENGINE_WORKTREE_SENTENCE,
380
+ ENGINE_OFFER_SENTENCE,
381
+ RELEASE_WORKTREE_SENTENCE,
382
+ RELEASE_OFFER_SENTENCE,
383
+ };
@@ -0,0 +1,189 @@
1
+ /**
2
+ * The `niro-local` skill, written by `niro mcp install` in a release without the cloud
3
+ * (src/lib/release.js). It teaches an assistant the local commands: what is indexed on this
4
+ * machine, the plan's line limit, adding or removing a folder, and what it must leave to the user.
5
+ * The cloud `niro-cli` skill is not installed alongside it, so the assistant never reaches for a
6
+ * command this release does not have.
7
+ */
8
+ const { USING_NIRO } = require("./usingNiro");
9
+
10
+ const NIRO_LOCAL_SKILL = `---
11
+ name: niro-local
12
+ description: manage Niro Local from chat - which folders are indexed on this machine, the plan and its line limit, add a folder (niro init), rebuild one (niro build), stop indexing one (niro plan remove), and what to do over the limit
13
+ ---
14
+
15
+ # Niro Local - manage it from chat
16
+
17
+ Niro Local builds a code graph of the user's repositories ON THEIR MACHINE and answers your
18
+ code questions from it through the \`niro\` MCP tools. You manage it by running the \`niro\`
19
+ CLI in the shell and reading its \`--json\` output. Gather what you need in conversation, run
20
+ ONE command, and report back in plain English.
21
+ For a how-to question about Niro, run \`niro guide\` (every page with one line on what it answers), pick the
22
+ page whose line fits, and answer from \`niro guide <page>\`. For a Niro error message,
23
+ \`niro guide --search "<the message>"\` names the page that explains it. The pages ship with niro, offline.
24
+
25
+ ## Rules
26
+
27
+ 1. **Signed in first.** Run \`niro whoami --json\`. If \`authed\` is false, ask the USER to
28
+ run \`niro start\` themselves in a terminal. It opens a browser to sign in and approve the
29
+ terminal; you cannot do that for them. Never run \`niro start\`, \`niro login\` or
30
+ \`niro uninstall\` yourself: they are interactive or destructive.
31
+ 2. **Never guess the folder.** Commands act on the current folder unless given a path. Say
32
+ which folder you mean before acting on it.
33
+ 3. **Ask before removing.** \`niro plan remove <folder>\` stops indexing a folder and deletes
34
+ its graph (the code itself is untouched). Confirm with the user first, naming the folder.
35
+ 4. **Sharing is the user's choice.** Turning on code sharing (which lifts the Free line limit, and
36
+ makes the watcher send the files Niro indexes, redacted, by itself) is done by the user in the
37
+ console; never turn it on for them and never describe it as required. A folder is kept out with
38
+ \`niro share exclude <folder>\`; run it only when the user asks. Coverage findings (for each line the graph missed,
39
+ the method that holds it and its file's path, with secrets masked) and the tool-usage record are sent on every plan.
40
+
41
+ ## What to run
42
+
43
+ ### "Is this folder set up?" / "What is Niro doing?"
44
+ \`niro status --json\` in the folder: \`indexed\`, \`last_build_at\`, \`plan\`, \`share_code\`,
45
+ \`assistants\`, \`auto_sync\`. If the folder is not indexed, offer to add it (below).
46
+
47
+ ### "Which folders are indexed?" / "How many lines am I using?"
48
+ \`niro plan --json\`: \`plan\`, \`max_lines\` (null means no line limit), \`lines_used\`,
49
+ \`over_by\`, \`no_room\`, \`limit_url\`, and \`folders\` with each folder's \`lines\`, largest
50
+ first. \`lines_used\` is the engine's own total: each repository counts once, by its largest
51
+ checkout (two checkouts of one repo are not counted twice), and a folder inside another indexed
52
+ folder is not counted again, so the folders' lines do not add up to it. Report usage as "X of Y
53
+ lines", or "Unlimited Lines of Code" when \`max_lines\` is null.
54
+
55
+ ### "Add this repo" / "Index this folder"
56
+ \`niro init\` in the folder, or \`niro init <path>\`. It adds the folder to the local engine if
57
+ it is new and builds its graph; an indexed folder is built again. \`--project <name>\` joins
58
+ that project (or starts it) instead of the one named after the folder: ask the user which, never
59
+ choose for them. \`--force\` adds a folder with no build file, when the user says it is meant. It
60
+ needs a machine already set up by \`niro start\`; if it says so, ask the user to run \`niro start\` once.
61
+
62
+ ### "Rebuild the graph" / "Update the graph"
63
+ \`niro build\` in the folder, or \`niro build <path>\`. It rebuilds a folder already added; only
64
+ changed files are reparsed. A folder not added yet is refused with a pointer to \`niro init\`.
65
+ Never run the engine (\`niro-local\`) directly: it builds only when \`niro\` passes it the licence.
66
+
67
+ ### "What about my folders from Niro web?"
68
+ This version indexes on this machine only and no longer uploads anything to Niro web. The folders
69
+ that were set up with Niro web are listed in \`~/.niro/projects.web.json\`; a leftover
70
+ \`.niro-project\` file in one is ignored. To use Niro on one of them, run \`niro init\` in it.
71
+
72
+ ### "Stop indexing X" / "Free up lines"
73
+ Confirm the folder with the user, then \`niro plan remove <folder>\`. Then \`niro plan --json\`
74
+ to show the new usage.
75
+
76
+ ### Over the limit
77
+ A build starts only while the machine is under its line limit; the one that crosses it is
78
+ allowed to finish, and after that builds stop until something changes. When \`no_room\` is
79
+ true, explain the three ways on and let the user choose:
80
+ - **Unlock unlimited lines on Free** by turning on sharing of redacted code (the user does
81
+ this in the console; give them \`limit_url\`).
82
+ - **Request a Pro free trial** (no line limit, no sharing needed), also from \`limit_url\`.
83
+ Your code stays on this machine, except, for each line the audit flags, the whole method that
84
+ holds it and one line for each name it uses, sent with secrets masked and author and company names removed. A record of
85
+ which Niro tools your assistant used is also sent, to improve Niro and to show you its value.
86
+ Niro's tools answer your assistant from the graph on this machine and never send the contents
87
+ of your files.
88
+ - **Stay under the limit**: remove folders they no longer need (\`niro plan remove\`).
89
+ The graph already built keeps answering questions in the meantime; only new builds stop.
90
+
91
+ ### "What has Niro done for me?"
92
+ \`niro impact\`: what Niro did over the last 7 and 30 days (\`--json\` for the numbers). Report it in plain words.
93
+
94
+ ### "Calls between my services are not connected"
95
+ \`niro route-rule\` says where a path goes when the project does not (list, add, remove). Read
96
+ \`niro guide configuring-a-folder\` first, and confirm the rule with the user before adding it.
97
+
98
+ ### "Can Niro read Scala?" / "Please support framework X"
99
+ Niro reads ${require("../lib/languages").supportedList()}. For anything else (a language, a framework whose routes are missing, a tool),
100
+ offer to ask Niro's team for it. Call the \`request_integration\` tool without \`confirm\` first: it sends
101
+ nothing and returns what would be sent, from which account. Show that to the user, and call it again
102
+ with \`confirm: true\` only after they say yes. Without the tool, the user can run
103
+ \`niro request-integration <name>\` (\`--kind framework\` or \`--kind tool\`, \`--reason "<why>"\`); it asks
104
+ before sending. The request is kept with their account.
105
+
106
+ ### "Which assistant is connected?" / "Connect another one"
107
+ \`niro status --json\` lists \`assistants\`. To connect another, ask the user to run
108
+ \`niro mcp install\` (it asks which assistant).
109
+
110
+ ### "Remove Niro from this machine"
111
+ Tell the user to run \`niro uninstall\` themselves; it asks before removing anything. It takes
112
+ out the assistant entries, the background watcher, \`~/.niro\` and \`~/.niro-local\` (with
113
+ every graph), then prints the npm command that removes the CLI itself.
114
+
115
+ ## Reporting
116
+
117
+ One or two sentences: what you ran, what it means, the next sensible step. Numbers with
118
+ thousands separators. Never paste raw JSON at the user.
119
+ `;
120
+
121
+ /**
122
+ * `niro-skill` for a release without the cloud: how to use the MCP tools, naming only the tools
123
+ * the local engine serves (niro-local's `tools/list`). The cloud version names tools such as
124
+ * find_reusable_code and list_projects that the engine does not offer in this release. get_impact_analysis is served
125
+ * by the engine since 2026-11-02 and is named here (lead, 2026-11-06).
126
+ */
127
+ const NIRO_SKILL_LOCAL = `---
128
+ name: niro-skill
129
+ description: Use Niro code-intelligence MCP tools to answer questions about THIS codebase - structure, call chains, blast radius / impact, entry points, HTTP calls, events and data access - from the graph Niro Local builds on this machine, instead of grep/read. Invoke whenever a task involves understanding, tracing, debugging, or assessing the impact of code, and for how-to questions about Niro itself or a Niro error message.
130
+ ---
131
+
132
+ # Niro code intelligence (Niro Local)
133
+
134
+ Niro Local indexes this repository into a graph on this machine (classes, methods, calls,
135
+ HTTP endpoints and calls, events, data access) and serves it through the \`niro\` MCP tools.
136
+ For any question answerable from the indexed code, prefer these tools over native grep/read.
137
+ For anything outside it (config values, docs, runtime state), use your native tools.
138
+
139
+ ## Explore first - MUST FOLLOW
140
+
141
+ Before you grep, glob or open files to hunt for something, check whether a Niro tool answers it:
142
+ - \`code_grep\` for a text search across the indexed files, \`get_source_code\` to read a symbol.
143
+ - \`resolve_name\` to turn a short or partial name into the exact class or method.
144
+ - \`list_types\` and \`get_class_structure\` for what exists and what a class holds.
145
+ - \`find_api_endpoints\` and \`find_handler\` for entry points (a route to its handler).
146
+ Then use the connection tools to see how the code fits together BEFORE choosing a file to read:
147
+ \`get_call_chain\` (what this calls), \`get_reverse_call_chain\` (who calls this),
148
+ \`get_blast_radius\`, \`get_service_topology\`, \`get_exception_flow\`.
149
+
150
+ ## Check both directions before you change anything (MUST FOLLOW)
151
+
152
+ Before you plan or start a change to existing code, establish:
153
+ - **Upstream, what depends on this:** callers here and in other services (HTTP, events).
154
+ - **Downstream, what this depends on:** what it calls, the data it touches, the events it sends.
155
+ \`get_blast_radius\` answers both in one call; \`get_reverse_call_chain\` is the upstream view.
156
+ \`get_impact_analysis\` is the lighter upstream-only view: the callers that break, several levels up, in one call.
157
+ Name the callers you found in the plan you show the user, and after the edit verify them with
158
+ tests or by reading them. The graph updates after the files are saved and rebuilt, so use the
159
+ list you captured before the edit rather than re-querying to verify.
160
+
161
+ ## Flows across services
162
+
163
+ - HTTP: \`find_outbound_http_calls\` (calls this code makes), \`find_api_endpoints\` (routes it
164
+ serves), \`get_service_topology\` (who talks to whom).
165
+ - Events: \`list_events\`, \`get_event_producers_and_handlers\`, \`find_orphaned_events\`
166
+ (published with no handler, or handled with nothing publishing).
167
+ - Data: \`list_data_resources\`, \`get_data_resource_usage\` (which code reads or writes a
168
+ table or collection).
169
+
170
+ ## When Niro does not apply - fall back silently
171
+
172
+ 1. **Tools missing.** Only call \`niro\` tools that are in your toolset.
173
+ 2. **Folder not indexed.** \`get_index_status\`, or a tool answering "not indexed on this
174
+ machine", means this folder has no graph. Use native tools, and tell the user once that
175
+ \`niro init\` in this folder would index it.
176
+ 3. **Out of scope.** Config, docs, runtime state and non-code questions go to native tools.
177
+ 4. **Graph behind.** A tool may say the graph is behind the files on disk; it rebuilds in the
178
+ background. Trust the files you just edited over the graph for those.
179
+
180
+ ## Beyond code questions
181
+
182
+ ${USING_NIRO}
183
+
184
+ ## Finishing
185
+
186
+ When the task is done, call \`mark_task_complete\` if it is in your toolset.
187
+ `;
188
+
189
+ module.exports = { NIRO_LOCAL_SKILL, NIRO_SKILL_LOCAL };