narai-primitives 2.1.3 → 2.3.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 (392) hide show
  1. package/README.md +20 -4
  2. package/dist/config/load.d.ts.map +1 -1
  3. package/dist/config/load.js +12 -1
  4. package/dist/config/load.js.map +1 -1
  5. package/dist/connectors/confluence/index.d.ts +3 -1
  6. package/dist/connectors/confluence/index.d.ts.map +1 -1
  7. package/dist/connectors/confluence/index.js +246 -31
  8. package/dist/connectors/confluence/index.js.map +1 -1
  9. package/dist/connectors/confluence/lib/confluence_client.d.ts +50 -30
  10. package/dist/connectors/confluence/lib/confluence_client.d.ts.map +1 -1
  11. package/dist/connectors/confluence/lib/confluence_client.js +69 -225
  12. package/dist/connectors/confluence/lib/confluence_client.js.map +1 -1
  13. package/dist/connectors/db/connector.d.ts.map +1 -1
  14. package/dist/connectors/db/connector.js +12 -6
  15. package/dist/connectors/db/connector.js.map +1 -1
  16. package/dist/connectors/db/dispatcher.d.ts +3 -2
  17. package/dist/connectors/db/dispatcher.d.ts.map +1 -1
  18. package/dist/connectors/db/dispatcher.js +142 -40
  19. package/dist/connectors/db/dispatcher.js.map +1 -1
  20. package/dist/connectors/db/index.d.ts +9 -0
  21. package/dist/connectors/db/index.d.ts.map +1 -1
  22. package/dist/connectors/db/index.js +9 -0
  23. package/dist/connectors/db/index.js.map +1 -1
  24. package/dist/connectors/db/lib/audit.d.ts.map +1 -1
  25. package/dist/connectors/db/lib/audit.js +46 -4
  26. package/dist/connectors/db/lib/audit.js.map +1 -1
  27. package/dist/connectors/db/lib/drivers/dynamodb.d.ts.map +1 -1
  28. package/dist/connectors/db/lib/drivers/dynamodb.js +24 -4
  29. package/dist/connectors/db/lib/drivers/dynamodb.js.map +1 -1
  30. package/dist/connectors/db/lib/drivers/mysql.js +1 -1
  31. package/dist/connectors/db/lib/drivers/mysql.js.map +1 -1
  32. package/dist/connectors/db/lib/drivers/postgresql.js +1 -1
  33. package/dist/connectors/db/lib/drivers/postgresql.js.map +1 -1
  34. package/dist/connectors/db/lib/drivers/sqlite.d.ts.map +1 -1
  35. package/dist/connectors/db/lib/drivers/sqlite.js +9 -5
  36. package/dist/connectors/db/lib/drivers/sqlite.js.map +1 -1
  37. package/dist/connectors/db/lib/drivers/sqlserver.d.ts.map +1 -1
  38. package/dist/connectors/db/lib/drivers/sqlserver.js +66 -32
  39. package/dist/connectors/db/lib/drivers/sqlserver.js.map +1 -1
  40. package/dist/connectors/db/lib/environments.d.ts +16 -0
  41. package/dist/connectors/db/lib/environments.d.ts.map +1 -1
  42. package/dist/connectors/db/lib/environments.js +16 -0
  43. package/dist/connectors/db/lib/environments.js.map +1 -1
  44. package/dist/connectors/db/lib/grant-store.d.ts +77 -0
  45. package/dist/connectors/db/lib/grant-store.d.ts.map +1 -0
  46. package/dist/connectors/db/lib/grant-store.js +158 -0
  47. package/dist/connectors/db/lib/grant-store.js.map +1 -0
  48. package/dist/connectors/db/lib/plugin_config.d.ts +2 -0
  49. package/dist/connectors/db/lib/plugin_config.d.ts.map +1 -1
  50. package/dist/connectors/db/lib/plugin_config.js +23 -2
  51. package/dist/connectors/db/lib/plugin_config.js.map +1 -1
  52. package/dist/connectors/db/lib/policy.d.ts +50 -14
  53. package/dist/connectors/db/lib/policy.d.ts.map +1 -1
  54. package/dist/connectors/db/lib/policy.js +298 -74
  55. package/dist/connectors/db/lib/policy.js.map +1 -1
  56. package/dist/connectors/github/actions/_fields.d.ts +18 -0
  57. package/dist/connectors/github/actions/_fields.d.ts.map +1 -0
  58. package/dist/connectors/github/actions/_fields.js +29 -0
  59. package/dist/connectors/github/actions/_fields.js.map +1 -0
  60. package/dist/connectors/github/actions/_pagination.d.ts +12 -0
  61. package/dist/connectors/github/actions/_pagination.d.ts.map +1 -0
  62. package/dist/connectors/github/actions/_pagination.js +26 -0
  63. package/dist/connectors/github/actions/_pagination.js.map +1 -0
  64. package/dist/connectors/github/actions/_types.d.ts +14 -0
  65. package/dist/connectors/github/actions/_types.d.ts.map +1 -0
  66. package/dist/connectors/github/actions/_types.js +2 -0
  67. package/dist/connectors/github/actions/_types.js.map +1 -0
  68. package/dist/connectors/github/actions/comments.d.ts +3 -0
  69. package/dist/connectors/github/actions/comments.d.ts.map +1 -0
  70. package/dist/connectors/github/actions/comments.js +166 -0
  71. package/dist/connectors/github/actions/comments.js.map +1 -0
  72. package/dist/connectors/github/actions/issues.d.ts +3 -0
  73. package/dist/connectors/github/actions/issues.d.ts.map +1 -0
  74. package/dist/connectors/github/actions/issues.js +129 -0
  75. package/dist/connectors/github/actions/issues.js.map +1 -0
  76. package/dist/connectors/github/actions/pulls.d.ts +3 -0
  77. package/dist/connectors/github/actions/pulls.d.ts.map +1 -0
  78. package/dist/connectors/github/actions/pulls.js +182 -0
  79. package/dist/connectors/github/actions/pulls.js.map +1 -0
  80. package/dist/connectors/github/actions/reads.d.ts +3 -0
  81. package/dist/connectors/github/actions/reads.d.ts.map +1 -0
  82. package/dist/connectors/github/actions/reads.js +349 -0
  83. package/dist/connectors/github/actions/reads.js.map +1 -0
  84. package/dist/connectors/github/actions/releases.d.ts +3 -0
  85. package/dist/connectors/github/actions/releases.d.ts.map +1 -0
  86. package/dist/connectors/github/actions/releases.js +124 -0
  87. package/dist/connectors/github/actions/releases.js.map +1 -0
  88. package/dist/connectors/github/actions/workflows.d.ts +3 -0
  89. package/dist/connectors/github/actions/workflows.d.ts.map +1 -0
  90. package/dist/connectors/github/actions/workflows.js +224 -0
  91. package/dist/connectors/github/actions/workflows.js.map +1 -0
  92. package/dist/connectors/github/index.d.ts +13 -1
  93. package/dist/connectors/github/index.d.ts.map +1 -1
  94. package/dist/connectors/github/index.js +33 -396
  95. package/dist/connectors/github/index.js.map +1 -1
  96. package/dist/connectors/github/lib/github_client.d.ts +242 -29
  97. package/dist/connectors/github/lib/github_client.d.ts.map +1 -1
  98. package/dist/connectors/github/lib/github_client.js +202 -256
  99. package/dist/connectors/github/lib/github_client.js.map +1 -1
  100. package/dist/connectors/github/lib/github_config.d.ts +10 -0
  101. package/dist/connectors/github/lib/github_config.d.ts.map +1 -0
  102. package/dist/connectors/github/lib/github_config.js +79 -0
  103. package/dist/connectors/github/lib/github_config.js.map +1 -0
  104. package/dist/connectors/gitlab/actions/_fields.d.ts +20 -0
  105. package/dist/connectors/gitlab/actions/_fields.d.ts.map +1 -0
  106. package/dist/connectors/gitlab/actions/_fields.js +44 -0
  107. package/dist/connectors/gitlab/actions/_fields.js.map +1 -0
  108. package/dist/connectors/gitlab/actions/_pagination.d.ts +19 -0
  109. package/dist/connectors/gitlab/actions/_pagination.d.ts.map +1 -0
  110. package/dist/connectors/gitlab/actions/_pagination.js +33 -0
  111. package/dist/connectors/gitlab/actions/_pagination.js.map +1 -0
  112. package/dist/connectors/gitlab/actions/_types.d.ts +12 -0
  113. package/dist/connectors/gitlab/actions/_types.d.ts.map +1 -0
  114. package/dist/connectors/gitlab/actions/_types.js +2 -0
  115. package/dist/connectors/gitlab/actions/_types.js.map +1 -0
  116. package/dist/connectors/gitlab/actions/issues.d.ts +3 -0
  117. package/dist/connectors/gitlab/actions/issues.d.ts.map +1 -0
  118. package/dist/connectors/gitlab/actions/issues.js +119 -0
  119. package/dist/connectors/gitlab/actions/issues.js.map +1 -0
  120. package/dist/connectors/gitlab/actions/merges.d.ts +3 -0
  121. package/dist/connectors/gitlab/actions/merges.d.ts.map +1 -0
  122. package/dist/connectors/gitlab/actions/merges.js +198 -0
  123. package/dist/connectors/gitlab/actions/merges.js.map +1 -0
  124. package/dist/connectors/gitlab/actions/notes.d.ts +3 -0
  125. package/dist/connectors/gitlab/actions/notes.d.ts.map +1 -0
  126. package/dist/connectors/gitlab/actions/notes.js +145 -0
  127. package/dist/connectors/gitlab/actions/notes.js.map +1 -0
  128. package/dist/connectors/gitlab/actions/pipelines.d.ts +3 -0
  129. package/dist/connectors/gitlab/actions/pipelines.d.ts.map +1 -0
  130. package/dist/connectors/gitlab/actions/pipelines.js +136 -0
  131. package/dist/connectors/gitlab/actions/pipelines.js.map +1 -0
  132. package/dist/connectors/gitlab/actions/reads.d.ts +3 -0
  133. package/dist/connectors/gitlab/actions/reads.d.ts.map +1 -0
  134. package/dist/connectors/gitlab/actions/reads.js +422 -0
  135. package/dist/connectors/gitlab/actions/reads.js.map +1 -0
  136. package/dist/connectors/gitlab/actions/releases.d.ts +3 -0
  137. package/dist/connectors/gitlab/actions/releases.d.ts.map +1 -0
  138. package/dist/connectors/gitlab/actions/releases.js +99 -0
  139. package/dist/connectors/gitlab/actions/releases.js.map +1 -0
  140. package/dist/connectors/gitlab/cli.d.ts +3 -0
  141. package/dist/connectors/gitlab/cli.d.ts.map +1 -0
  142. package/dist/connectors/gitlab/cli.js +24 -0
  143. package/dist/connectors/gitlab/cli.js.map +1 -0
  144. package/dist/connectors/gitlab/index.d.ts +29 -0
  145. package/dist/connectors/gitlab/index.d.ts.map +1 -0
  146. package/dist/connectors/gitlab/index.js +95 -0
  147. package/dist/connectors/gitlab/index.js.map +1 -0
  148. package/dist/connectors/gitlab/lib/gitlab_client.d.ts +306 -0
  149. package/dist/connectors/gitlab/lib/gitlab_client.d.ts.map +1 -0
  150. package/dist/connectors/gitlab/lib/gitlab_client.js +249 -0
  151. package/dist/connectors/gitlab/lib/gitlab_client.js.map +1 -0
  152. package/dist/connectors/gitlab/lib/gitlab_config.d.ts +11 -0
  153. package/dist/connectors/gitlab/lib/gitlab_config.d.ts.map +1 -0
  154. package/dist/connectors/gitlab/lib/gitlab_config.js +115 -0
  155. package/dist/connectors/gitlab/lib/gitlab_config.js.map +1 -0
  156. package/dist/connectors/jira/index.d.ts +3 -1
  157. package/dist/connectors/jira/index.d.ts.map +1 -1
  158. package/dist/connectors/jira/index.js +299 -41
  159. package/dist/connectors/jira/index.js.map +1 -1
  160. package/dist/connectors/jira/lib/jira_client.d.ts +56 -41
  161. package/dist/connectors/jira/lib/jira_client.d.ts.map +1 -1
  162. package/dist/connectors/jira/lib/jira_client.js +71 -248
  163. package/dist/connectors/jira/lib/jira_client.js.map +1 -1
  164. package/dist/connectors/linear/cli.d.ts +3 -0
  165. package/dist/connectors/linear/cli.d.ts.map +1 -0
  166. package/dist/connectors/linear/cli.js +22 -0
  167. package/dist/connectors/linear/cli.js.map +1 -0
  168. package/dist/connectors/linear/index.d.ts +27 -0
  169. package/dist/connectors/linear/index.d.ts.map +1 -0
  170. package/dist/connectors/linear/index.js +496 -0
  171. package/dist/connectors/linear/index.js.map +1 -0
  172. package/dist/connectors/linear/lib/linear_client.d.ts +249 -0
  173. package/dist/connectors/linear/lib/linear_client.d.ts.map +1 -0
  174. package/dist/connectors/linear/lib/linear_client.js +154 -0
  175. package/dist/connectors/linear/lib/linear_client.js.map +1 -0
  176. package/dist/connectors/linear/lib/queries.d.ts +15 -0
  177. package/dist/connectors/linear/lib/queries.d.ts.map +1 -0
  178. package/dist/connectors/linear/lib/queries.js +188 -0
  179. package/dist/connectors/linear/lib/queries.js.map +1 -0
  180. package/dist/connectors/notion/index.d.ts +2 -1
  181. package/dist/connectors/notion/index.d.ts.map +1 -1
  182. package/dist/connectors/notion/index.js +213 -28
  183. package/dist/connectors/notion/index.js.map +1 -1
  184. package/dist/connectors/notion/lib/markdown_to_blocks.d.ts +21 -0
  185. package/dist/connectors/notion/lib/markdown_to_blocks.d.ts.map +1 -0
  186. package/dist/connectors/notion/lib/markdown_to_blocks.js +102 -0
  187. package/dist/connectors/notion/lib/markdown_to_blocks.js.map +1 -0
  188. package/dist/connectors/notion/lib/notion_blocks.d.ts +34 -0
  189. package/dist/connectors/notion/lib/notion_blocks.d.ts.map +1 -0
  190. package/dist/connectors/notion/lib/notion_blocks.js +87 -0
  191. package/dist/connectors/notion/lib/notion_blocks.js.map +1 -0
  192. package/dist/connectors/notion/lib/notion_client.d.ts +35 -25
  193. package/dist/connectors/notion/lib/notion_client.d.ts.map +1 -1
  194. package/dist/connectors/notion/lib/notion_client.js +63 -185
  195. package/dist/connectors/notion/lib/notion_client.js.map +1 -1
  196. package/dist/hub/index.d.ts.map +1 -1
  197. package/dist/hub/index.js +23 -3
  198. package/dist/hub/index.js.map +1 -1
  199. package/dist/toolkit/agent_resolver.d.ts +14 -4
  200. package/dist/toolkit/agent_resolver.d.ts.map +1 -1
  201. package/dist/toolkit/agent_resolver.js +38 -6
  202. package/dist/toolkit/agent_resolver.js.map +1 -1
  203. package/dist/toolkit/atlassian/adf_validator.d.ts +45 -0
  204. package/dist/toolkit/atlassian/adf_validator.d.ts.map +1 -0
  205. package/dist/toolkit/atlassian/adf_validator.js +83 -0
  206. package/dist/toolkit/atlassian/adf_validator.js.map +1 -0
  207. package/dist/toolkit/atlassian/index.d.ts +5 -0
  208. package/dist/toolkit/atlassian/index.d.ts.map +1 -0
  209. package/dist/toolkit/atlassian/index.js +5 -0
  210. package/dist/toolkit/atlassian/index.js.map +1 -0
  211. package/dist/toolkit/audit/writer.d.ts.map +1 -1
  212. package/dist/toolkit/audit/writer.js +45 -5
  213. package/dist/toolkit/audit/writer.js.map +1 -1
  214. package/dist/toolkit/connector_error.d.ts +12 -0
  215. package/dist/toolkit/connector_error.d.ts.map +1 -0
  216. package/dist/toolkit/connector_error.js +18 -0
  217. package/dist/toolkit/connector_error.js.map +1 -0
  218. package/dist/toolkit/guardrail.d.ts +12 -2
  219. package/dist/toolkit/guardrail.d.ts.map +1 -1
  220. package/dist/toolkit/guardrail.js +17 -3
  221. package/dist/toolkit/guardrail.js.map +1 -1
  222. package/dist/toolkit/http_client.d.ts +134 -0
  223. package/dist/toolkit/http_client.d.ts.map +1 -0
  224. package/dist/toolkit/http_client.js +385 -0
  225. package/dist/toolkit/http_client.js.map +1 -0
  226. package/dist/toolkit/index.d.ts +3 -0
  227. package/dist/toolkit/index.d.ts.map +1 -1
  228. package/dist/toolkit/index.js +5 -0
  229. package/dist/toolkit/index.js.map +1 -1
  230. package/dist/toolkit/usage/aggregate.d.ts.map +1 -1
  231. package/dist/toolkit/usage/aggregate.js +19 -3
  232. package/dist/toolkit/usage/aggregate.js.map +1 -1
  233. package/package.json +14 -2
  234. package/plugin-hooks/dispatcher.mjs +639 -0
  235. package/plugin-hooks/plugin-config.mjs +36 -0
  236. package/plugins/{aws-agent → aws-connector}/.claude-plugin/plugin.json +1 -1
  237. package/plugins/{aws-agent → aws-connector}/README.md +7 -7
  238. package/plugins/{aws-agent/bin/aws-agent → aws-connector/bin/aws-connector} +3 -3
  239. package/plugins/aws-connector/commands/aws-connector.md +6 -0
  240. package/plugins/{gcp-agent → aws-connector}/hooks/hooks.json +12 -11
  241. package/plugins/aws-connector/package.json +9 -0
  242. package/plugins/aws-connector/plugin-config.json +4 -0
  243. package/plugins/{aws-agent/skills/aws-agent → aws-connector/skills/aws-connector}/SKILL.md +5 -5
  244. package/plugins/confluence-connector/.claude-plugin/plugin.json +6 -0
  245. package/plugins/{confluence-agent → confluence-connector}/README.md +2 -2
  246. package/plugins/confluence-connector/bin/confluence-connector +17 -0
  247. package/plugins/confluence-connector/commands/confluence-connector.md +6 -0
  248. package/plugins/{jira-agent → confluence-connector}/hooks/hooks.json +12 -11
  249. package/plugins/confluence-connector/package.json +8 -0
  250. package/plugins/confluence-connector/plugin-config.json +4 -0
  251. package/plugins/confluence-connector/skills/confluence-connector/SKILL.md +146 -0
  252. package/plugins/{create-connector → connector-creator}/.claude-plugin/plugin.json +1 -1
  253. package/plugins/{create-connector → connector-creator}/README.md +2 -2
  254. package/plugins/connector-creator/skills/connector-creator/SKILL.md +412 -0
  255. package/plugins/connector-creator/skills/connector-creator/assets/templates/_runtime/connector-gate.mjs.tmpl +120 -0
  256. package/plugins/connector-creator/skills/connector-creator/assets/templates/composite/SKILL.md.tmpl +26 -0
  257. package/plugins/connector-creator/skills/connector-creator/assets/templates/composite/bin.tmpl +2 -0
  258. package/plugins/connector-creator/skills/connector-creator/assets/templates/composite/index.mjs.tmpl +35 -0
  259. package/plugins/connector-creator/skills/connector-creator/assets/templates/knowledge/SKILL.md.tmpl +23 -0
  260. package/plugins/connector-creator/skills/connector-creator/assets/templates/shell-gate/SKILL.md.tmpl +27 -0
  261. package/plugins/connector-creator/skills/connector-creator/assets/templates/shell-gate/gates.json.tmpl +5 -0
  262. package/plugins/connector-creator/skills/connector-creator/lib/connector-registry.mjs +43 -0
  263. package/plugins/connector-creator/skills/connector-creator/lib/settings-wiring.mjs +71 -0
  264. package/plugins/connector-creator/skills/connector-creator/references/connector-contract.md +79 -0
  265. package/plugins/connector-creator/skills/connector-creator/references/flavor-authoring.md +58 -0
  266. package/plugins/connector-creator/skills/connector-creator/references/research-patterns.md +51 -0
  267. package/plugins/{db-agent → db-connector}/.claude-plugin/plugin.json +3 -3
  268. package/plugins/{db-agent → db-connector}/README.md +2 -2
  269. package/plugins/{github-agent/bin/github-agent → db-connector/bin/db-connector} +3 -3
  270. package/plugins/db-connector/commands/db-connector.md +6 -0
  271. package/plugins/db-connector/gates.json +45 -0
  272. package/plugins/db-connector/gates.strict-bare.json +13 -0
  273. package/plugins/{db-agent → db-connector}/hooks/guardrails.json +4 -2
  274. package/plugins/{aws-agent → db-connector}/hooks/hooks.json +15 -11
  275. package/plugins/{db-agent → db-connector}/package.json +1 -1
  276. package/plugins/db-connector/plugin-config.json +5 -0
  277. package/plugins/{db-agent/skills/db-agent → db-connector/skills/db-connector}/SKILL.md +5 -5
  278. package/plugins/{gcp-agent → gcp-connector}/.claude-plugin/plugin.json +1 -1
  279. package/plugins/{gcp-agent → gcp-connector}/README.md +5 -5
  280. package/plugins/{gcp-agent/bin/gcp-agent → gcp-connector/bin/gcp-connector} +3 -3
  281. package/plugins/gcp-connector/commands/gcp-connector.md +6 -0
  282. package/plugins/{github-agent → gcp-connector}/hooks/hooks.json +12 -11
  283. package/plugins/gcp-connector/package.json +9 -0
  284. package/plugins/gcp-connector/plugin-config.json +4 -0
  285. package/plugins/{gcp-agent/skills/gcp-agent → gcp-connector/skills/gcp-connector}/SKILL.md +5 -5
  286. package/plugins/git-connector/.claude-plugin/plugin.json +6 -0
  287. package/plugins/git-connector/CONTRIBUTING.md +117 -0
  288. package/plugins/git-connector/README.md +94 -0
  289. package/plugins/git-connector/SECURITY.md +143 -0
  290. package/plugins/git-connector/gates.json +67 -0
  291. package/plugins/git-connector/hooks/hooks.json +25 -0
  292. package/plugins/git-connector/package.json +9 -0
  293. package/plugins/git-connector/plugin-config.json +4 -0
  294. package/plugins/{github-agent → github-connector}/.claude-plugin/plugin.json +1 -1
  295. package/plugins/github-connector/README.md +48 -0
  296. package/plugins/{confluence-agent/bin/confluence-agent → github-connector/bin/github-connector} +3 -3
  297. package/plugins/github-connector/commands/github-connector.md +6 -0
  298. package/plugins/github-connector/hooks/hooks.json +50 -0
  299. package/plugins/{jira-agent → github-connector}/package.json +1 -1
  300. package/plugins/github-connector/plugin-config.json +4 -0
  301. package/plugins/github-connector/skills/github-connector/SKILL.md +106 -0
  302. package/plugins/gitlab-connector/.claude-plugin/plugin.json +6 -0
  303. package/plugins/gitlab-connector/README.md +62 -0
  304. package/plugins/{db-agent/bin/db-agent → gitlab-connector/bin/gitlab-connector} +3 -3
  305. package/plugins/gitlab-connector/commands/gitlab-connector.md +6 -0
  306. package/plugins/gitlab-connector/gates.json +18 -0
  307. package/plugins/gitlab-connector/hooks/hooks.json +50 -0
  308. package/plugins/{confluence-agent → gitlab-connector}/package.json +1 -1
  309. package/plugins/gitlab-connector/plugin-config.json +4 -0
  310. package/plugins/gitlab-connector/skills/gitlab-connector/SKILL.md +115 -0
  311. package/plugins/jira-connector/.claude-plugin/plugin.json +6 -0
  312. package/plugins/{jira-agent → jira-connector}/README.md +1 -1
  313. package/plugins/{jira-agent/bin/jira-agent → jira-connector/bin/jira-connector} +2 -2
  314. package/plugins/jira-connector/commands/jira-connector.md +6 -0
  315. package/plugins/jira-connector/gates.json +12 -0
  316. package/plugins/jira-connector/hooks/hooks.json +50 -0
  317. package/plugins/{github-agent → jira-connector}/package.json +1 -1
  318. package/plugins/jira-connector/plugin-config.json +4 -0
  319. package/plugins/jira-connector/skills/jira-connector/SKILL.md +146 -0
  320. package/plugins/linear-connector/.claude-plugin/plugin.json +6 -0
  321. package/plugins/linear-connector/README.md +29 -0
  322. package/plugins/linear-connector/bin/linear-connector +17 -0
  323. package/plugins/linear-connector/commands/linear-connector.md +6 -0
  324. package/plugins/linear-connector/hooks/hooks.json +50 -0
  325. package/plugins/linear-connector/package.json +8 -0
  326. package/plugins/linear-connector/plugin-config.json +4 -0
  327. package/plugins/linear-connector/skills/linear-connector/SKILL.md +159 -0
  328. package/plugins/notion-connector/.claude-plugin/plugin.json +6 -0
  329. package/plugins/{notion-agent → notion-connector}/README.md +5 -5
  330. package/plugins/{notion-agent/bin/notion-agent → notion-connector/bin/notion-connector} +2 -2
  331. package/plugins/notion-connector/commands/notion-connector.md +6 -0
  332. package/plugins/notion-connector/hooks/hooks.json +50 -0
  333. package/plugins/notion-connector/package.json +8 -0
  334. package/plugins/notion-connector/plugin-config.json +4 -0
  335. package/plugins/notion-connector/skills/notion-connector/SKILL.md +141 -0
  336. package/dist/connectors/confluence/lib/confluence_error.d.ts +0 -13
  337. package/dist/connectors/confluence/lib/confluence_error.d.ts.map +0 -1
  338. package/dist/connectors/confluence/lib/confluence_error.js +0 -19
  339. package/dist/connectors/confluence/lib/confluence_error.js.map +0 -1
  340. package/dist/connectors/github/lib/github_error.d.ts +0 -11
  341. package/dist/connectors/github/lib/github_error.d.ts.map +0 -1
  342. package/dist/connectors/github/lib/github_error.js +0 -17
  343. package/dist/connectors/github/lib/github_error.js.map +0 -1
  344. package/dist/connectors/jira/lib/jira_error.d.ts +0 -11
  345. package/dist/connectors/jira/lib/jira_error.d.ts.map +0 -1
  346. package/dist/connectors/jira/lib/jira_error.js +0 -17
  347. package/dist/connectors/jira/lib/jira_error.js.map +0 -1
  348. package/dist/connectors/notion/lib/notion_error.d.ts +0 -12
  349. package/dist/connectors/notion/lib/notion_error.d.ts.map +0 -1
  350. package/dist/connectors/notion/lib/notion_error.js +0 -18
  351. package/dist/connectors/notion/lib/notion_error.js.map +0 -1
  352. package/plugins/aws-agent/commands/aws-agent.md +0 -6
  353. package/plugins/aws-agent/hooks/reminder.mjs +0 -16
  354. package/plugins/aws-agent/package.json +0 -9
  355. package/plugins/confluence-agent/.claude-plugin/plugin.json +0 -6
  356. package/plugins/confluence-agent/commands/confluence-agent.md +0 -6
  357. package/plugins/confluence-agent/hooks/hooks.json +0 -49
  358. package/plugins/confluence-agent/hooks/reminder.mjs +0 -25
  359. package/plugins/confluence-agent/skills/confluence-agent/SKILL.md +0 -40
  360. package/plugins/create-connector/skills/create-connector/SKILL.md +0 -252
  361. package/plugins/db-agent/commands/db-agent.md +0 -6
  362. package/plugins/db-agent/hooks/db-guard.mjs +0 -110
  363. package/plugins/db-agent/hooks/hooks.json +0 -61
  364. package/plugins/db-agent/hooks/reminder.mjs +0 -16
  365. package/plugins/gcp-agent/commands/gcp-agent.md +0 -6
  366. package/plugins/gcp-agent/hooks/reminder.mjs +0 -16
  367. package/plugins/gcp-agent/package.json +0 -9
  368. package/plugins/github-agent/README.md +0 -13
  369. package/plugins/github-agent/commands/github-agent.md +0 -6
  370. package/plugins/github-agent/hooks/reminder.mjs +0 -16
  371. package/plugins/github-agent/skills/github-agent/SKILL.md +0 -41
  372. package/plugins/jira-agent/.claude-plugin/plugin.json +0 -6
  373. package/plugins/jira-agent/commands/jira-agent.md +0 -6
  374. package/plugins/jira-agent/hooks/reminder.mjs +0 -16
  375. package/plugins/jira-agent/skills/jira-agent/SKILL.md +0 -37
  376. package/plugins/notion-agent/.claude-plugin/plugin.json +0 -6
  377. package/plugins/notion-agent/commands/notion-agent.md +0 -6
  378. package/plugins/notion-agent/hooks/hooks.json +0 -49
  379. package/plugins/notion-agent/hooks/reminder.mjs +0 -17
  380. package/plugins/notion-agent/package.json +0 -8
  381. package/plugins/notion-agent/skills/notion-agent/SKILL.md +0 -48
  382. /package/plugins/{create-connector/skills/create-connector → connector-creator/skills/connector-creator}/assets/templates/bin.tmpl +0 -0
  383. /package/plugins/{create-connector/skills/create-connector → connector-creator/skills/connector-creator}/assets/templates/connector-SKILL.md.tmpl +0 -0
  384. /package/plugins/{create-connector/skills/create-connector → connector-creator/skills/connector-creator}/assets/templates/index.mjs.tmpl +0 -0
  385. /package/plugins/{create-connector/skills/create-connector → connector-creator/skills/connector-creator}/assets/templates/tests-example.mjs.tmpl +0 -0
  386. /package/plugins/{create-connector/skills/create-connector → connector-creator/skills/connector-creator}/references/action-design.md +0 -0
  387. /package/plugins/{create-connector/skills/create-connector → connector-creator/skills/connector-creator}/references/auth-patterns.md +0 -0
  388. /package/plugins/{create-connector/skills/create-connector → connector-creator/skills/connector-creator}/references/connector-anatomy.md +0 -0
  389. /package/plugins/{create-connector/skills/create-connector/references/db-agent-pointer.md → connector-creator/skills/connector-creator/references/db-connector-pointer.md} +0 -0
  390. /package/plugins/{create-connector/skills/create-connector → connector-creator/skills/connector-creator}/references/plugin-layer.md +0 -0
  391. /package/plugins/{create-connector/skills/create-connector → connector-creator/skills/connector-creator}/references/template-sync.md +0 -0
  392. /package/plugins/{create-connector/skills/create-connector → connector-creator/skills/connector-creator}/references/verification.md +0 -0
