toolfunnel 0.7.0 → 0.8.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 (73) hide show
  1. package/README.md +238 -235
  2. package/SECURITY.md +84 -84
  3. package/bin/toolfunnel.js +530 -451
  4. package/docs/KNOWN_BUGS.md +100 -80
  5. package/docs/MANUAL.pdf +0 -0
  6. package/docs/design.md +84 -84
  7. package/docs/packaging.md +116 -115
  8. package/hooks/hooks.manifest.json +27 -27
  9. package/hooks/scripts/example-audit.js +21 -21
  10. package/hooks/scripts/example-deny-dangerous.js +39 -39
  11. package/mcp/expose.example.json +30 -30
  12. package/mcp/servers/mock-modern/server.js +147 -147
  13. package/mcp/servers/mock-upstream/server.js +379 -380
  14. package/package.json +67 -67
  15. package/src/auth/config.js +172 -174
  16. package/src/auth/install.js +181 -181
  17. package/src/auth/resource-server.js +358 -353
  18. package/src/core/atomic-write.js +97 -0
  19. package/src/core/child-reaper.js +61 -61
  20. package/src/core/config-home.js +226 -134
  21. package/src/core/events.js +105 -105
  22. package/src/core/hook-engine.js +304 -329
  23. package/src/core/hook-loader.js +766 -824
  24. package/src/core/hook-runner.js +615 -566
  25. package/src/core/logger.js +295 -297
  26. package/src/core/matcher.js +100 -100
  27. package/src/core/metrics.js +90 -75
  28. package/src/core/output-cap.js +31 -0
  29. package/src/core/rename-migration.js +178 -163
  30. package/src/core/requires.js +138 -138
  31. package/src/core/server-config.js +98 -98
  32. package/src/extend/add-hook.md +155 -152
  33. package/src/extend/add-mcp.md +119 -119
  34. package/src/extend/configure.md +88 -88
  35. package/src/extend/create-tool.md +168 -168
  36. package/src/extend/howto.js +102 -102
  37. package/src/extend/package.md +190 -190
  38. package/src/extend/wrap.md +99 -99
  39. package/src/mcp/aggregator.js +2248 -1674
  40. package/src/mcp/expose-store.js +755 -577
  41. package/src/mcp/gated-run.js +210 -210
  42. package/src/mcp/http-transport.js +1657 -1563
  43. package/src/mcp/mcp-client.js +1174 -1070
  44. package/src/mcp/modern.js +409 -406
  45. package/src/mcp/protocol.js +473 -468
  46. package/src/mcp/server.js +3317 -3112
  47. package/src/mcp/tool-approvals.js +396 -0
  48. package/src/tools/registry.js +607 -661
  49. package/src/tools/tool-state.js +170 -170
  50. package/src/ui/public/app.js +1246 -1187
  51. package/src/ui/public/index.html +286 -286
  52. package/src/ui/public/styles.css +535 -535
  53. package/src/ui/server.js +1742 -1616
  54. package/tools/scripts/base64.js +139 -139
  55. package/tools/scripts/danger.js +61 -61
  56. package/tools/scripts/echo.js +39 -39
  57. package/tools/scripts/hash.js +101 -101
  58. package/tools/scripts/json.js +109 -109
  59. package/tools/scripts/text-stats.js +131 -131
  60. package/tools/scripts/tf-accept-change.js +67 -0
  61. package/tools/scripts/tf-env.js +43 -43
  62. package/tools/scripts/tf-hook-add.js +151 -151
  63. package/tools/scripts/tf-hook-set.js +120 -120
  64. package/tools/scripts/tf-list.js +192 -192
  65. package/tools/scripts/tf-log.js +86 -86
  66. package/tools/scripts/tf-mcp-add.js +130 -117
  67. package/tools/scripts/tf-mcp-set.js +121 -121
  68. package/tools/scripts/tf-pack.js +237 -237
  69. package/tools/scripts/tf-tool-add.js +134 -134
  70. package/tools/scripts/tf-tool-set.js +142 -142
  71. package/tools/scripts/tf-wrap.js +103 -103
  72. package/tools/scripts/uuid.js +102 -102
  73. package/tools/tools.register.json +16 -5
