failproofai 0.0.2-beta.2 → 0.0.2-beta.4

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 (130) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  9. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  10. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  12. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  18. package/.next/standalone/.next/server/app/_not-found.rsc +17 -17
  19. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +17 -17
  20. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  21. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +11 -11
  22. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  24. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  25. package/.next/standalone/.next/server/app/index.html +1 -1
  26. package/.next/standalone/.next/server/app/index.rsc +16 -16
  27. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  28. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -16
  29. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  30. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +11 -11
  31. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  32. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  33. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  35. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  36. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  38. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  39. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  42. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  43. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  46. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/chunks/[root-of-the-server]__02nt~6d._.js +1 -1
  49. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
  50. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0103jwf._.js → [root-of-the-server]__05ib_c3._.js} +2 -2
  51. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__092s1ta._.js +2 -2
  52. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09icjsf._.js +2 -2
  53. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g.lg8b._.js +2 -2
  54. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h..k-e._.js +2 -2
  55. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ovwjau._.js → [root-of-the-server]__0od~yp1._.js} +2 -2
  56. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0okos0k._.js +2 -2
  57. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +5 -5
  58. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11pa2ra._.js +2 -2
  59. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12t-wym._.js +2 -2
  60. package/.next/standalone/.next/server/chunks/ssr/_10lm7or._.js +1 -1
  61. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
  62. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +1 -1
  63. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  64. package/.next/standalone/.next/server/pages/404.html +2 -2
  65. package/.next/standalone/.next/server/pages/500.html +1 -1
  66. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
  68. package/.next/standalone/.next/static/chunks/{0sm1iqi3m~xiz.js → 03qghe4e2_.ul.js} +1 -1
  69. package/.next/standalone/.next/static/chunks/{0jrzwsyo7wo26.js → 0_eej2~ju.yds.js} +1 -1
  70. package/.next/standalone/.next/static/chunks/{0tl2f-3yc.rqc.js → 0bc69j4t8njpq.js} +1 -1
  71. package/.next/standalone/.next/static/chunks/0nnxt7uoz_cvj.css +1 -0
  72. package/.next/standalone/.next/static/chunks/{0uftmw5od9kdz.js → 0qaojcc.nvqd8.js} +1 -1
  73. package/.next/standalone/.next/static/chunks/{001k0zayn2o.s.js → 0xg4wy053mmhs.js} +1 -1
  74. package/.next/standalone/.next/static/chunks/{0pdd7~yp8ytu6.js → 12mgwr8gh_kqo.js} +2 -2
  75. package/.next/standalone/.next/static/chunks/{0tbr0o7vwc~-s.js → 134~t05vpu75e.js} +1 -1
  76. package/.next/standalone/.next/static/chunks/{0wtcha31~i7rm.js → 17veghz_js0u3.js} +1 -1
  77. package/.next/standalone/Dockerfile.docs +12 -0
  78. package/.next/standalone/README.md +59 -46
  79. package/.next/standalone/app/components/session-hooks-panel.tsx +31 -6
  80. package/.next/standalone/app/policies/hooks-client.tsx +31 -6
  81. package/.next/standalone/dist/cli.mjs +234 -27
  82. package/.next/standalone/dist/index.js +2 -2
  83. package/.next/standalone/docs/{architecture.md → architecture.mdx} +40 -23
  84. package/.next/standalone/docs/{built-in-policies.md → built-in-policies.mdx} +134 -12
  85. package/.next/standalone/docs/cli/dashboard.mdx +28 -0
  86. package/.next/standalone/docs/cli/environment-variables.mdx +34 -0
  87. package/.next/standalone/docs/cli/hook.mdx +30 -0
  88. package/.next/standalone/docs/cli/install-policies.mdx +48 -0
  89. package/.next/standalone/docs/cli/list-policies.mdx +31 -0
  90. package/.next/standalone/docs/cli/remove-policies.mdx +44 -0
  91. package/.next/standalone/docs/cli/version.mdx +12 -0
  92. package/.next/standalone/docs/{configuration.md → configuration.mdx} +16 -16
  93. package/.next/standalone/docs/{custom-hooks.md → custom-policies.mdx} +80 -42
  94. package/.next/standalone/docs/{dashboard.md → dashboard.mdx} +26 -29
  95. package/.next/standalone/docs/docs.json +31 -4
  96. package/.next/standalone/docs/examples.mdx +253 -0
  97. package/.next/standalone/docs/for-agents.mdx +38 -0
  98. package/.next/standalone/docs/getting-started.mdx +134 -0
  99. package/.next/standalone/docs/introduction.mdx +57 -0
  100. package/.next/standalone/docs/logo/dark.svg +21 -0
  101. package/.next/standalone/docs/logo/light.svg +21 -0
  102. package/.next/standalone/docs/{package-aliases.md → package-aliases.mdx} +5 -5
  103. package/.next/standalone/docs/{testing.md → testing.mdx} +11 -11
  104. package/.next/standalone/package.json +6 -9
  105. package/.next/standalone/scripts/publish-aliases.mjs +4 -2
  106. package/.next/standalone/skills-lock.json +10 -0
  107. package/.next/standalone/src/hooks/builtin-policies.ts +271 -25
  108. package/.next/standalone/src/hooks/handler.ts +1 -0
  109. package/.next/standalone/src/hooks/hook-activity-store.ts +6 -1
  110. package/.next/standalone/src/hooks/policy-evaluator.ts +23 -2
  111. package/.next/standalone/src/hooks/policy-helpers.ts +2 -2
  112. package/.next/standalone/vitest.config.e2e.mts +3 -0
  113. package/.next/standalone/vitest.config.mts +3 -0
  114. package/README.md +59 -46
  115. package/dist/cli.mjs +234 -27
  116. package/dist/index.js +2 -2
  117. package/package.json +6 -9
  118. package/scripts/publish-aliases.mjs +4 -2
  119. package/src/hooks/builtin-policies.ts +271 -25
  120. package/src/hooks/handler.ts +1 -0
  121. package/src/hooks/hook-activity-store.ts +6 -1
  122. package/src/hooks/policy-evaluator.ts +23 -2
  123. package/src/hooks/policy-helpers.ts +2 -2
  124. package/.next/standalone/.next/static/chunks/15jpradyu_531.css +0 -1
  125. package/.next/standalone/docs/cli-reference.md +0 -175
  126. package/.next/standalone/docs/getting-started.md +0 -128
  127. package/.next/standalone/docs/introduction.md +0 -47
  128. /package/.next/standalone/.next/static/{JksWDLwDoPy6bcczVWlff → N7CmoNJD3b7hE1pCaP_Gs}/_buildManifest.js +0 -0
  129. /package/.next/standalone/.next/static/{JksWDLwDoPy6bcczVWlff → N7CmoNJD3b7hE1pCaP_Gs}/_clientMiddlewareManifest.js +0 -0
  130. /package/.next/standalone/.next/static/{JksWDLwDoPy6bcczVWlff → N7CmoNJD3b7hE1pCaP_Gs}/_ssgManifest.js +0 -0