@@ -0,0 +1,639 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Shared PreToolUse / PostToolUse / SessionStart / SessionEnd dispatcher
4
+ * for narai-primitives builtin Claude Code plugins.
5
+ *
6
+ * Usage:
7
+ * node dispatcher.mjs <event>
8
+ *
9
+ * Where <event> is one of: session-start, pre-tool-use, post-tool-use,
10
+ * session-end. Reads ${CLAUDE_PLUGIN_ROOT}/plugin-config.json for the
11
+ * plugin's identity and routes to the appropriate handler.
12
+ *
13
+ * Best-effort: handler-internal failures are logged to stderr but do not
14
+ * block tool execution. Argument / configuration errors exit with a
15
+ * non-zero code so Claude Code surfaces them to the operator.
16
+ */
17
+ import * as fs from "node:fs";
18
+ import * as path from "node:path";
19
+ import { fileURLToPath, pathToFileURL } from "node:url";
20
+ import { parsePluginConfig } from "./plugin-config.mjs";
21
+
22
+ const VALID_EVENTS = new Set([
23
+ "session-start",
24
+ "pre-tool-use",
25
+ "post-tool-use",
26
+ "session-end",
27
+ ]);
28
+
29
+ // Only run main() when invoked as a CLI, not when imported by tests.
30
+ // Resolve symlinks on both sides so the smart-bootstrap dedup path
31
+ // (where `node_modules/narai-primitives` is symlinked from a sibling
32
+ // plugin) still recognizes itself as the CLI entrypoint.
33
+ const isMainScript = (() => {
34
+ if (process.argv[1] === undefined) return false;
35
+ try {
36
+ const realArgv = fs.realpathSync(process.argv[1]);
37
+ const realSelf = fs.realpathSync(fileURLToPath(import.meta.url));
38
+ return realArgv === realSelf;
39
+ } catch {
40
+ // Fall back to literal comparison if realpath can't resolve.
41
+ return process.argv[1] === fileURLToPath(import.meta.url);
42
+ }
43
+ })();
44
+
45
+ if (isMainScript) {
46
+ main().catch((err) => {
47
+ process.stderr.write(`dispatcher: ${err?.message ?? err}\n`);
48
+ process.exit(1);
49
+ });
50
+ }
51
+
52
+ async function main() {
53
+ const event = process.argv[2];
54
+ if (!VALID_EVENTS.has(event)) {
55
+ process.stderr.write(
56
+ `dispatcher: unknown event '${event}' (expected one of ${[...VALID_EVENTS].join(", ")})\n`,
57
+ );
58
+ process.exit(2);
59
+ }
60
+
61
+ const root = process.env.CLAUDE_PLUGIN_ROOT;
62
+ if (!root) {
63
+ process.stderr.write("dispatcher: CLAUDE_PLUGIN_ROOT not set\n");
64
+ process.exit(2);
65
+ }
66
+
67
+ const cfgPath = path.join(root, "plugin-config.json");
68
+ if (!fs.existsSync(cfgPath)) {
69
+ process.stderr.write(`dispatcher: missing ${cfgPath}\n`);
70
+ process.exit(2);
71
+ }
72
+ const cfg = parsePluginConfig(fs.readFileSync(cfgPath, "utf-8"));
73
+
74
+ switch (event) {
75
+ case "session-start":
76
+ await onSessionStart(cfg);
77
+ break;
78
+ case "pre-tool-use":
79
+ await onPreToolUse(cfg);
80
+ break;
81
+ case "post-tool-use":
82
+ await onPostToolUse(cfg);
83
+ break;
84
+ case "session-end":
85
+ await onSessionEnd(cfg);
86
+ break;
87
+ }
88
+ process.exit(0);
89
+ }
90
+
91
+ async function loadToolkit() {
92
+ const { existsSync } = fs;
93
+ const { homedir } = await import("node:os");
94
+ const { fileURLToPath, pathToFileURL } = await import("node:url");
95
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
96
+ const candidates = [
97
+ // 1. Bundled: dispatcher at narai-primitives/plugin-hooks/; toolkit at narai-primitives/dist/toolkit/guardrail.js
98
+ path.join(__dirname, "..", "dist", "toolkit", "guardrail.js"),
99
+ // 2. Claude Code plugin install
100
+ process.env.CLAUDE_PLUGIN_DATA
101
+ ? path.join(process.env.CLAUDE_PLUGIN_DATA, "node_modules", "narai-primitives", "dist", "toolkit", "guardrail.js")
102
+ : null,
103
+ ].filter((p) => p !== null);
104
+ for (const p of candidates) {
105
+ if (!existsSync(p)) continue;
106
+ try {
107
+ return await import(pathToFileURL(p).href);
108
+ } catch {
109
+ // try next
110
+ }
111
+ }
112
+ return null;
113
+ }
114
+
115
+ /**
116
+ * Lazily load the db audit module from dist. Returns the module namespace
117
+ * ({ enableAudit, logEvent, scrubSqlSecrets, ... }) or null if unavailable.
118
+ * Only used when NARAI_AUDIT_PATH is set, so the common path stays cheap.
119
+ */
120
+ async function loadAudit() {
121
+ const { existsSync } = fs;
122
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
123
+ const candidates = [
124
+ path.join(__dirname, "..", "dist", "connectors", "db", "lib", "audit.js"),
125
+ process.env.CLAUDE_PLUGIN_DATA
126
+ ? path.join(process.env.CLAUDE_PLUGIN_DATA, "node_modules", "narai-primitives", "dist", "connectors", "db", "lib", "audit.js")
127
+ : null,
128
+ ].filter((p) => p !== null);
129
+ for (const p of candidates) {
130
+ if (!existsSync(p)) continue;
131
+ try {
132
+ return await import(pathToFileURL(p).href);
133
+ } catch {
134
+ // try next
135
+ }
136
+ }
137
+ return null;
138
+ }
139
+
140
+ /**
141
+ * Walk siblings of `pluginDataDir` looking for a `node_modules/narai-primitives`
142
+ * at `wantedVersion`. Returns the matched node_modules path, or null if no
143
+ * usable sibling found. Used to skip redundant npm install when N builtin
144
+ * plugins are loaded in the same Claude Code session.
145
+ */
146
+ export function findSiblingInstall(pluginDataDir, wantedVersion) {
147
+ const parent = path.dirname(pluginDataDir);
148
+ let entries;
149
+ try {
150
+ entries = fs.readdirSync(parent, { withFileTypes: true });
151
+ } catch {
152
+ return null;
153
+ }
154
+ for (const entry of entries) {
155
+ if (!entry.isDirectory()) continue;
156
+ const candidate = path.join(parent, entry.name);
157
+ if (candidate === pluginDataDir) continue;
158
+ const pkgJson = path.join(
159
+ candidate,
160
+ "node_modules",
161
+ "narai-primitives",
162
+ "package.json",
163
+ );
164
+ if (!fs.existsSync(pkgJson)) continue;
165
+ try {
166
+ const meta = JSON.parse(fs.readFileSync(pkgJson, "utf-8"));
167
+ if (meta.version === wantedVersion) {
168
+ return path.join(candidate, "node_modules");
169
+ }
170
+ } catch {
171
+ continue;
172
+ }
173
+ }
174
+ return null;
175
+ }
176
+
177
+ async function onSessionStart(cfg) {
178
+ const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
179
+ const pluginData = process.env.CLAUDE_PLUGIN_DATA;
180
+ if (!pluginRoot || !pluginData) return;
181
+
182
+ await ensureBootstrap(pluginRoot, pluginData);
183
+
184
+ // Best-effort: emit nudge banner if the toolkit is reachable.
185
+ try {
186
+ const reminderPath = path.join(
187
+ pluginData,
188
+ "node_modules",
189
+ "narai-primitives",
190
+ "dist",
191
+ "toolkit",
192
+ "plugin",
193
+ "reminder.js",
194
+ );
195
+ if (fs.existsSync(reminderPath)) {
196
+ // pathToFileURL is required on Windows — Node refuses raw absolute
197
+ // paths as ESM specifiers (ERR_UNSUPPORTED_ESM_URL_SCHEME).
198
+ const mod = await import(pathToFileURL(reminderPath).href);
199
+ const decision = mod.evaluateNudge({ connectors: [cfg.name] });
200
+ if (decision.nudge) process.stdout.write(decision.banner + "\n");
201
+ }
202
+ } catch (err) {
203
+ process.stderr.write(`dispatcher: nudge failed (${err.message})\n`);
204
+ }
205
+
206
+ // Best-effort: stale-summarize.
207
+ try {
208
+ const stalePath = path.join(
209
+ pluginData,
210
+ "node_modules",
211
+ "narai-primitives",
212
+ "plugin-hooks",
213
+ "stale-summarize.mjs",
214
+ );
215
+ if (fs.existsSync(stalePath)) {
216
+ process.env.USAGE_CONNECTOR_NAME = cfg.name;
217
+ await import(pathToFileURL(stalePath).href);
218
+ }
219
+ } catch (err) {
220
+ process.stderr.write(`dispatcher: stale-summarize failed (${err.message})\n`);
221
+ }
222
+ }
223
+
224
+ async function onPreToolUse(cfg) {
225
+ const stdin = await readStdin();
226
+ if (!stdin) return;
227
+ let payload;
228
+ try {
229
+ payload = JSON.parse(stdin);
230
+ } catch {
231
+ // Unparseable tool input: under fail-closed, deny rather than fall open.
232
+ // Env-only here (there is no manifest to read an enforcement field from).
233
+ if (effectiveEnforcement(undefined) === "fail_closed") {
234
+ process.stdout.write(JSON.stringify({
235
+ hookSpecificOutput: {
236
+ hookEventName: "PreToolUse",
237
+ permissionDecision: "deny",
238
+ permissionDecisionReason: "fail-closed: unparseable tool input/command",
239
+ },
240
+ }));
241
+ }
242
+ return;
243
+ }
244
+ // Derive the tool being gated and the text to scan. Bash scans the
245
+ // command; Write scans the file content; Edit scans the incoming text
246
+ // (new_string only — old_string is the text being removed). `command`
247
+ // therefore holds the candidate text for whichever tool fired.
248
+ let scanTool;
249
+ let command;
250
+ if (payload.tool_name === "Bash") {
251
+ scanTool = "Bash";
252
+ command = payload.tool_input?.command;
253
+ } else if (payload.tool_name === "Write") {
254
+ scanTool = "Write";
255
+ command = payload.tool_input?.content;
256
+ } else if (payload.tool_name === "Edit") {
257
+ scanTool = "Edit";
258
+ command = payload.tool_input?.new_string;
259
+ } else {
260
+ return;
261
+ }
262
+ if (typeof command !== "string" || command.length === 0) return;
263
+
264
+ const decisions = [];
265
+
266
+ // 1. db-guard (Bash only; only if kind=db, and not opted out via user_config).
267
+ // The token-blocklist engine is command-shaped and meaningless for file content.
268
+ if (scanTool === "Bash" && cfg.kind === "db" && process.env.DB_AGENT_GUARDRAILS !== "off") {
269
+ const guardrailsPath = path.join(
270
+ process.env.CLAUDE_PLUGIN_ROOT,
271
+ "hooks",
272
+ "guardrails.json",
273
+ );
274
+ if (fs.existsSync(guardrailsPath)) {
275
+ // Cheap pre-read of the manifest's own `enforcement` field so the
276
+ // engine-unavailable and engine-throw paths below can honor a
277
+ // `fail_closed` declared by the manifest, not only the env var. If the
278
+ // file itself will not parse, this stays undefined (env-only), matching
279
+ // the documented "a fully corrupt manifest needs the env var" rule.
280
+ let dbEnforcement;
281
+ try {
282
+ dbEnforcement = JSON.parse(fs.readFileSync(guardrailsPath, "utf-8")).enforcement;
283
+ } catch {
284
+ dbEnforcement = undefined;
285
+ }
286
+ try {
287
+ const toolkit = await loadToolkit();
288
+ if (toolkit && typeof toolkit.findBlockingRule === "function") {
289
+ const { findBlockingRule, defaultDenyMessage, loadGuardrailManifest } = toolkit;
290
+ const manifest = loadGuardrailManifest(guardrailsPath);
291
+ const match = findBlockingRule(command, [manifest]);
292
+ if (match) {
293
+ decisions.push({
294
+ decision: "deny",
295
+ reason: defaultDenyMessage(match),
296
+ });
297
+ }
298
+ } else if (effectiveEnforcement(dbEnforcement) === "fail_closed") {
299
+ decisions.push({
300
+ decision: "deny",
301
+ reason: "fail-closed enforcement: db guardrail engine is unavailable",
302
+ });
303
+ }
304
+ } catch (err) {
305
+ process.stderr.write(`dispatcher: db-guard failed (${err.message})\n`);
306
+ if (effectiveEnforcement(dbEnforcement) === "fail_closed") {
307
+ decisions.push({
308
+ decision: "deny",
309
+ reason: `fail-closed enforcement: db guardrail manifest could not be evaluated (${err.message})`,
310
+ });
311
+ }
312
+ }
313
+ }
314
+ }
315
+
316
+ // 2. user-connector gates from $HOME and cwd. Mirror connector-gate.mjs:
317
+ // honor NARAI_GATE_DISABLE (comma-separated rule names) so operators
318
+ // can silence a noisy rule without editing gates.json.
319
+ const disabled = new Set(
320
+ (process.env.NARAI_GATE_DISABLE ?? "")
321
+ .split(",")
322
+ .map((s) => s.trim())
323
+ .filter(Boolean),
324
+ );
325
+ // 3. plugin-shipped gates.json at CLAUDE_PLUGIN_ROOT/gates.json — lets
326
+ // hook-only plugins (e.g. git-connector) ship default rules out-of-the-box.
327
+ const pluginGatesFile = path.join(process.env.CLAUDE_PLUGIN_ROOT, "gates.json");
328
+ if (fs.existsSync(pluginGatesFile)) {
329
+ try {
330
+ const gateCfg = JSON.parse(fs.readFileSync(pluginGatesFile, "utf-8"));
331
+ applyGatesManifest(gateCfg, cfg.name, command, disabled, decisions, scanTool);
332
+ } catch (err) {
333
+ process.stderr.write(
334
+ `dispatcher: plugin-root gate scan failed (${err.message})\n`,
335
+ );
336
+ if (effectiveEnforcement(undefined) === "fail_closed") {
337
+ decisions.push({
338
+ decision: "deny",
339
+ reason: `fail-closed enforcement: gates manifest at ${pluginGatesFile} could not be parsed`,
340
+ });
341
+ }
342
+ }
343
+ }
344
+
345
+ // 4. user-connector gates from $HOME and cwd.
346
+ const home = process.env.HOME ?? "";
347
+ const cwd = process.cwd();
348
+ for (const root of [home, cwd]) {
349
+ if (!root) continue;
350
+ const gatesDir = path.join(root, ".connectors", "connectors");
351
+ if (!fs.existsSync(gatesDir)) continue;
352
+ let slugs;
353
+ try {
354
+ slugs = fs
355
+ .readdirSync(gatesDir, { withFileTypes: true })
356
+ .filter((e) => e.isDirectory())
357
+ .map((e) => e.name);
358
+ } catch {
359
+ continue;
360
+ }
361
+ for (const slug of slugs) {
362
+ const gatesFile = path.join(gatesDir, slug, "gates.json");
363
+ if (!fs.existsSync(gatesFile)) continue;
364
+ try {
365
+ const gateCfg = JSON.parse(fs.readFileSync(gatesFile, "utf-8"));
366
+ applyGatesManifest(gateCfg, slug, command, disabled, decisions, scanTool);
367
+ } catch (err) {
368
+ process.stderr.write(
369
+ `dispatcher: gate scan failed for ${gatesFile} (${err.message})\n`,
370
+ );
371
+ if (effectiveEnforcement(undefined) === "fail_closed") {
372
+ decisions.push({
373
+ decision: "deny",
374
+ reason: `fail-closed enforcement: gates manifest at ${gatesFile} could not be parsed`,
375
+ });
376
+ }
377
+ }
378
+ }
379
+ }
380
+
381
+ if (decisions.length === 0) return;
382
+ const rank = { deny: 2, ask: 1, allow: 0 };
383
+ decisions.sort((a, b) => rank[b.decision] - rank[a.decision]);
384
+ const winner = decisions[0];
385
+ process.stdout.write(JSON.stringify({
386
+ hookSpecificOutput: {
387
+ hookEventName: "PreToolUse",
388
+ permissionDecision: winner.decision,
389
+ permissionDecisionReason: winner.reason,
390
+ },
391
+ }));
392
+
393
+ // Best-effort audit of blocked/escalated decisions. Only runs when an
394
+ // audit destination is configured, keeping the common allow path cheap.
395
+ const auditPath = process.env.NARAI_AUDIT_PATH;
396
+ if (auditPath && (winner.decision === "deny" || winner.decision === "ask")) {
397
+ try {
398
+ const audit = await loadAudit();
399
+ if (audit && typeof audit.logEvent === "function") {
400
+ audit.enableAudit(auditPath);
401
+ const scrub = typeof audit.scrubSqlSecrets === "function"
402
+ ? audit.scrubSqlSecrets
403
+ : (s) => s;
404
+ audit.logEvent({
405
+ event_type: winner.decision === "deny" ? "guardrail_deny" : "guardrail_ask",
406
+ details: { tool: payload.tool_name, command: scrub(command), reason: winner.reason },
407
+ });
408
+ }
409
+ } catch (err) {
410
+ process.stderr.write(`dispatcher: decision audit failed (${err.message})\n`);
411
+ }
412
+ }
413
+ }
414
+
415
+ async function readStdin() {
416
+ const chunks = [];
417
+ for await (const chunk of process.stdin) chunks.push(chunk);
418
+ return Buffer.concat(chunks).toString("utf-8").trim();
419
+ }
420
+ async function onPostToolUse(cfg) {
421
+ const pluginData = process.env.CLAUDE_PLUGIN_DATA;
422
+ if (!pluginData) return;
423
+ const usagePath = path.join(
424
+ pluginData,
425
+ "node_modules",
426
+ "narai-primitives",
427
+ "plugin-hooks",
428
+ "usage-record.mjs",
429
+ );
430
+ if (!fs.existsSync(usagePath)) return;
431
+ process.env.USAGE_CONNECTOR_NAME = cfg.name;
432
+ if (cfg.binPath) process.env.USAGE_BIN_HINT = cfg.binPath;
433
+ try {
434
+ await import(pathToFileURL(usagePath).href);
435
+ } catch (err) {
436
+ process.stderr.write(`dispatcher: usage-record failed (${err.message})\n`);
437
+ }
438
+ }
439
+ async function onSessionEnd(cfg) {
440
+ const pluginData = process.env.CLAUDE_PLUGIN_DATA;
441
+ if (!pluginData) return;
442
+ const summaryPath = path.join(
443
+ pluginData,
444
+ "node_modules",
445
+ "narai-primitives",
446
+ "plugin-hooks",
447
+ "session-summary.mjs",
448
+ );
449
+ if (!fs.existsSync(summaryPath)) return;
450
+ // session-summary.mjs only runs its `main()` when it's the CLI entry
451
+ // point (`import.meta.url === file://${process.argv[1]}`). Importing it
452
+ // here would be a no-op; spawn it as a subprocess so the guard passes.
453
+ try {
454
+ const { spawnSync } = await import("node:child_process");
455
+ spawnSync("node", [summaryPath], {
456
+ stdio: "inherit",
457
+ env: { ...process.env, USAGE_CONNECTOR_NAME: cfg.name },
458
+ });
459
+ } catch (err) {
460
+ process.stderr.write(`dispatcher: session-summary failed (${err.message})\n`);
461
+ }
462
+ }
463
+
464
+ /**
465
+ * Ensure narai-primitives is installed in pluginData. Tries (in order):
466
+ * 1. Skip if already installed at the right version.
467
+ * 2. Symlink from a sibling plugin's node_modules.
468
+ * 3. npm install in pluginData.
469
+ *
470
+ * Best-effort: all branches return without throwing. The caller proceeds
471
+ * to side effects (nudge, stale-summarize, etc.) even when the install
472
+ * is cached, so recurring per-session behavior fires every run.
473
+ */
474
+ async function ensureBootstrap(pluginRoot, pluginData) {
475
+ const rootPkg = path.join(pluginRoot, "package.json");
476
+ if (!fs.existsSync(rootPkg)) return;
477
+ let rootMeta;
478
+ try {
479
+ rootMeta = JSON.parse(fs.readFileSync(rootPkg, "utf-8"));
480
+ } catch {
481
+ return;
482
+ }
483
+ // Read the wanted narai-primitives version from the plugin's
484
+ // `dependencies` block (e.g. `"^2.1.3"`) and strip the semver
485
+ // prefix so the equality check matches the installed package's
486
+ // resolved version field (e.g. `"2.1.3"`). The plugin's own
487
+ // `version` is independent and not interchangeable.
488
+ const depRange = rootMeta.dependencies?.["narai-primitives"];
489
+ const wantVersion = depRange?.replace(/^[\^~>=< ]+/, "");
490
+ if (!wantVersion) return;
491
+
492
+ fs.mkdirSync(pluginData, { recursive: true });
493
+
494
+ const myInstall = path.join(pluginData, "node_modules", "narai-primitives");
495
+ if (fs.existsSync(myInstall)) {
496
+ try {
497
+ const installed = JSON.parse(
498
+ fs.readFileSync(path.join(myInstall, "package.json"), "utf-8"),
499
+ );
500
+ if (installed.version === wantVersion) return;
501
+ } catch {
502
+ // Fall through to re-install.
503
+ }
504
+ }
505
+
506
+ const sibling = findSiblingInstall(pluginData, wantVersion);
507
+ if (sibling !== null) {
508
+ try {
509
+ const myNodeModules = path.join(pluginData, "node_modules");
510
+ if (fs.existsSync(myNodeModules)) {
511
+ fs.rmSync(myNodeModules, { recursive: true, force: true });
512
+ }
513
+ fs.symlinkSync(sibling, myNodeModules, "dir");
514
+ return;
515
+ } catch {
516
+ // Fall through to install.
517
+ }
518
+ }
519
+
520
+ fs.copyFileSync(rootPkg, path.join(pluginData, "package.json"));
521
+ const { spawnSync } = await import("node:child_process");
522
+ spawnSync("npm", ["install", "--no-audit", "--no-fund"], {
523
+ cwd: pluginData,
524
+ stdio: "inherit",
525
+ });
526
+ }
527
+
528
+ /**
529
+ * Resolve the effective enforcement posture from the global
530
+ * NARAI_GATE_ENFORCEMENT env var and an optional manifest-level field.
531
+ * Strictest wins: fail-closed if either requests it, else fail-open.
532
+ */
533
+ export function effectiveEnforcement(manifestEnforcement) {
534
+ const env = process.env.NARAI_GATE_ENFORCEMENT;
535
+ if (env === "fail_closed" || manifestEnforcement === "fail_closed") {
536
+ return "fail_closed";
537
+ }
538
+ return "fail_open";
539
+ }
540
+
541
+ /**
542
+ * Expand the `__PROTECTED_BRANCHES__` token in a gate pattern into a
543
+ * regex-escaped alternation of the default protected branches (main, master)
544
+ * plus any names in the NARAI_GIT_PROTECTED_BRANCHES env var (comma-separated).
545
+ * Operator-provided names are regex-escaped, so this cannot inject regex.
546
+ * Patterns without the token are returned unchanged (backward compatible).
547
+ */
548
+ export function expandPattern(pattern) {
549
+ if (typeof pattern !== "string" || !pattern.includes("__PROTECTED_BRANCHES__")) {
550
+ return pattern;
551
+ }
552
+ const extra = (process.env.NARAI_GIT_PROTECTED_BRANCHES ?? "")
553
+ .split(",")
554
+ .map((s) => s.trim())
555
+ .filter(Boolean);
556
+ const branches = ["main", "master", ...extra];
557
+ const escaped = branches.map((b) => b.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
558
+ return pattern.replace(/__PROTECTED_BRANCHES__/g, `(?:${escaped.join("|")})`);
559
+ }
560
+
561
+ /**
562
+ * Apply a parsed gates.json manifest to a command. Rules with invalid
563
+ * shape, disabled names, or uncompilable patterns are skipped. Anchored
564
+ * patterns match per-segment so chaining (`echo ok; psql ...`) can't bypass.
565
+ *
566
+ * Under fail-closed enforcement (env var or the manifest's `enforcement`
567
+ * field), a rule whose pattern will not compile becomes a hard deny instead
568
+ * of being silently skipped — we cannot prove the command is safe.
569
+ */
570
+ export function applyGatesManifest(manifest, source, text, disabled, decisions, scanTool = "Bash") {
571
+ const enforcement = effectiveEnforcement(manifest.enforcement);
572
+ // Bash commands are split on chaining operators so anchored rules apply
573
+ // per-segment. File content (Write/Edit) is matched as a single unit so
574
+ // characters like `;` or `|` inside the file do not fragment it. If the
575
+ // splitter throws on pathological input, fail closed denies rather than
576
+ // silently skipping the command.
577
+ let segments;
578
+ try {
579
+ segments = scanTool === "Bash" ? splitCompound(text) : [text];
580
+ } catch {
581
+ if (enforcement === "fail_closed") {
582
+ decisions.push({
583
+ decision: "deny",
584
+ reason: `fail-closed enforcement: ${source} could not tokenize the command`,
585
+ });
586
+ }
587
+ return;
588
+ }
589
+ for (const rule of manifest.rules ?? []) {
590
+ if (
591
+ !["deny", "ask", "allow"].includes(rule.decision) ||
592
+ typeof rule.pattern !== "string"
593
+ ) continue;
594
+ if (typeof rule.name === "string" && disabled.has(rule.name)) continue;
595
+ // A rule applies to a tool only if listed in `applies_to`. Default is
596
+ // Bash-only, so every existing rule keeps its current behavior and is
597
+ // skipped on Write/Edit unless it explicitly opts in.
598
+ const appliesTo = Array.isArray(rule.applies_to) ? rule.applies_to : ["Bash"];
599
+ if (!appliesTo.includes(scanTool)) continue;
600
+ let re;
601
+ try { re = new RegExp(expandPattern(rule.pattern)); } catch {
602
+ if (enforcement === "fail_closed") {
603
+ decisions.push({
604
+ decision: "deny",
605
+ reason: `fail-closed enforcement: ${source} gate rule '${rule.name ?? "rule"}' has an invalid pattern`,
606
+ });
607
+ }
608
+ continue;
609
+ }
610
+ for (const segment of segments) {
611
+ if (re.test(segment)) {
612
+ decisions.push({
613
+ decision: rule.decision,
614
+ reason: rule.reason ?? `${source} gate: ${rule.name ?? "rule"}`,
615
+ });
616
+ break;
617
+ }
618
+ }
619
+ }
620
+ }
621
+
622
+ /**
623
+ * Split a bash command on chaining operators so anchored gate rules
624
+ * apply per-segment. Mirrors connector-gate.mjs's behavior.
625
+ */
626
+ function splitCompound(cmd) {
627
+ const parts = cmd.split(/\s*(?:&&|\|\||;|\|)\s*/);
628
+ return parts
629
+ .map((p) => stripPrefix(p.trim()))
630
+ .filter((p) => p.length > 0);
631
+ }
632
+
633
+ function stripPrefix(s) {
634
+ let cur = s;
635
+ while (/^[A-Za-z_][A-Za-z0-9_]*=\S*\s+/.test(cur)) {
636
+ cur = cur.replace(/^[A-Za-z_][A-Za-z0-9_]*=\S*\s+/, "");
637
+ }
638
+ return cur.replace(/^(sudo|nice|time)\s+/, "");
639
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Parse and validate a plugin-config.json string.
3
+ *
4
+ * Shape:
5
+ * { name: string,
6
+ * binPath?: string,
7
+ * kind?: "connector" | "db" | "hook-only" }
8
+ */
9
+ const VALID_KINDS = new Set(["connector", "db", "hook-only"]);
10
+
11
+ export function parsePluginConfig(raw) {
12
+ let parsed;
13
+ try {
14
+ parsed = JSON.parse(raw);
15
+ } catch (err) {
16
+ throw new Error(`plugin-config.json: invalid JSON — ${err.message}`);
17
+ }
18
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
19
+ throw new Error("plugin-config.json: expected an object");
20
+ }
21
+ if (typeof parsed.name !== "string" || parsed.name.length === 0) {
22
+ throw new Error("plugin-config.json: 'name' must be a non-empty string");
23
+ }
24
+ if (parsed.binPath !== undefined && typeof parsed.binPath !== "string") {
25
+ throw new Error("plugin-config.json: 'binPath' must be a string");
26
+ }
27
+ if (parsed.kind !== undefined && !VALID_KINDS.has(parsed.kind)) {
28
+ throw new Error(
29
+ `plugin-config.json: 'kind' must be one of ${[...VALID_KINDS].join(", ")}`,
30
+ );
31
+ }
32
+ const out = { name: parsed.name };
33
+ if (parsed.binPath !== undefined) out.binPath = parsed.binPath;
34
+ if (parsed.kind !== undefined) out.kind = parsed.kind;
35
+ return out;
36
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "aws-agent-plugin",
2
+ "name": "aws-connector-plugin",
3
3
  "version": "1.1.0",
4
4
  "description": "Read-only AWS connector for Claude Code. Built on narai-primitives (subpath ./aws). Lambda, RDS, S3, CloudWatch.",
5
5
  "author": "narai"