@gotgenes/pi-autoformat 0.1.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.
@@ -0,0 +1,35 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ env:
9
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
10
+
11
+ jobs:
12
+ check:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v6
16
+
17
+ - uses: pnpm/action-setup@v4
18
+ with:
19
+ version: latest
20
+
21
+ - uses: actions/setup-node@v6
22
+ with:
23
+ node-version: 24
24
+ cache: "pnpm"
25
+
26
+ - run: pnpm install --frozen-lockfile
27
+
28
+ - name: Type check
29
+ run: pnpm exec tsc --noEmit
30
+
31
+ - name: Lint
32
+ run: pnpm run lint
33
+
34
+ - name: Test
35
+ run: pnpm run test
@@ -0,0 +1,22 @@
1
+ name: release-please
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ env:
9
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
10
+
11
+ permissions:
12
+ contents: write
13
+ pull-requests: write
14
+
15
+ jobs:
16
+ release-please:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: googleapis/release-please-action@v4.4.1
20
+ with:
21
+ token: ${{ secrets.GITHUB_TOKEN }}
22
+ config-file: release-please-config.json
@@ -0,0 +1,3 @@
1
+ config:
2
+ default: true
3
+ MD013: false
@@ -0,0 +1,28 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/gotgenes/pi-autoformat/main/schemas/pi-autoformat.schema.json",
3
+ "formatMode": "prompt",
4
+ "hideSummariesInTui": false,
5
+ "formatters": {
6
+ "biome": {
7
+ "command": [
8
+ "pnpm",
9
+ "exec",
10
+ "biome",
11
+ "check",
12
+ "--write",
13
+ "--files-ignore-unknown=true",
14
+ "$FILE"
15
+ ],
16
+ "extensions": [".ts", ".json"]
17
+ },
18
+ "markdownlint-cli2": {
19
+ "command": ["pnpm", "exec", "markdownlint-cli2", "--fix", "$FILE"],
20
+ "extensions": [".md"]
21
+ }
22
+ },
23
+ "chains": {
24
+ ".ts": ["biome"],
25
+ ".json": ["biome"],
26
+ ".md": ["markdownlint-cli2"]
27
+ }
28
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.1.0"
3
+ }
package/AGENTS.md ADDED
@@ -0,0 +1,71 @@
1
+ # AGENTS.md
2
+
3
+ ## Project Purpose
4
+
5
+ This repository is for a Pi extension that auto-formats files after agent edits so formatting does not fail late at commit time.
6
+
7
+ Read `docs/plans/` before making architectural changes.
8
+
9
+ ## Workflow
10
+
11
+ - Keep scope tight.
12
+ - Prefer small, reversible changes.
13
+ - Preserve intentional behavior unless there is a clear reason to change it.
14
+ - Ask before removing functionality or changing defaults.
15
+
16
+ ## Implementation Priorities
17
+
18
+ - Prefer prompt-end formatting over immediate per-tool formatting unless the task explicitly requires otherwise.
19
+ - Favor repository-configured formatter commands over hardcoded formatter behavior.
20
+ - Prefer extension-owned config files over Pi `settings.json` keys for package-specific behavior.
21
+ - Format only files touched by the agent, not the whole repository.
22
+ - Make formatter failures visible, but do not block the original file edit by default.
23
+
24
+ ## Code Style
25
+
26
+ - Use TypeScript.
27
+ - Avoid `any` unless absolutely necessary.
28
+ - Use standard top-level imports only.
29
+ - Keep modules focused and composable.
30
+ - Prefer explicit configuration over hidden behavior.
31
+
32
+ ## Configuration
33
+
34
+ - Use extension-owned config files:
35
+ - global: `~/.pi/agent/extensions/pi-autoformat/config.json`
36
+ - project: `.pi/extensions/pi-autoformat/config.json`
37
+ - Project config overrides global config.
38
+ - Do not move package configuration into Pi `settings.json` without explicit discussion.
39
+ - Keep `schemas/pi-autoformat.schema.json`, `docs/configuration.md`, `README.md`, and the TypeScript config loader aligned.
40
+
41
+ ## Testing
42
+
43
+ - Add focused tests for formatter resolution, execution order, and failure handling.
44
+ - Test prompt-end batching behavior.
45
+ - Test custom formatter command configuration.
46
+ - Test multiple formatter chains for the same file type.
47
+ - Add focused tests for config loading, merge precedence, and validation issues.
48
+ - Add extension lifecycle tests once the runtime entrypoint exists.
49
+
50
+ ## Commits
51
+
52
+ - Use Conventional Commits.
53
+ - Commit at meaningful checkpoints without waiting for an explicit reminder.
54
+ - Prefer small, reviewable commits that leave the repository in a valid state.
55
+ - Examples:
56
+ - `feat: add prompt-end formatter queue`
57
+ - `fix: preserve formatter order for markdown chains`
58
+ - `test: cover custom formatter override`
59
+ - `docs: refine initial implementation plan`
60
+
61
+ ## Notes for Agents
62
+
63
+ Before implementing, understand:
64
+
65
+ 1. the problem being solved
66
+ 2. the timing tradeoffs between tool-mode and prompt-mode formatting
67
+ 3. the need to support repository-specific formatter chains
68
+ 4. the chosen config layout and merge precedence
69
+ 5. the need to keep schema, config loader, and docs aligned
70
+
71
+ Do not assume commit-time hooks are an acceptable primary formatting mechanism.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Christopher D. Lasher
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # pi-autoformat
2
+
3
+ `pi-autoformat` is a Pi extension package that automatically formats files after the agent edits them.
4
+
5
+ ## The problem this package solves
6
+
7
+ Pi agents often make correct code changes that still fail at commit time because formatting was never run.
8
+
9
+ That creates a frustrating workflow:
10
+
11
+ 1. the agent edits files
12
+ 2. the agent appears done
13
+ 3. pre-commit hooks or CI run formatters later
14
+ 4. files mutate after the fact
15
+ 5. commits fail or the agent has to recover from surprise formatting changes
16
+
17
+ This package moves formatting earlier in the workflow so the agent is less likely to leave behind unformatted files.
18
+
19
+ ## How it works
20
+
21
+ `pi-autoformat` watches files touched by Pi mutation tools and runs configured formatter commands for just those files.
22
+
23
+ Design goals:
24
+
25
+ - format only files the agent touched
26
+ - prefer prompt-end batching over per-edit formatting by default
27
+ - support repository-specific formatter commands
28
+ - support ordered formatter chains for the same extension
29
+ - surface formatter failures without blocking the original edit by default
30
+ - keep reporting concise by default, with interactive summaries and non-interactive logs
31
+
32
+ Default behavior is **prompt mode**:
33
+
34
+ - collect files touched during the agent's work
35
+ - run formatters once after the prompt finishes
36
+
37
+ This is safer than formatting immediately after every edit because prompt-end batching avoids mutating a file in between sibling exact-text edits.
38
+
39
+ ## Installation
40
+
41
+ ### From npm
42
+
43
+ ```bash
44
+ pi install npm:@gotgenes/pi-autoformat
45
+ ```
46
+
47
+ ### Local development checkout
48
+
49
+ ```bash
50
+ pi install /absolute/path/to/pi-autoformat
51
+ ```
52
+
53
+ ## Configuration
54
+
55
+ `pi-autoformat` uses extension-owned config files.
56
+
57
+ Configuration is loaded in this order:
58
+
59
+ 1. global: `~/.pi/agent/extensions/pi-autoformat/config.json`
60
+ 2. project: `.pi/extensions/pi-autoformat/config.json`
61
+
62
+ Project config overrides global config.
63
+
64
+ Example:
65
+
66
+ ```json
67
+ {
68
+ "$schema": "https://raw.githubusercontent.com/gotgenes/pi-autoformat/main/schemas/pi-autoformat.schema.json",
69
+ "formatMode": "prompt",
70
+ "commandTimeoutMs": 10000,
71
+ "hideSummariesInTui": false,
72
+ "formatters": {
73
+ "prettier": {
74
+ "command": ["prettier", "--write", "$FILE"],
75
+ "extensions": [".js", ".ts", ".tsx", ".json", ".md"]
76
+ },
77
+ "markdownlint-cli2": {
78
+ "command": ["markdownlint-cli2", "--fix", "$FILE"],
79
+ "extensions": [".md"]
80
+ }
81
+ },
82
+ "chains": {
83
+ ".md": ["prettier", "markdownlint-cli2"],
84
+ ".ts": ["prettier"],
85
+ ".tsx": ["prettier"]
86
+ }
87
+ }
88
+ ```
89
+
90
+ See [docs/configuration.md](docs/configuration.md) for the full configuration reference.
91
+
92
+ Formatter command resolution in v1 stays intentionally simple:
93
+
94
+ - built-in formatter commands run from the project `cwd`
95
+ - the extension uses the inherited environment and `PATH`
96
+ - if your environment manager already resolves the right tool for that directory, plain commands like `prettier` can work as-is
97
+ - if your repo needs wrappers such as `pnpm exec`, `npx`, `mise x`, or similar, configure those commands explicitly in `formatters`
98
+
99
+ ## Reporting behavior
100
+
101
+ By default, `pi-autoformat` reports:
102
+
103
+ - concise success summaries after formatting runs
104
+ - per-file failure summaries when one or more formatter commands fail
105
+ - config validation issues detected while loading global or project config
106
+
107
+ In the interactive TUI, these appear as notifications.
108
+
109
+ Outside the TUI, they are written as prefixed log lines.
110
+
111
+ Set `hideSummariesInTui` to `true` if you want to suppress interactive success summaries while still surfacing failures.
112
+
113
+ ## Formatter model
114
+
115
+ Each formatter entry can define:
116
+
117
+ - `command: string[]`
118
+ - `extensions: string[]`
119
+ - `environment?: Record<string, string>`
120
+ - `disabled?: boolean`
121
+
122
+ `$FILE` is replaced with the absolute path of the touched file.
123
+
124
+ Chains are configured separately so formatter order is explicit.
125
+
126
+ For v1, `pi-autoformat` runs formatters only when a `chains` entry exists for the file extension.
127
+
128
+ Example Markdown chain:
129
+
130
+ 1. `prettier --write`
131
+ 2. `markdownlint-cli2 --fix`
132
+
133
+ ## Validation and autocomplete
134
+
135
+ The config file supports JSON Schema-based validation and editor autocomplete.
136
+
137
+ You can use either:
138
+
139
+ - the default-branch URL for the latest schema
140
+ - a pinned release-tag URL for reproducible validation
141
+
142
+ Examples:
143
+
144
+ ```json
145
+ {
146
+ "$schema": "https://raw.githubusercontent.com/gotgenes/pi-autoformat/main/schemas/pi-autoformat.schema.json"
147
+ }
148
+ ```
149
+
150
+ ```json
151
+ {
152
+ "$schema": "https://raw.githubusercontent.com/gotgenes/pi-autoformat/v1.0.0/schemas/pi-autoformat.schema.json"
153
+ }
154
+ ```
155
+
156
+ ## Status
157
+
158
+ This project is under active development.
159
+
160
+ The current repository includes the formatter registry, execution pipeline, touched-file queue, config loading and validation, and the Pi extension runtime wiring for prompt-, tool-, and session-mode flushing.
161
+
162
+ Known v1 limitations:
163
+
164
+ - only Pi `write` and `edit` mutations are tracked automatically
165
+ - arbitrary shell-driven file mutations are not detected yet
166
+ - reporting is intentionally concise and does not yet expose full formatter stdout/stderr by default
167
+
168
+ ## Development
169
+
170
+ ```bash
171
+ pnpm install
172
+ pnpm test
173
+ pnpm run lint
174
+ ```
175
+
176
+ ## License
177
+
178
+ MIT
package/biome.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.4.13/schema.json",
3
+ "formatter": {
4
+ "enabled": true,
5
+ "indentStyle": "space",
6
+ "indentWidth": 2
7
+ },
8
+ "linter": {
9
+ "enabled": true
10
+ },
11
+ "javascript": {
12
+ "formatter": {
13
+ "quoteStyle": "double",
14
+ "semicolons": "always"
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,177 @@
1
+ # Configuration
2
+
3
+ `pi-autoformat` uses extension-owned config files.
4
+
5
+ ## Config locations
6
+
7
+ Configuration is loaded from these files, in order:
8
+
9
+ 1. global: `~/.pi/agent/extensions/pi-autoformat/config.json`
10
+ 2. project: `.pi/extensions/pi-autoformat/config.json`
11
+
12
+ Project config overrides global config.
13
+
14
+ ## Schema validation
15
+
16
+ The config file is designed to support JSON Schema validation and autocomplete.
17
+
18
+ You can point `$schema` at either:
19
+
20
+ - the default-branch URL for the latest published schema
21
+ - a pinned release-tag URL for reproducible validation
22
+
23
+ Examples:
24
+
25
+ Latest:
26
+
27
+ ```json
28
+ {
29
+ "$schema": "https://raw.githubusercontent.com/gotgenes/pi-autoformat/main/schemas/pi-autoformat.schema.json",
30
+ "formatMode": "prompt",
31
+ "commandTimeoutMs": 10000,
32
+ "hideSummariesInTui": false,
33
+ "formatters": {
34
+ "prettier": {
35
+ "command": ["prettier", "--write", "$FILE"],
36
+ "extensions": [".js", ".ts", ".tsx", ".json", ".md"]
37
+ },
38
+ "markdownlint-cli2": {
39
+ "command": ["markdownlint-cli2", "--fix", "$FILE"],
40
+ "extensions": [".md"]
41
+ }
42
+ },
43
+ "chains": {
44
+ ".md": ["prettier", "markdownlint-cli2"],
45
+ ".ts": ["prettier"],
46
+ ".tsx": ["prettier"]
47
+ }
48
+ }
49
+ ```
50
+
51
+ Pinned tag:
52
+
53
+ ```json
54
+ {
55
+ "$schema": "https://raw.githubusercontent.com/gotgenes/pi-autoformat/v1.0.0/schemas/pi-autoformat.schema.json"
56
+ }
57
+ ```
58
+
59
+ ## Settings reference
60
+
61
+ ### `formatMode`
62
+
63
+ When formatting should run.
64
+
65
+ Allowed values:
66
+
67
+ - `"prompt"` — format once after the agent finishes the prompt. Recommended default.
68
+ - `"tool"` — format immediately after each successful mutation tool call.
69
+ - `"session"` — accumulate touched files and format on session shutdown.
70
+
71
+ ### `commandTimeoutMs`
72
+
73
+ Timeout in milliseconds for each formatter command.
74
+
75
+ Example:
76
+
77
+ ```json
78
+ {
79
+ "commandTimeoutMs": 10000
80
+ }
81
+ ```
82
+
83
+ ### `hideSummariesInTui`
84
+
85
+ Whether formatter summaries should be hidden in the interactive TUI.
86
+
87
+ Example:
88
+
89
+ ```json
90
+ {
91
+ "hideSummariesInTui": false
92
+ }
93
+ ```
94
+
95
+ ### `formatters`
96
+
97
+ Formatter registry keyed by formatter name.
98
+
99
+ Each formatter can define:
100
+
101
+ - `command: string[]`
102
+ - `extensions: string[]`
103
+ - `environment?: Record<string, string>`
104
+ - `disabled?: boolean`
105
+
106
+ `$FILE` is replaced with the absolute path to the touched file.
107
+
108
+ For v1, formatter command resolution stays intentionally simple:
109
+
110
+ - commands run from the project `cwd`
111
+ - commands inherit the extension process environment and `PATH`
112
+ - the extension does not try to auto-detect and invoke project-local binaries on its own
113
+ - if your repo needs wrappers such as `pnpm exec`, `npx`, or `mise x`, configure them explicitly in `command`
114
+
115
+ Example:
116
+
117
+ ```json
118
+ {
119
+ "formatters": {
120
+ "prettier": {
121
+ "command": ["pnpm", "exec", "prettier", "--write", "$FILE"],
122
+ "extensions": [".js", ".ts", ".tsx", ".json", ".md"]
123
+ },
124
+ "markdownlint-cli2": {
125
+ "command": ["pnpm", "exec", "markdownlint-cli2", "--fix", "$FILE"],
126
+ "extensions": [".md"],
127
+ "environment": {
128
+ "CI": "1"
129
+ }
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ ### `chains`
136
+
137
+ Ordered formatter chains keyed by file extension.
138
+
139
+ For v1, formatter execution is driven by explicit `chains` only.
140
+ If an extension has no `chains` entry, `pi-autoformat` does not run any formatter for that extension.
141
+
142
+ The chain order is explicit and should be preserved.
143
+
144
+ Example:
145
+
146
+ ```json
147
+ {
148
+ "chains": {
149
+ ".md": ["prettier", "markdownlint-cli2"],
150
+ ".ts": ["prettier"],
151
+ ".tsx": ["prettier"]
152
+ }
153
+ }
154
+ ```
155
+
156
+ ## Merge behavior
157
+
158
+ Merge order:
159
+
160
+ 1. built-in defaults
161
+ 2. global config
162
+ 3. project config
163
+
164
+ Recommended merge semantics:
165
+
166
+ - top-level scalar values override by precedence
167
+ - `formatters` merge by formatter name
168
+ - `chains` merge by extension key
169
+ - when a project config defines a formatter or chain key, that key replaces the lower-precedence value for that entry
170
+
171
+ This keeps repo-local formatter behavior explicit while still allowing users to set global defaults such as `formatMode`.
172
+
173
+ ## Notes
174
+
175
+ - Config is intentionally separate from Pi's shared `settings.json`.
176
+ - A dedicated config file avoids collisions with Pi core settings and makes strict schema validation practical.
177
+ - Schema URLs can point at either the default branch or pinned release tags depending on whether you want latest or reproducible validation behavior.