@@ -1,175 +0,0 @@
1
- ---
2
- title: CLI Reference
3
- description: "All commands, flags, and environment variables for the failproofai CLI"
4
- icon: terminal
5
- ---
6
-
7
- All commands are invoked via the `failproofai` binary.
8
-
9
- ---
10
-
11
- ## Launch the dashboard
12
-
13
- ```bash
14
- failproofai
15
- failproofai --start
16
- ```
17
-
18
- Starts the web dashboard at `http://localhost:8020`. Use `--start` for production mode (Next.js standalone). The default bare invocation uses development mode with auto-reload.
19
-
20
- **Options (dev mode only):**
21
-
22
- | Flag | Description |
23
- |------|-------------|
24
- | `--port <number>` | Port to listen on (default: `8020`) |
25
- | `--projects-path <path>` | Override the Claude projects path |
26
- | `--allowed-origins <origins>` | Comma-separated list of hosts/IPs allowed to access dev resources (e.g. HMR websocket). Required when accessing the dev server from a hostname other than `localhost`. |
27
-
28
- **Example — allow a custom hostname in dev:**
29
-
30
- ```bash
31
- npm run dev -- --allowed-origins dashboard.example.com
32
- # or multiple:
33
- npm run dev -- --allowed-origins dashboard.example.com,192.168.1.5
34
- ```
35
-
36
- You can also set the env var directly instead of using the flag:
37
-
38
- ```bash
39
- FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev
40
- ```
41
-
42
- ---
43
-
44
- ## Hook handler (internal)
45
-
46
- ```bash
47
- failproofai --hook <EventType>
48
- ```
49
-
50
- This is the command written into Claude Code's `settings.json` by `--install-policies`. You will not normally call this directly.
51
-
52
- **EventType** is one of: `PreToolUse`, `PostToolUse`, `Notification`, `Stop`.
53
-
54
- Reads a JSON payload from stdin, evaluates all enabled policies, writes a decision to stdout, and exits.
55
-
56
- ---
57
-
58
- ## Install policies
59
-
60
- ```bash
61
- failproofai --install-policies [policy-names...] [options]
62
- ```
63
-
64
- Writes hook entries into Claude Code's `settings.json` so that failproofai intercepts tool calls.
65
-
66
- **Options:**
67
-
68
- | Flag | Description |
69
- |------|-------------|
70
- | `--scope user` | Install into `~/.claude/settings.json` (default — all sessions) |
71
- | `--scope project` | Install into `.claude/settings.json` in the current directory |
72
- | `--scope local` | Install into `.claude/settings.local.json` in the current directory |
73
- | `--custom <path>` | Path to a JS file containing custom hook policies |
74
- | `--beta` | Include beta policies in installation |
75
-
76
- **Examples:**
77
-
78
- ```bash
79
- # Install all default policies globally
80
- failproofai --install-policies
81
-
82
- # Install two specific policies for the current project
83
- failproofai --install-policies block-sudo sanitize-api-keys --scope project
84
-
85
- # Install with a custom hooks file
86
- failproofai --install-policies --custom ./my-policies.js
87
- ```
88
-
89
- When `--custom <path>` is provided, the resolved absolute path is saved to `policies-config.json` as `customPoliciesPath`. The file is loaded and executed at hook-fire time (not at install time).
90
-
91
- ---
92
-
93
- ## Remove policies
94
-
95
- ```bash
96
- failproofai --remove-policies [policy-names...] [options]
97
- ```
98
-
99
- Removes failproofai hook entries from Claude Code's `settings.json`.
100
-
101
- **Options:**
102
-
103
- | Flag | Description |
104
- |------|-------------|
105
- | `--scope user` | Remove from global settings (default) |
106
- | `--scope project` | Remove from project settings |
107
- | `--scope local` | Remove from local settings |
108
- | `--scope all` | Remove from all scopes |
109
- | `--custom` | Clear the `customPoliciesPath` from config |
110
-
111
- **Examples:**
112
-
113
- ```bash
114
- # Remove all policies globally
115
- failproofai --remove-policies
116
-
117
- # Remove a specific policy
118
- failproofai --remove-policies block-sudo
119
-
120
- # Remove custom hooks path
121
- failproofai --remove-policies --custom
122
- ```
123
-
124
- ---
125
-
126
- ## List policies
127
-
128
- ```bash
129
- failproofai --list-policies
130
- ```
131
-
132
- Prints all available policies with their status, configured parameters, and custom hooks.
133
-
134
- **Sample output:**
135
-
136
- ```
137
- Failproof AI Hook Policies (user)
138
-
139
- Status Name Description
140
- ────── ──────────────────────────────────────────────────────────────
141
- ✓ block-sudo Block sudo commands
142
- allowPatterns: ["sudo systemctl status"]
143
- ✓ block-rm-rf Block recursive deletions
144
- ✗ block-curl-pipe-sh Block curl|bash patterns
145
- ✓ sanitize-api-keys Redact API keys from output
146
- additionalPatterns: [{ regex: "MY_TOKEN_...", label: "..." }]
147
-
148
- ── Custom Hooks (/home/alice/myproject/my-policies.js) ──────────────
149
- ✓ require-jira-ticket Block commits without ticket
150
- ✓ approval-gate Approval gate for destructive ops
151
- ```
152
-
153
- Unknown keys in `policyParams` are flagged here (not at hook-fire time, so you can catch typos).
154
-
155
- ---
156
-
157
- ## Print version
158
-
159
- ```bash
160
- failproofai --version
161
- ```
162
-
163
- Prints the installed version number.
164
-
165
- ---
166
-
167
- ## Environment variables
168
-
169
- | Variable | Description |
170
- |----------|-------------|
171
- | `FAILPROOFAI_TELEMETRY_DISABLED=1` | Disable anonymous usage telemetry |
172
- | `FAILPROOFAI_LOG_LEVEL=info\|warn\|error` | Server log level (default: `warn`) |
173
- | `FAILPROOFAI_DISABLE_PAGES=policies,projects` | Comma-separated list of dashboard pages to disable |
174
- | `FAILPROOFAI_ALLOWED_DEV_ORIGINS` | Comma-separated list of hosts/IPs allowed to access Next.js dev resources (HMR). Dev mode only. Equivalent to `--allowed-origins`. |
175
- | `CLAUDE_PROJECTS_PATH` | Override the path where Claude Code project folders are found |
@@ -1,128 +0,0 @@
1
- ---
2
- title: Getting Started
3
- description: "Install failproofai, enable policies, and take it for a spin"
4
- icon: rocket
5
- ---
6
-
7
- ## Requirements
8
-
9
- - **Node.js** >= 20.9.0
10
- - **Bun** >= 1.3.0 (optional — only needed for development / building from source)
11
-
12
- ---
13
-
14
- ## Installation
15
-
16
- ```bash
17
- npm install -g failproofai
18
- # or
19
- bun add -g failproofai
20
- ```
21
-
22
- ---
23
-
24
- ## Quick Start
25
-
26
- ### 1. Launch the dashboard
27
-
28
- ```bash
29
- failproofai
30
- ```
31
-
32
- Opens a local web dashboard at `http://localhost:8020`. The dashboard lets you browse your Claude Code projects and sessions, inspect session logs and tool calls, and manage policies.
33
-
34
- ### 2. Install policies
35
-
36
- Policies are the security rules that Claude Code enforces when it runs tools. Installing them writes hook entries into Claude Code's `settings.json`.
37
-
38
- **Install globally** (applies to all Claude Code sessions):
39
-
40
- ```bash
41
- failproofai --install-policies
42
- ```
43
-
44
- **Install for the current project only:**
45
-
46
- ```bash
47
- failproofai --install-policies --scope project
48
- ```
49
-
50
- **Install specific policies by name:**
51
-
52
- ```bash
53
- failproofai --install-policies block-sudo block-rm-rf sanitize-api-keys
54
- ```
55
-
56
- See [Built-in Policies](./built-in-policies.md) for the full list.
57
-
58
- ### 3. Verify installation
59
-
60
- ```bash
61
- failproofai --list-policies
62
- ```
63
-
64
- This shows every policy, whether it is enabled, and any configured parameters.
65
-
66
- ### 4. Try it out
67
-
68
- Once policies are installed, run Claude Code as normal. When Claude attempts a blocked action (e.g. `sudo`, `rm -rf`, or outputting an API key), failproofai intercepts and blocks it automatically.
69
-
70
- ---
71
-
72
- ## How policies work
73
-
74
- When Claude Code is about to run a tool (a `PreToolUse` event), or has just run one (a `PostToolUse` event), it invokes failproofai as a subprocess:
75
-
76
- ```
77
- Claude Code → failproofai --hook PreToolUse → stdin: JSON payload
78
- stdout: decision JSON
79
- exit code: 0 (allow/instruct) or 2 (deny on Stop)
80
- ```
81
-
82
- failproofai reads the tool name and input, evaluates all enabled policies, and returns a decision:
83
-
84
- - **allow** — Claude proceeds normally (empty stdout)
85
- - **deny** — Claude is told the action is blocked and why
86
- - **instruct** — Claude gets extra context/instructions added to its prompt
87
-
88
- Policies run entirely in your local process. Nothing is sent to a remote service.
89
-
90
- ---
91
-
92
- ## Data storage
93
-
94
- failproofai stores all configuration and logs locally:
95
-
96
- | Path | Contents |
97
- |------|----------|
98
- | `~/.failproofai/policies-config.json` | Global policy configuration |
99
- | `~/.failproofai/hook-activity.jsonl` | Hook execution history (one JSON line per event) |
100
- | `~/.failproofai/hook.log` | Debug log for custom hook errors |
101
- | `.failproofai/policies-config.json` | Per-project policy configuration (committed) |
102
- | `.failproofai/policies-config.local.json` | Per-project personal overrides (gitignored) |
103
-
104
- ---
105
-
106
- ## Uninstalling
107
-
108
- ```bash
109
- failproofai --remove-policies
110
- ```
111
-
112
- Removes the hook entries from `~/.claude/settings.json`. The failproofai configuration files in `~/.failproofai/` are left in place.
113
-
114
- To remove for a specific scope:
115
-
116
- ```bash
117
- failproofai --remove-policies --scope project
118
- ```
119
-
120
- ---
121
-
122
- ## Next steps
123
-
124
- - [Configuration](./configuration.md) — understand scopes and the config file format
125
- - [Built-in Policies](./built-in-policies.md) — full list of policies and their parameters
126
- - [Custom Hooks](./custom-hooks.md) — write your own policies in JavaScript
127
- - [Dashboard](./dashboard.md) — using the session viewer and policy manager
128
- - [CLI Reference](./cli-reference.md) — all flags and commands
@@ -1,47 +0,0 @@
1
- ---
2
- title: Introduction
3
- description: "Open-source hooks, policies, and session visualization for Claude Code and the Agents SDK"
4
- ---
5
-
6
- # Failproof AI
7
-
8
- Open-source hooks, policies, and session visualization for **Claude Code** and the **Agents SDK**. Runs entirely locally — no data leaves your machine.
9
-
10
- ## What is Failproof AI?
11
-
12
- Failproof AI is a security and observability toolkit that intercepts Claude Code tool calls in real time. It evaluates configurable policies — blocking dangerous commands, redacting secrets, and adding safety instructions — before Claude can act.
13
-
14
- It also includes a local web dashboard for browsing Claude Code sessions, inspecting tool calls, and managing policies visually.
15
-
16
- ## Key features
17
-
18
- | Feature | Description |
19
- |---------|-------------|
20
- | [35+ Built-in Policies](./built-in-policies.md) | Block sudo, rm -rf, force-push, secret leaks, and more — out of the box. |
21
- | [Custom Hooks](./custom-hooks.md) | Write your own policies in JavaScript with a simple allow/deny/instruct API. |
22
- | [Session Dashboard](./dashboard.md) | Browse projects, inspect sessions, and review every tool call and policy decision. |
23
- | [Three-Scope Config](./configuration.md) | Global, project, and local configuration with automatic merging. |
24
-
25
- ## Quick start
26
-
27
- Install globally:
28
-
29
- ```bash
30
- npm install -g failproofai
31
- # or
32
- bun add -g failproofai
33
- ```
34
-
35
- Enable policies:
36
-
37
- ```bash
38
- failproofai --install-policies
39
- ```
40
-
41
- Launch the dashboard:
42
-
43
- ```bash
44
- failproofai
45
- ```
46
-
47
- See the [Getting Started](./getting-started.md) guide for a full walkthrough.