toolfunnel 0.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 (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +324 -0
  3. package/bin/toolfunnel.js +112 -0
  4. package/docs/admin-ui.md +404 -0
  5. package/docs/configuration.md +402 -0
  6. package/docs/hooks-and-gating.md +428 -0
  7. package/docs/logging.md +223 -0
  8. package/docs/management.md +429 -0
  9. package/docs/oauth.md +103 -0
  10. package/docs/setup.md +352 -0
  11. package/docs/tools-and-upstreams.md +469 -0
  12. package/hooks/hooks.manifest.json +27 -0
  13. package/hooks/scripts/.gitkeep +3 -0
  14. package/hooks/scripts/example-audit.js +21 -0
  15. package/hooks/scripts/example-deny-dangerous.js +31 -0
  16. package/mcp/expose.example.json +30 -0
  17. package/mcp/servers/mock-upstream/server.js +170 -0
  18. package/package.json +63 -0
  19. package/src/auth/config.js +172 -0
  20. package/src/auth/install.js +181 -0
  21. package/src/auth/resource-server.js +319 -0
  22. package/src/core/events.js +105 -0
  23. package/src/core/hook-engine.js +275 -0
  24. package/src/core/hook-loader.js +791 -0
  25. package/src/core/hook-runner.js +346 -0
  26. package/src/core/logger.js +169 -0
  27. package/src/core/matcher.js +51 -0
  28. package/src/core/metrics.js +75 -0
  29. package/src/core/tool-registry.js +180 -0
  30. package/src/extend/add-hook.md +142 -0
  31. package/src/extend/add-mcp.md +121 -0
  32. package/src/extend/create-tool.md +132 -0
  33. package/src/extend/howto.js +98 -0
  34. package/src/extend/package.md +154 -0
  35. package/src/mcp/aggregator.js +802 -0
  36. package/src/mcp/expose-store.js +430 -0
  37. package/src/mcp/gated-run.js +194 -0
  38. package/src/mcp/http-transport.js +962 -0
  39. package/src/mcp/mcp-client.js +524 -0
  40. package/src/mcp/protocol.js +466 -0
  41. package/src/mcp/server.js +1240 -0
  42. package/src/packages/packager.js +713 -0
  43. package/src/tools/drift.js +138 -0
  44. package/src/tools/registry.js +468 -0
  45. package/src/tools/tool-state.js +104 -0
  46. package/src/ui/public/app.js +1055 -0
  47. package/src/ui/public/index.html +249 -0
  48. package/src/ui/public/logo.jpg +0 -0
  49. package/src/ui/public/styles.css +535 -0
  50. package/src/ui/server.js +1144 -0
  51. package/tools/scripts/base64.js +139 -0
  52. package/tools/scripts/danger.js +61 -0
  53. package/tools/scripts/echo.js +39 -0
  54. package/tools/scripts/hash.js +101 -0
  55. package/tools/scripts/json.js +109 -0
  56. package/tools/scripts/text-stats.js +131 -0
  57. package/tools/scripts/tf-hook-add.js +152 -0
  58. package/tools/scripts/tf-hook-set.js +113 -0
  59. package/tools/scripts/tf-list.js +195 -0
  60. package/tools/scripts/tf-log.js +83 -0
  61. package/tools/scripts/tf-mcp-add.js +119 -0
  62. package/tools/scripts/tf-mcp-set.js +104 -0
  63. package/tools/scripts/tf-tool-add.js +129 -0
  64. package/tools/scripts/tf-tool-set.js +148 -0
  65. package/tools/scripts/uuid.js +102 -0
  66. package/tools/tools.register.json +171 -0
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * tool-state.js — per-tool ACTIVE/DISABLED overlay for the register.
5
+ *
6
+ * Mirrors a sibling state overlay (see a config file): a small
7
+ * overlay keyed by tool id, written atomically, loaded on startup → survives
8
+ * close/detach (persistent session-to-session). The register (tools.register.json)
9
+ * holds ALL tools; this overlay decides which are surfaced to toolfunnel_list_tools.
10
+ *
11
+ * DEFAULT ON: a tool absent from the overlay is ACTIVE. Only an explicit
12
+ * { enabled: false } disables it. So newly-added tools are active until you
13
+ * untick them — and the file only ever lists the tools you've toggled.
14
+ *
15
+ * THREE independent axes (the visibility MATRIX), all keyed by the surfaced name
16
+ * (a local tool id, OR an upstream's surfaced name `<upstream>_<tool>` / its `as`,
17
+ * OR a meta-tool name like `toolfunnel_list_tools`):
18
+ * - enabled : LEAN-VISIBLE — surfaced by toolfunnel_list_tools AND runnable. Default ON.
19
+ * - hidden : manager-list declutter only (UI/tf_list). Default OFF. INDEPENDENT of enabled.
20
+ * - hot : promoted to the TOP-LEVEL tools/list (injected EVERY turn). Default depends on
21
+ * the tool KIND, supplied by the caller via isToolHot(state,id,defaultHot):
22
+ * meta-tools default hot:true (the management surface), local/upstream default
23
+ * hot:false (opt-in promotion). A disabled tool is never hot.
24
+ *
25
+ * Shape of tools.state.json: { "<id>": { "enabled": false, "hidden": true, "hot": true }, ... }
26
+ *
27
+ * CommonJS, Node built-ins only. Reuses registry.js's atomicWriteJson (temp+rename).
28
+ */
29
+
30
+ const fs = require('node:fs');
31
+ const { atomicWriteJson } = require('./registry');
32
+
33
+ /** Load the overlay ({} if missing/malformed — never throws). */
34
+ function loadToolState(statePath) {
35
+ try {
36
+ const d = JSON.parse(fs.readFileSync(statePath, 'utf8'));
37
+ return (d && typeof d === 'object' && !Array.isArray(d)) ? d : {};
38
+ } catch (_e) {
39
+ return {};
40
+ }
41
+ }
42
+
43
+ /** Default ON: enabled unless the overlay explicitly says enabled:false. */
44
+ function isToolEnabled(state, id) {
45
+ const e = state && state[id];
46
+ return !(e && e.enabled === false);
47
+ }
48
+
49
+ /** Default NOT hidden: hidden only when the overlay explicitly says hidden:true.
50
+ * `hidden` is a manager-list-only flag (declutter); it is INDEPENDENT of `enabled`
51
+ * (MCP visibility). A tool can be active-but-hidden, or disabled-but-visible. */
52
+ function isToolHidden(state, id) {
53
+ const e = state && state[id];
54
+ return !!(e && e.hidden === true);
55
+ }
56
+
57
+ /** Default OFF for local/upstream, ON for meta — the caller supplies the kind-appropriate
58
+ * `defaultHot`. An explicit boolean in the overlay always wins; absence falls back to the
59
+ * default. `hot` is the TOP-LEVEL (every-turn) promotion axis — INDEPENDENT of enabled/hidden,
60
+ * though a disabled tool is filtered out of the top-level surface by the assembler, not here. */
61
+ function isToolHot(state, id, defaultHot) {
62
+ const e = state && state[id];
63
+ if (e && typeof e.hot === 'boolean') return e.hot;
64
+ return !!defaultHot;
65
+ }
66
+
67
+ /** Set a tool's enabled flag, MERGING (so `hidden`/`hot` are preserved). Persists atomically. */
68
+ function setToolEnabled(statePath, id, enabled) {
69
+ if (typeof id !== 'string' || !id) throw new Error('setToolEnabled: id required');
70
+ const s = loadToolState(statePath);
71
+ s[id] = { ...(s[id] || {}), enabled: !!enabled };
72
+ atomicWriteJson(statePath, s);
73
+ return s;
74
+ }
75
+
76
+ /** Set a tool's hot flag, MERGING (so `enabled`/`hidden` are preserved). Persists atomically. */
77
+ function setToolHot(statePath, id, hot) {
78
+ if (typeof id !== 'string' || !id) throw new Error('setToolHot: id required');
79
+ const s = loadToolState(statePath);
80
+ s[id] = { ...(s[id] || {}), hot: !!hot };
81
+ atomicWriteJson(statePath, s);
82
+ return s;
83
+ }
84
+
85
+ /** Set a tool's hidden flag, MERGING (so `enabled` is preserved). Persists atomically. */
86
+ function setToolHidden(statePath, id, hidden) {
87
+ if (typeof id !== 'string' || !id) throw new Error('setToolHidden: id required');
88
+ const s = loadToolState(statePath);
89
+ s[id] = { ...(s[id] || {}), hidden: !!hidden };
90
+ atomicWriteJson(statePath, s);
91
+ return s;
92
+ }
93
+
94
+ /** Drop a tool's overlay entry entirely (revert to defaults: active + not hidden).
95
+ * No-op if the id was never toggled. Persists atomically. */
96
+ function clearToolState(statePath, id) {
97
+ if (typeof id !== 'string' || !id) throw new Error('clearToolState: id required');
98
+ const s = loadToolState(statePath);
99
+ delete s[id];
100
+ atomicWriteJson(statePath, s);
101
+ return s;
102
+ }
103
+
104
+ module.exports = { loadToolState, isToolEnabled, isToolHidden, isToolHot, setToolEnabled, setToolHidden, setToolHot, clearToolState };