@@ -1,105 +1,105 @@
1
- 'use strict';
2
-
3
- /**
4
- * events.js - lifecycle event names + per-event stdin payload builder.
5
- *
6
- * This is the hook contract surface: the six lifecycle events and
7
- * (the exact stdin JSON shape). Field names are FROZEN - they are the hook wire contract and must
8
- * match Claude Code's documented hook input byte-for-byte so the real hook
9
- * scripts run unchanged. Do not rename or add fields.
10
- *
11
- * CommonJS only. Zero host imports (core/ must run headless under node --test).
12
- */
13
-
14
- /**
15
- * The six lifecycle events v3 supports.
16
- * Values equal the `hook_event_name` written into the stdin payload.
17
- * Frozen so callers can rely on identity comparison and can't mutate the set.
18
- */
19
- const EVENTS = Object.freeze({
20
- SessionStart: 'SessionStart',
21
- UserPromptSubmit: 'UserPromptSubmit',
22
- PreToolUse: 'PreToolUse',
23
- PostToolUse: 'PostToolUse',
24
- Stop: 'Stop',
25
- PreCompact: 'PreCompact',
26
- });
27
-
28
- // Set of valid event names for fast membership checks / validation.
29
- const EVENT_NAMES = Object.freeze(Object.values(EVENTS));
30
-
31
- /**
32
- * Build the stdin JSON object the runner pipes to a hook command.
33
- *
34
- * Every event carries the same four common fields:
35
- * session_id, transcript_path, cwd, hook_event_name
36
- * supplied by `ctx`. Each event then adds its own fields from `extra`:
37
- *
38
- * SessionStart -> source : "startup" | "resume" | "compact"
39
- * UserPromptSubmit -> prompt : "<user text>"
40
- * PreToolUse -> tool_name, tool_input
41
- * PostToolUse -> tool_name, tool_input, tool_response
42
- * Stop -> stop_hook_active : true | false
43
- * PreCompact -> trigger ("manual"|"auto"), custom_instructions
44
- *
45
- * @param {string} event one of EVENTS (the hook_event_name).
46
- * @param {object} ctx common fields: { session_id, transcript_path, cwd }.
47
- * @param {object} [extra] event-specific fields (see table above).
48
- * @returns {object} the stdin payload, with the contract's frozen field names.
49
- * @throws {Error} if `event` is not one of the six known events.
50
- */
51
- function buildPayload(event, ctx, extra) {
52
- if (!EVENT_NAMES.includes(event)) {
53
- throw new Error(`buildPayload: unknown event "${event}"`);
54
- }
55
-
56
- const c = ctx || {};
57
- const e = extra || {};
58
-
59
- // Common fields - present on EVERY event, in their contract order.
60
- // hook_event_name is always the canonical event string (not whatever ctx held).
61
- const payload = {
62
- session_id: c.session_id,
63
- transcript_path: c.transcript_path,
64
- cwd: c.cwd,
65
- hook_event_name: event,
66
- };
67
-
68
- // Event-specific additions. Each branch sets EXACTLY the fields the contract names -
69
- // no more, no fewer - so the payload matches Claude Code's shape precisely.
70
- switch (event) {
71
- case EVENTS.SessionStart:
72
- payload.source = e.source;
73
- break;
74
-
75
- case EVENTS.UserPromptSubmit:
76
- payload.prompt = e.prompt;
77
- break;
78
-
79
- case EVENTS.PreToolUse:
80
- payload.tool_name = e.tool_name;
81
- payload.tool_input = e.tool_input;
82
- break;
83
-
84
- case EVENTS.PostToolUse:
85
- payload.tool_name = e.tool_name;
86
- payload.tool_input = e.tool_input;
87
- payload.tool_response = e.tool_response;
88
- break;
89
-
90
- case EVENTS.Stop:
91
- payload.stop_hook_active = e.stop_hook_active;
92
- break;
93
-
94
- case EVENTS.PreCompact:
95
- payload.trigger = e.trigger;
96
- payload.custom_instructions = e.custom_instructions;
97
- break;
98
-
99
- // No default: the membership check above already rejected unknown events.
100
- }
101
-
102
- return payload;
103
- }
104
-
105
- module.exports = { EVENTS, EVENT_NAMES, buildPayload };
1
+ 'use strict';
2
+
3
+ /**
4
+ * events.js - lifecycle event names + per-event stdin payload builder.
5
+ *
6
+ * This is the hook contract surface: the six lifecycle events and
7
+ * (the exact stdin JSON shape). Field names are FROZEN - they are the hook wire contract and must
8
+ * match Claude Code's documented hook input byte-for-byte so the real hook
9
+ * scripts run unchanged. Do not rename or add fields.
10
+ *
11
+ * CommonJS only. Zero host imports (core/ must run headless under node --test).
12
+ */
13
+
14
+ /**
15
+ * The six lifecycle events v3 supports.
16
+ * Values equal the `hook_event_name` written into the stdin payload.
17
+ * Frozen so callers can rely on identity comparison and can't mutate the set.
18
+ */
19
+ const EVENTS = Object.freeze({
20
+ SessionStart: 'SessionStart',
21
+ UserPromptSubmit: 'UserPromptSubmit',
22
+ PreToolUse: 'PreToolUse',
23
+ PostToolUse: 'PostToolUse',
24
+ Stop: 'Stop',
25
+ PreCompact: 'PreCompact',
26
+ });
27
+
28
+ // Set of valid event names for fast membership checks / validation.
29
+ const EVENT_NAMES = Object.freeze(Object.values(EVENTS));
30
+
31
+ /**
32
+ * Build the stdin JSON object the runner pipes to a hook command.
33
+ *
34
+ * Every event carries the same four common fields:
35
+ * session_id, transcript_path, cwd, hook_event_name
36
+ * supplied by `ctx`. Each event then adds its own fields from `extra`:
37
+ *
38
+ * SessionStart -> source : "startup" | "resume" | "compact"
39
+ * UserPromptSubmit -> prompt : "<user text>"
40
+ * PreToolUse -> tool_name, tool_input
41
+ * PostToolUse -> tool_name, tool_input, tool_response
42
+ * Stop -> stop_hook_active : true | false
43
+ * PreCompact -> trigger ("manual"|"auto"), custom_instructions
44
+ *
45
+ * @param {string} event one of EVENTS (the hook_event_name).
46
+ * @param {object} ctx common fields: { session_id, transcript_path, cwd }.
47
+ * @param {object} [extra] event-specific fields (see table above).
48
+ * @returns {object} the stdin payload, with the contract's frozen field names.
49
+ * @throws {Error} if `event` is not one of the six known events.
50
+ */
51
+ function buildPayload(event, ctx, extra) {
52
+ if (!EVENT_NAMES.includes(event)) {
53
+ throw new Error(`buildPayload: unknown event "${event}"`);
54
+ }
55
+
56
+ const c = ctx || {};
57
+ const e = extra || {};
58
+
59
+ // Common fields - present on EVERY event, in their contract order.
60
+ // hook_event_name is always the canonical event string (not whatever ctx held).
61
+ const payload = {
62
+ session_id: c.session_id,
63
+ transcript_path: c.transcript_path,
64
+ cwd: c.cwd,
65
+ hook_event_name: event,
66
+ };
67
+
68
+ // Event-specific additions. Each branch sets EXACTLY the fields the contract names -
69
+ // no more, no fewer - so the payload matches Claude Code's shape precisely.
70
+ switch (event) {
71
+ case EVENTS.SessionStart:
72
+ payload.source = e.source;
73
+ break;
74
+
75
+ case EVENTS.UserPromptSubmit:
76
+ payload.prompt = e.prompt;
77
+ break;
78
+
79
+ case EVENTS.PreToolUse:
80
+ payload.tool_name = e.tool_name;
81
+ payload.tool_input = e.tool_input;
82
+ break;
83
+
84
+ case EVENTS.PostToolUse:
85
+ payload.tool_name = e.tool_name;
86
+ payload.tool_input = e.tool_input;
87
+ payload.tool_response = e.tool_response;
88
+ break;
89
+
90
+ case EVENTS.Stop:
91
+ payload.stop_hook_active = e.stop_hook_active;
92
+ break;
93
+
94
+ case EVENTS.PreCompact:
95
+ payload.trigger = e.trigger;
96
+ payload.custom_instructions = e.custom_instructions;
97
+ break;
98
+
99
+ // No default: the membership check above already rejected unknown events.
100
+ }
101
+
102
+ return payload;
103
+ }
104
+
105
+ module.exports = { EVENTS, EVENT_NAMES, buildPayload };